1/*****************************************************************************
2
3  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
4  more contributor license agreements.  See the NOTICE file distributed
5  with this work for additional information regarding copyright ownership.
6  Accellera licenses this file to you under the Apache License, Version 2.0
7  (the "License"); you may not use this file except in compliance with the
8  License.  You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
15  implied.  See the License for the specific language governing
16  permissions and limitations under the License.
17
18 *****************************************************************************/
19
20/*****************************************************************************
21
22  simple_cpu.cpp --
23
24  Original Author: Martin Janssen, Synopsys, Inc., 2002-02-15
25
26 *****************************************************************************/
27
28/*****************************************************************************
29
30  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
31  changes you are making here.
32
33      Name, Affiliation, Date:
34  Description of Modification:
35
36 *****************************************************************************/
37
38#include "systemc.h"
39
40#define READ 0
41#define WRITE 1
42
43SC_MODULE( exec_decode )
44{
45  SC_HAS_PROCESS( exec_decode );
46
47  sc_in<unsigned>  instruction;
48  sc_signal<unsigned>& program_counter;
49
50  unsigned pc; // Program counter
51  unsigned cpu_reg[32]; // Cpu registers
52
53  unsigned *data_mem; // The data memory
54
55  exec_decode( sc_module_name NAME,
56	       sc_signal<unsigned>& INSTRUCTION,
57	       sc_signal<unsigned>& PROGRAM_COUNTER )
58    : program_counter(PROGRAM_COUNTER)
59  {
60    instruction(INSTRUCTION);
61	SC_METHOD( entry );
62    // sensitive only to the clock
63    sensitive << instruction;
64
65    pc = 0x000000; // Power up reset value
66    for (int i =0; i<32; i++) cpu_reg[i] = 0;
67
68    // Initialize the data memory from file datamem
69    FILE *fp = fopen("simple_cpu/datamem", "r");
70    if (fp == (FILE *) 0) return; // No data mem file to read
71    // First field in this file is the size of data memory desired
72    int size;
73    fscanf(fp, "%d", &size);
74    data_mem = new unsigned[size];
75    if (data_mem == (unsigned *) 0) {
76      printf("Not enough memory left\n");
77      return;
78    }
79    unsigned mem_word;
80    size = 0;
81    while (fscanf(fp, "%x", &mem_word) != EOF) {
82      data_mem[size++] = mem_word;
83    }
84
85    // Start off simulation by writing program_counter
86    program_counter.write(pc);
87  }
88
89  // Functionality
90  void entry();
91};
92
93void
94exec_decode::entry()
95{
96  unsigned instr;
97  unsigned opcode;
98  unsigned regnum1, regnum2, regnum3;
99  unsigned addr;
100
101  int i;
102
103  instr = instruction.read();
104  opcode = (instr & 0xe0000000) >> 29; // Extract opcode
105  switch(opcode) {
106  case 0x0: // Halt
107    printf("CPU Halted\n");
108    printf("\tPC = 0x%x\n", pc);
109    for (i = 0; i < 32; i++)
110      printf("\tR[%d] = %x\n", i, cpu_reg[i]);
111    // Don't write pc and execution will stop
112    break;
113  case 0x1: // Store
114    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
115    addr = (instr & 0x00ffffff); //  Extract address
116    printf("Store: Memory[0x%x] = R[%d]\n", addr, regnum1);
117    data_mem[addr] = cpu_reg[regnum1];
118    pc = pc + 1;
119    program_counter.write(pc);
120    break;
121  case 0x2: // Load
122    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
123    addr = (instr & 0x00ffffff); //  Extract address
124    printf("Load: R[%d] = Memory[0x%x]\n", regnum1, addr);
125    cpu_reg[regnum1] = data_mem[addr];
126    pc = pc + 1;
127    program_counter.write(pc);
128    break;
129  case 0x3: // Add
130    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
131    regnum2 = (instr & 0x00f80000) >> 19; // Extract register number
132    regnum3 = (instr & 0x0007c000) >> 14; // Extract register number
133    printf("R[%d] = R[%d] + R[%d]\n", regnum3, regnum1, regnum2);
134    cpu_reg[regnum3] = cpu_reg[regnum1] + cpu_reg[regnum2];
135    pc = pc + 1;
136    program_counter.write(pc);
137    break;
138  case 0x4: // Subtract
139    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
140    regnum2 = (instr & 0x00f80000) >> 19; // Extract register number
141    regnum3 = (instr & 0x0007c000) >> 14; // Extract register number
142    printf("R[%d] = R[%d] - R[%d]\n", regnum3, regnum1, regnum2);
143    cpu_reg[regnum3] = cpu_reg[regnum1] - cpu_reg[regnum2];
144    pc = pc + 1;
145    program_counter.write(pc);
146    break;
147  case 0x5: // Multiply
148    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
149    regnum2 = (instr & 0x00f80000) >> 19; // Extract register number
150    regnum3 = (instr & 0x0007c000) >> 14; // Extract register number
151    printf("R[%d] = R[%d] * R[%d]\n", regnum3, regnum1, regnum2);
152    cpu_reg[regnum3] = cpu_reg[regnum1] * cpu_reg[regnum2];
153    pc = pc + 1;
154    program_counter.write(pc);
155    break;
156  case 0x6: // Divide
157    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
158    regnum2 = (instr & 0x00f80000) >> 19; // Extract register number
159    regnum3 = (instr & 0x0007c000) >> 14; // Extract register number
160    printf("R[%d] = R[%d] / R[%d]\n", regnum3, regnum1, regnum2);
161    if (cpu_reg[regnum2] == 0) {
162      printf("Division exception - divide by zero\n");
163    }
164    else {
165      cpu_reg[regnum3] = cpu_reg[regnum1] / cpu_reg[regnum2];
166    }
167    pc = pc + 1;
168    program_counter.write(pc);
169    break;
170  case 0x7: // JNZ
171    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
172    addr = (instr & 0x00ffffff); //  Extract address
173    printf("JNZ R[%d] 0x%x\n", regnum1, addr);
174    if (cpu_reg[regnum1] == 0x0)
175      pc = pc + 1;
176    else
177      pc = addr;
178    program_counter.write(pc);
179    break;
180  default: // Bad opcode
181    printf("Bad opcode 0x%x\n", opcode);
182    pc = pc + 1;
183    program_counter.write(pc);
184    break;
185  }
186}
187
188
189SC_MODULE( fetch )
190{
191  SC_HAS_PROCESS( fetch );
192
193  sc_in<unsigned> program_counter;
194  sc_signal<unsigned>& instruction;
195
196  unsigned *prog_mem; // The program memory
197
198  fetch( sc_module_name NAME,
199	 sc_signal<unsigned>& PROGRAM_COUNTER,
200	 sc_signal<unsigned>& INSTRUCTION )
201    : instruction(INSTRUCTION)
202  {
203    program_counter(PROGRAM_COUNTER);
204    SC_METHOD( entry );
205    sensitive << program_counter;
206
207    // Initialize the program memory from file progmem
208    FILE *fp = fopen("simple_cpu/progmem", "r");
209    if (fp == (FILE *) 0) return; // No prog mem file to read
210    // First field in this file is the size of program memory desired
211    int size;
212    fscanf(fp, "%d", &size);
213    prog_mem = new unsigned[size];
214    if (prog_mem == (unsigned *) 0) {
215      printf("Not enough memory left\n");
216      return;
217    }
218    unsigned mem_word;
219    size = 0;
220    while (fscanf(fp, "%x", &mem_word) != EOF) {
221      prog_mem[size++] = mem_word;
222    }
223    instruction.write(0);
224  }
225
226  // Functionality
227  void entry();
228};
229
230void fetch::entry()
231{
232  unsigned pc, instr;
233  pc = program_counter.read();
234  instr = prog_mem[pc];
235  instruction.write(instr);
236}
237
238int
239sc_main(int ac, char *av[])
240{
241  sc_signal<unsigned> pc;
242  sc_signal<unsigned> instr;
243
244  exec_decode ED("ED", instr, pc);
245  fetch F("F", pc, instr);
246
247  // instead of a testbench routine, we include the testbench here
248  sc_start(1, SC_NS);
249  sc_start( 10, SC_NS );
250
251  fflush( stdout );
252
253  return 0;
254}
255