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