Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

ECE 310

Fall 2022

Design of Complex Digital Systems

Project #1: Simple CPU

1. Introduction

The main purpose of this project is to let you start dealing with more complex designs, and become familiar with some of the elements used within a CPU.

All code will be scanned through MOSS system ( https://theory.stanford.edu/~aiken/moss/ ) to detect plagiarism.  Please feel free to discuss. But don’t look at anyone one’s code or

show your code to anyone one either. If any plagiarism is detected, strict action will be taken.

2. Learning Objectives

.     Complete a design involving separate control and datapath with multiple modules

.     Complete a design that includes most of the elements to be used in the CPU

3. Project Report

You are expected to turn in a report after the end of this project. Follow the project report format on the course web-site.  Be sure to include all items listed in that report format for full credit.

4. Design: simplified CPU

The microcontroller designed in this assignment is a simplified version of a CPU. Specifically, four simplifications are considered as follows:

1)   No off-chip memory: The instructions of the program are assumed to be in the   memory.   2)   The programs  consist of valid instructions  ONLY, i.e., you do not have to perform error

checking to detect bad instructions

3)   No overflow detection is required.

4)   The CPU has a synchronous reset rst. That resets all registers to zero.

5. Design: Guidelines

For the ADD, SUB, MUL, DIV and XOR operations, Modules developed in HW3, 5 and 6 need to be used. Any other implementation will be considered incomplete and only partial credits will be given which will not exceed 25% of the credit. Once the design is completed, verify that the design works as expected. A testbench and memory image file will be provided.

4. Wolfware Submission

You also need to  submit your Verilog code electronically through Wolfware as proj1.v.   This file  should  contain a module  called proj1  and  include the provided test bench.   It may use the ‘include  directive  to  include  other  files,  if  you  wish,  but  they  must  also  be   submitted  with Wolfware.  In addition, a second program will be used to test your code that will not be provided.

Instructions set:

0x01  ADD

0x02 SUB

0x03 MUL

0x04  DIV

0x05  XOR

0x6 JUMP

0x7 JUMPZ

0x8 STORE

0x9 LOAD

They have to be implemented this way

0x01  ADD  => you have to use HW3 module  my8bitaddsub_gate

0x02 SUB =>   you have to use HW3 module    my8bitaddsub_gate

0x03 MUL =>  you have to use HW5 module

0x04  DIV =>    you have to use HW6 module

0x05  XOR =>  you have to use 2-1 mux based XOR developed in HW3

5.1 Top-level module:

module proj1(

clk,

rst,

MemRW_IO,

MemAddr_IO,

MemD_IO

);

input clk;

input rst;

output MemRW_IO;

output [7:0]MemAddr_IO;

output [15:0]MemD_IO;

CPU Schematic

Here are the modules that needs to be coded up

All instructions are assumed to present in a memory

Module 1

The memory module:

module  ram(

we,

d,

q,

addr

);

We => 1 bit read / write enable

D => 16 bit data input

Q => 16 bit data output

Addr => 8 bit input address

Module 2

Alu module

module alu(

A,

B,

opALU,

Rout

);

A =>  16 bit input 1

B => 16 bit input 2

opAlu, 2 bit input, 0 = xor, 1 = a+b, 3 = negate

Rout => 16 bit output

Module 3

Controller

module ctr (

clk,

rst,

zflag,

opcode,

muxPC,

muxMAR,

muxACC,

loadMAR,

loadPC,

loadACC,

loadMDR,

loadIR,

opALU,

MemRW

);

input clk;

input rst;

input zflag;

input [7:0]opcode;

output reg muxPC;

output reg muxMAR;

output reg muxACC;

output reg loadMAR;

output reg loadPC;

output reg loadACC;

output reg loadMDR;

output reg loadIR;

output reg opALU;

output reg MemRW;

You will have to think about how to integrate the HW modules in to the project. A simple way   would be to do DIV   similar to ADD. You will have div_ 1 and div_2 to get the two parameters.

Then you will have div_3 , 4, 5 , 6 that would the 4 state machine states in HW6.

we move through the states at each clock cycle. There are only two exceptions. At decode we have to see what is the opcode and go to the next state accordingly.

At Jumpz you have to look at the zeroflag. If the flag is high, we have to execute to go to the exec jump state or go to fetch_ 1 state.

When at each of the state you will have to set all the appropriate outputs as shown in the finite state machine.

Module 4

Register bank

module registers(

clk,

rst,

PC_reg,

PC_next,

IR_reg,

IR_next,

ACC_reg,

ACC_next,

MDR_reg,

MDR_next,

MAR_reg,

MAR_next,

Zflag_reg,

zflag_next

);

input wire clk;

input wire rst;

output reg   [7:0]PC_reg;

input wire   [7:0]PC_next;

output reg   [15:0]IR_reg;

input wire  [15:0]IR_next;

output reg  [15:0]ACC_reg;

input wire  [15:0]ACC_next;

output reg  [15:0]MDR_reg;

input wire  [15:0]MDR_next;

output reg   [7:0]MAR_reg;

input wire  [7:0]MAR_next;

output reg Zflag_reg;

input wire zflag_next;

This is a very simple module. At reset set all registers to zero. At all other clocks cycles, All it does is at each rising edge of clock, it grabs the next value and stores it in the registers.

Module 5

Data path: In this module the next values are generated for all the registers and the singles to drive all the muxes.

module datapath(

clk,

rst,

muxPC,

muxMAR,

muxACC,

loadMAR,

loadPC,

loadACC,

loadMDR,

loadIR,

opALU,

zflag,

opcode,

MemAddr,

MemD,

MemQ

);

input clk;

input  rst;

input  muxPC;

input  muxMAR;

input  muxACC;

input  loadMAR;

input  loadPC;

input  loadACC;

input  loadMDR;

input  loadIR;

input  opALU;

output   zflag;

output    [7:0]opcode;

output    [7:0]MemAddr;

output   [15:0]MemD;

input   [15:0]MemQ;

reg  [7:0]PC_next;

wire  [15:0]IR_next;

reg  [15:0]ACC_next;

wire  [15:0]MDR_next;

reg  [7:0]MAR_next;

reg zflag_next;

wire  [7:0]PC_reg;

wire  [15:0]IR_reg;

wire  [15:0]ACC_reg;

wire  [15:0]MDR_reg;

wire  [7:0]MAR_reg;

wire zflag_reg;

wire  [15:0]ALU_out;

//one instance of ALU

// one instance of register.


//code to generate

[7:0]PC_next;

Only change if loadpc is enabled.

Mux pc decides between pc+1 or branch address

Reset address is 0, Hence nothing for the datapath to do at reset.

[15:0]IR_next;

Gets value of mdr_reg if loadir is set

[15:0]ACC_next;

Only change when loaddacc is enabled.

Muxacc decides between mdr_reg and alu out

[15:0]MDR_next;

Gets value from memeory,  if load mdr is set

[7:0]MAR_next;

Only change if loadmar is enabled.

Mux mar decides between  pcreg or IR[15:8]reg

zflag_next;

Decide  based on the content of acc_reg

//needs to generate the following outputs

//set this outputs based on the registered value and not the next value to prevent glitches.

output   zflag; => based on ACC reg

output    [7:0]opcode; => based on IR_reg

output   [7:0]MemAddr => Same as MAR_reg

output   [15:0]MemD => Same as ACC reg

Module 6

High level module

module proj1(

clk,

rst,

MemRW_IO,

MemAddr_IO,

MemD_IO

);

input clk;

input rst;

output MemRW_IO;

output [7:0]MemAddr_IO;

output [15:0]MemD_IO;

//one instance of memory

//one instance of controller

//one instance of datapath1

//these are just to observe the signals.

assign MemAddr_IO = MemAddr;

assign MemD_IO = MemD;

assign MemRW_IO = MemRW;

The program to be loaded in to memory for verification

A test bench and a memory image memory.list will be provided.

Testbench snippet

always

#5 clk = !clk;

initial begin

clk=1'b0;

rst=1'b1;

$readmemh("memory.list", proj1_tb.dut.ram_ins.mem256x16);

#20 rst=1'b0;

#40000 //might need to be very large

$display("Final value\n");

$display("0x000e %d\n",proj1_tb.dut.ram_ins.mem256x16[16'h000e]);

$finish;

end