112855Sgabeblack@google.com/*****************************************************************************
212855Sgabeblack@google.com
312855Sgabeblack@google.com  Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
412855Sgabeblack@google.com  more contributor license agreements.  See the NOTICE file distributed
512855Sgabeblack@google.com  with this work for additional information regarding copyright ownership.
612855Sgabeblack@google.com  Accellera licenses this file to you under the Apache License, Version 2.0
712855Sgabeblack@google.com  (the "License"); you may not use this file except in compliance with the
812855Sgabeblack@google.com  License.  You may obtain a copy of the License at
912855Sgabeblack@google.com
1012855Sgabeblack@google.com    http://www.apache.org/licenses/LICENSE-2.0
1112855Sgabeblack@google.com
1212855Sgabeblack@google.com  Unless required by applicable law or agreed to in writing, software
1312855Sgabeblack@google.com  distributed under the License is distributed on an "AS IS" BASIS,
1412855Sgabeblack@google.com  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
1512855Sgabeblack@google.com  implied.  See the License for the specific language governing
1612855Sgabeblack@google.com  permissions and limitations under the License.
1712855Sgabeblack@google.com
1812855Sgabeblack@google.com *****************************************************************************/
1912855Sgabeblack@google.com
2012855Sgabeblack@google.com/*****************************************************************************
2112855Sgabeblack@google.com
2212855Sgabeblack@google.com  simple_cpu.cpp --
2312855Sgabeblack@google.com
2412855Sgabeblack@google.com  Original Author: Martin Janssen, Synopsys, Inc., 2002-02-15
2512855Sgabeblack@google.com
2612855Sgabeblack@google.com *****************************************************************************/
2712855Sgabeblack@google.com
2812855Sgabeblack@google.com/*****************************************************************************
2912855Sgabeblack@google.com
3012855Sgabeblack@google.com  MODIFICATION LOG - modifiers, enter your name, affiliation, date and
3112855Sgabeblack@google.com  changes you are making here.
3212855Sgabeblack@google.com
3312855Sgabeblack@google.com      Name, Affiliation, Date:
3412855Sgabeblack@google.com  Description of Modification:
3512855Sgabeblack@google.com
3612855Sgabeblack@google.com *****************************************************************************/
3712855Sgabeblack@google.com
3812855Sgabeblack@google.com#include "systemc.h"
3912855Sgabeblack@google.com
4012855Sgabeblack@google.com#define READ 0
4112855Sgabeblack@google.com#define WRITE 1
4212855Sgabeblack@google.com
4312855Sgabeblack@google.comSC_MODULE( exec_decode )
4412855Sgabeblack@google.com{
4512855Sgabeblack@google.com  SC_HAS_PROCESS( exec_decode );
4612855Sgabeblack@google.com
4712855Sgabeblack@google.com  sc_in<unsigned>  instruction;
4812855Sgabeblack@google.com  sc_signal<unsigned>& program_counter;
4912855Sgabeblack@google.com
5012855Sgabeblack@google.com  unsigned pc; // Program counter
5112855Sgabeblack@google.com  unsigned cpu_reg[32]; // Cpu registers
5212855Sgabeblack@google.com
5312855Sgabeblack@google.com  unsigned *data_mem; // The data memory
5412855Sgabeblack@google.com
5512855Sgabeblack@google.com  exec_decode( sc_module_name NAME,
5612855Sgabeblack@google.com	       sc_signal<unsigned>& INSTRUCTION,
5712855Sgabeblack@google.com	       sc_signal<unsigned>& PROGRAM_COUNTER )
5812855Sgabeblack@google.com    : program_counter(PROGRAM_COUNTER)
5912855Sgabeblack@google.com  {
6012855Sgabeblack@google.com    instruction(INSTRUCTION);
6112855Sgabeblack@google.com	SC_METHOD( entry );
6212855Sgabeblack@google.com    // sensitive only to the clock
6312855Sgabeblack@google.com    sensitive << instruction;
6412855Sgabeblack@google.com
6512855Sgabeblack@google.com    pc = 0x000000; // Power up reset value
6612855Sgabeblack@google.com    for (int i =0; i<32; i++) cpu_reg[i] = 0;
6712855Sgabeblack@google.com
6812855Sgabeblack@google.com    // Initialize the data memory from file datamem
6912855Sgabeblack@google.com    FILE *fp = fopen("simple_cpu/datamem", "r");
7012855Sgabeblack@google.com    if (fp == (FILE *) 0) return; // No data mem file to read
7112855Sgabeblack@google.com    // First field in this file is the size of data memory desired
7212855Sgabeblack@google.com    int size;
7312855Sgabeblack@google.com    fscanf(fp, "%d", &size);
7412855Sgabeblack@google.com    data_mem = new unsigned[size];
7512855Sgabeblack@google.com    if (data_mem == (unsigned *) 0) {
7612855Sgabeblack@google.com      printf("Not enough memory left\n");
7712855Sgabeblack@google.com      return;
7812855Sgabeblack@google.com    }
7912855Sgabeblack@google.com    unsigned mem_word;
8012855Sgabeblack@google.com    size = 0;
8112855Sgabeblack@google.com    while (fscanf(fp, "%x", &mem_word) != EOF) {
8212855Sgabeblack@google.com      data_mem[size++] = mem_word;
8312855Sgabeblack@google.com    }
8412855Sgabeblack@google.com
8512855Sgabeblack@google.com    // Start off simulation by writing program_counter
8612855Sgabeblack@google.com    program_counter.write(pc);
8712855Sgabeblack@google.com  }
8812855Sgabeblack@google.com
8912855Sgabeblack@google.com  // Functionality
9012855Sgabeblack@google.com  void entry();
9112855Sgabeblack@google.com};
9212855Sgabeblack@google.com
9312855Sgabeblack@google.comvoid
9412855Sgabeblack@google.comexec_decode::entry()
9512855Sgabeblack@google.com{
9612855Sgabeblack@google.com  unsigned instr;
9712855Sgabeblack@google.com  unsigned opcode;
9812855Sgabeblack@google.com  unsigned regnum1, regnum2, regnum3;
9912855Sgabeblack@google.com  unsigned addr;
10012855Sgabeblack@google.com
10112855Sgabeblack@google.com  int i;
10212855Sgabeblack@google.com
10312855Sgabeblack@google.com  instr = instruction.read();
10412855Sgabeblack@google.com  opcode = (instr & 0xe0000000) >> 29; // Extract opcode
10512855Sgabeblack@google.com  switch(opcode) {
10612855Sgabeblack@google.com  case 0x0: // Halt
10712855Sgabeblack@google.com    printf("CPU Halted\n");
10812855Sgabeblack@google.com    printf("\tPC = 0x%x\n", pc);
10912855Sgabeblack@google.com    for (i = 0; i < 32; i++)
11012855Sgabeblack@google.com      printf("\tR[%d] = %x\n", i, cpu_reg[i]);
11112855Sgabeblack@google.com    // Don't write pc and execution will stop
11212855Sgabeblack@google.com    break;
11312855Sgabeblack@google.com  case 0x1: // Store
11412855Sgabeblack@google.com    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
11512855Sgabeblack@google.com    addr = (instr & 0x00ffffff); //  Extract address
11612855Sgabeblack@google.com    printf("Store: Memory[0x%x] = R[%d]\n", addr, regnum1);
11712855Sgabeblack@google.com    data_mem[addr] = cpu_reg[regnum1];
11812855Sgabeblack@google.com    pc = pc + 1;
11912855Sgabeblack@google.com    program_counter.write(pc);
12012855Sgabeblack@google.com    break;
12112855Sgabeblack@google.com  case 0x2: // Load
12212855Sgabeblack@google.com    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
12312855Sgabeblack@google.com    addr = (instr & 0x00ffffff); //  Extract address
12412855Sgabeblack@google.com    printf("Load: R[%d] = Memory[0x%x]\n", regnum1, addr);
12512855Sgabeblack@google.com    cpu_reg[regnum1] = data_mem[addr];
12612855Sgabeblack@google.com    pc = pc + 1;
12712855Sgabeblack@google.com    program_counter.write(pc);
12812855Sgabeblack@google.com    break;
12912855Sgabeblack@google.com  case 0x3: // Add
13012855Sgabeblack@google.com    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
13112855Sgabeblack@google.com    regnum2 = (instr & 0x00f80000) >> 19; // Extract register number
13212855Sgabeblack@google.com    regnum3 = (instr & 0x0007c000) >> 14; // Extract register number
13312855Sgabeblack@google.com    printf("R[%d] = R[%d] + R[%d]\n", regnum3, regnum1, regnum2);
13412855Sgabeblack@google.com    cpu_reg[regnum3] = cpu_reg[regnum1] + cpu_reg[regnum2];
13512855Sgabeblack@google.com    pc = pc + 1;
13612855Sgabeblack@google.com    program_counter.write(pc);
13712855Sgabeblack@google.com    break;
13812855Sgabeblack@google.com  case 0x4: // Subtract
13912855Sgabeblack@google.com    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
14012855Sgabeblack@google.com    regnum2 = (instr & 0x00f80000) >> 19; // Extract register number
14112855Sgabeblack@google.com    regnum3 = (instr & 0x0007c000) >> 14; // Extract register number
14212855Sgabeblack@google.com    printf("R[%d] = R[%d] - R[%d]\n", regnum3, regnum1, regnum2);
14312855Sgabeblack@google.com    cpu_reg[regnum3] = cpu_reg[regnum1] - cpu_reg[regnum2];
14412855Sgabeblack@google.com    pc = pc + 1;
14512855Sgabeblack@google.com    program_counter.write(pc);
14612855Sgabeblack@google.com    break;
14712855Sgabeblack@google.com  case 0x5: // Multiply
14812855Sgabeblack@google.com    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
14912855Sgabeblack@google.com    regnum2 = (instr & 0x00f80000) >> 19; // Extract register number
15012855Sgabeblack@google.com    regnum3 = (instr & 0x0007c000) >> 14; // Extract register number
15112855Sgabeblack@google.com    printf("R[%d] = R[%d] * R[%d]\n", regnum3, regnum1, regnum2);
15212855Sgabeblack@google.com    cpu_reg[regnum3] = cpu_reg[regnum1] * cpu_reg[regnum2];
15312855Sgabeblack@google.com    pc = pc + 1;
15412855Sgabeblack@google.com    program_counter.write(pc);
15512855Sgabeblack@google.com    break;
15612855Sgabeblack@google.com  case 0x6: // Divide
15712855Sgabeblack@google.com    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
15812855Sgabeblack@google.com    regnum2 = (instr & 0x00f80000) >> 19; // Extract register number
15912855Sgabeblack@google.com    regnum3 = (instr & 0x0007c000) >> 14; // Extract register number
16012855Sgabeblack@google.com    printf("R[%d] = R[%d] / R[%d]\n", regnum3, regnum1, regnum2);
16112855Sgabeblack@google.com    if (cpu_reg[regnum2] == 0) {
16212855Sgabeblack@google.com      printf("Division exception - divide by zero\n");
16312855Sgabeblack@google.com    }
16412855Sgabeblack@google.com    else {
16512855Sgabeblack@google.com      cpu_reg[regnum3] = cpu_reg[regnum1] / cpu_reg[regnum2];
16612855Sgabeblack@google.com    }
16712855Sgabeblack@google.com    pc = pc + 1;
16812855Sgabeblack@google.com    program_counter.write(pc);
16912855Sgabeblack@google.com    break;
17012855Sgabeblack@google.com  case 0x7: // JNZ
17112855Sgabeblack@google.com    regnum1 = (instr & 0x1f000000) >> 24; // Extract register number
17212855Sgabeblack@google.com    addr = (instr & 0x00ffffff); //  Extract address
17312855Sgabeblack@google.com    printf("JNZ R[%d] 0x%x\n", regnum1, addr);
17412855Sgabeblack@google.com    if (cpu_reg[regnum1] == 0x0)
17512855Sgabeblack@google.com      pc = pc + 1;
17612855Sgabeblack@google.com    else
17712855Sgabeblack@google.com      pc = addr;
17812855Sgabeblack@google.com    program_counter.write(pc);
17912855Sgabeblack@google.com    break;
18012855Sgabeblack@google.com  default: // Bad opcode
18112855Sgabeblack@google.com    printf("Bad opcode 0x%x\n", opcode);
18212855Sgabeblack@google.com    pc = pc + 1;
18312855Sgabeblack@google.com    program_counter.write(pc);
18412855Sgabeblack@google.com    break;
18512855Sgabeblack@google.com  }
18612855Sgabeblack@google.com}
18712855Sgabeblack@google.com
18812855Sgabeblack@google.com
18912855Sgabeblack@google.comSC_MODULE( fetch )
19012855Sgabeblack@google.com{
19112855Sgabeblack@google.com  SC_HAS_PROCESS( fetch );
19212855Sgabeblack@google.com
19312855Sgabeblack@google.com  sc_in<unsigned> program_counter;
19412855Sgabeblack@google.com  sc_signal<unsigned>& instruction;
19512855Sgabeblack@google.com
19612855Sgabeblack@google.com  unsigned *prog_mem; // The program memory
19712855Sgabeblack@google.com
19812855Sgabeblack@google.com  fetch( sc_module_name NAME,
19912855Sgabeblack@google.com	 sc_signal<unsigned>& PROGRAM_COUNTER,
20012855Sgabeblack@google.com	 sc_signal<unsigned>& INSTRUCTION )
20112855Sgabeblack@google.com    : instruction(INSTRUCTION)
20212855Sgabeblack@google.com  {
20312855Sgabeblack@google.com    program_counter(PROGRAM_COUNTER);
20412855Sgabeblack@google.com    SC_METHOD( entry );
20512855Sgabeblack@google.com    sensitive << program_counter;
20612855Sgabeblack@google.com
20712855Sgabeblack@google.com    // Initialize the program memory from file progmem
20812855Sgabeblack@google.com    FILE *fp = fopen("simple_cpu/progmem", "r");
20912855Sgabeblack@google.com    if (fp == (FILE *) 0) return; // No prog mem file to read
21012855Sgabeblack@google.com    // First field in this file is the size of program memory desired
21112855Sgabeblack@google.com    int size;
21212855Sgabeblack@google.com    fscanf(fp, "%d", &size);
21312855Sgabeblack@google.com    prog_mem = new unsigned[size];
21412855Sgabeblack@google.com    if (prog_mem == (unsigned *) 0) {
21512855Sgabeblack@google.com      printf("Not enough memory left\n");
21612855Sgabeblack@google.com      return;
21712855Sgabeblack@google.com    }
21812855Sgabeblack@google.com    unsigned mem_word;
21912855Sgabeblack@google.com    size = 0;
22012855Sgabeblack@google.com    while (fscanf(fp, "%x", &mem_word) != EOF) {
22112855Sgabeblack@google.com      prog_mem[size++] = mem_word;
22212855Sgabeblack@google.com    }
22312855Sgabeblack@google.com    instruction.write(0);
22412855Sgabeblack@google.com  }
22512855Sgabeblack@google.com
22612855Sgabeblack@google.com  // Functionality
22712855Sgabeblack@google.com  void entry();
22812855Sgabeblack@google.com};
22912855Sgabeblack@google.com
23012855Sgabeblack@google.comvoid fetch::entry()
23112855Sgabeblack@google.com{
23212855Sgabeblack@google.com  unsigned pc, instr;
23312855Sgabeblack@google.com  pc = program_counter.read();
23412855Sgabeblack@google.com  instr = prog_mem[pc];
23512855Sgabeblack@google.com  instruction.write(instr);
23612855Sgabeblack@google.com}
23712855Sgabeblack@google.com
23812855Sgabeblack@google.comint
23912855Sgabeblack@google.comsc_main(int ac, char *av[])
24012855Sgabeblack@google.com{
24112855Sgabeblack@google.com  sc_signal<unsigned> pc;
24212855Sgabeblack@google.com  sc_signal<unsigned> instr;
24312855Sgabeblack@google.com
24412855Sgabeblack@google.com  exec_decode ED("ED", instr, pc);
24512855Sgabeblack@google.com  fetch F("F", pc, instr);
24612855Sgabeblack@google.com
24712855Sgabeblack@google.com  // instead of a testbench routine, we include the testbench here
24812855Sgabeblack@google.com  sc_start(1, SC_NS);
24912855Sgabeblack@google.com  sc_start( 10, SC_NS );
25012855Sgabeblack@google.com
25112855Sgabeblack@google.com  fflush( stdout );
25212855Sgabeblack@google.com
25312855Sgabeblack@google.com  return 0;
25412855Sgabeblack@google.com}
255