add provided RTL models
This commit is contained in:
parent
652ecf2686
commit
31b077c5f2
55
RTL/ALU.sv
Normal file
55
RTL/ALU.sv
Normal file
@ -0,0 +1,55 @@
|
||||
// Create Date: 2018.10.15
|
||||
// Module Name: ALU
|
||||
// Project Name: CSE141L
|
||||
//
|
||||
// Revision 2022.04.30
|
||||
// Additional Comments:
|
||||
// combinational (unclocked) ALU
|
||||
import definitions::*; // includes package "definitions"
|
||||
module ALU #(parameter W=8)(
|
||||
input [W-1:0] InputA, // data inputs
|
||||
InputB,
|
||||
input SC_in, // shift or carry in
|
||||
input [ 2:0] OP, // ALU opcode, part of microcode
|
||||
output logic [W-1:0] Out, // or: output reg [7:0] OUT,
|
||||
output logic PF, // reduction parity
|
||||
output logic Zero, // output = zero flag
|
||||
output logic SC_out // shift or carry out
|
||||
// you may provide additional status flags as inputs, if desired
|
||||
);
|
||||
|
||||
op_mne op_mnemonic; // type enum: used for convenient waveform viewing
|
||||
|
||||
// InputA = current LFSR state
|
||||
// InputB = tap_pattern
|
||||
always_comb begin
|
||||
Out = 0;
|
||||
SC_out = 0; // No Op = default
|
||||
case(OP)
|
||||
kADD : {SC_out,Out} = {1'b0,InputA} + InputB; // add
|
||||
kLSH : {SC_out,Out} = {InputA[7:0],SC_in}; // shift left, fill in with SC_in
|
||||
// for logical left shift, tie SC_in = 0
|
||||
kRSH : {Out,SC_out} = {SC_in, InputA[7:0]}; // shift right
|
||||
kXOR : Out = InputA ^ InputB; // exclusive OR
|
||||
kAND : Out = InputA & InputB; // bitwise AND
|
||||
endcase
|
||||
end
|
||||
|
||||
always_comb // assign Zero = !Out;
|
||||
case(Out)
|
||||
'b0 : Zero = 1'b1;
|
||||
default : Zero = 1'b0;
|
||||
endcase
|
||||
|
||||
always_comb
|
||||
PF = ^Out; // Out[7]^Out[6]^...^Out[0] // reduction XOR
|
||||
|
||||
always_comb
|
||||
op_mnemonic = op_mne'(OP); // displays operation name in waveform viewer
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
/* InputA=10101010 SC_in = 1
|
||||
kLSH Out = 01010101
|
||||
*/
|
56
RTL/Ctrl.sv
Normal file
56
RTL/Ctrl.sv
Normal file
@ -0,0 +1,56 @@
|
||||
// CSE141L
|
||||
import definitions::*;
|
||||
// control decoder (combinational, not clocked)
|
||||
// inputs from instrROM, ALU flags
|
||||
// outputs to program_counter (fetch unit)
|
||||
module Ctrl (
|
||||
input[ 8:0] Instruction, // machine code
|
||||
input[ 7:0] DatMemAddr,
|
||||
output logic Jump ,
|
||||
BranchEn ,
|
||||
RegWrEn , // write to reg_file (common)
|
||||
MemWrEn , // write to mem (store only)
|
||||
LoadInst , // mem or ALU to reg_file ?
|
||||
PCTarg ,
|
||||
tapSel ,
|
||||
Ack // "done w/ program"
|
||||
// output logic[2:0] ALU_inst
|
||||
);
|
||||
|
||||
/* ***** All numerical values are completely arbitrary and for illustration only *****
|
||||
*/
|
||||
|
||||
// ALU commands
|
||||
//assign ALU_inst = Instruction[2:0];
|
||||
|
||||
// STR commands only -- write to data_memory
|
||||
assign MemWrEn = Instruction[8:6]==3'b110;
|
||||
|
||||
// all but STR and NOOP (or maybe CMP or TST) -- write to reg_file
|
||||
assign RegWrEn = Instruction[8:7]!=2'b11;
|
||||
|
||||
// route data memory --> reg_file for loads
|
||||
// whenever instruction = 9'b110??????;
|
||||
assign LoadInst = Instruction[8:6]==3'b110; // calls out load specially
|
||||
|
||||
assign tapSel = LoadInst && DatMemAddr=='d62;
|
||||
// jump enable command to program counter / instruction fetch module on right shift command
|
||||
// equiv to simply: assign Jump = Instruction[2:0] == kRSH;
|
||||
always_comb
|
||||
if(Instruction[2:0] == kRSH)
|
||||
Jump = 1;
|
||||
else
|
||||
Jump = 0;
|
||||
|
||||
// branch every time instruction = 9'b?????1111;
|
||||
assign BranchEn = &Instruction[3:0];
|
||||
|
||||
// whenever branch or jump is taken, PC gets updated or incremented from "Target"
|
||||
// PCTarg = 2-bit address pointer into Target LUT (PCTarg in --> Target out
|
||||
assign PCTarg = Instruction[3:2];
|
||||
|
||||
// reserve instruction = 9'b111111111; for Ack
|
||||
assign Ack = &Instruction;
|
||||
|
||||
endmodule
|
||||
|
39
RTL/DataMem.sv
Normal file
39
RTL/DataMem.sv
Normal file
@ -0,0 +1,39 @@
|
||||
// Create Date: 2017.01.25
|
||||
// Revision: 2022.05.04 made data width parametric
|
||||
// Design Name:
|
||||
// Module Name: DataMem
|
||||
// single address pointer for both read and write
|
||||
// CSE141L
|
||||
module DataMem #(parameter W=8, D=8)(
|
||||
input Clk,
|
||||
Reset, // again, note use of Reset for preloads
|
||||
WriteEn,
|
||||
input [D-1:0] DataAddress, // 8-bit-wide pointer to 256-deep memory
|
||||
input [W-1:0] DataIn, // 8-bit-wide data path, also
|
||||
output logic[W-1:0] DataOut);
|
||||
|
||||
logic [W-1:0] Core[2**D]; // 8x256 two-dimensional array -- the memory itself
|
||||
|
||||
always_comb // reads are combinational
|
||||
DataOut = Core[DataAddress];
|
||||
|
||||
/* optional way to plant constants into DataMem at startup
|
||||
initial
|
||||
$readmemh("dataram_init.list", Core);
|
||||
*/
|
||||
always_ff @ (posedge Clk) // writes are sequential
|
||||
/*( Reset response is needed only for initialization (see inital $readmemh above for another choice)
|
||||
if you do not need to preload your data memory with any constants, you may omit the if(Reset) and the else,
|
||||
and go straight to if(WriteEn) ...
|
||||
*/
|
||||
if(Reset) begin
|
||||
// you may initialize your memory w/ constants, if you wish
|
||||
for(int i=128;i<256;i++)
|
||||
Core[ i] <= 0;
|
||||
Core[ 16] <= 254; // overrides the 0 ***sample only***
|
||||
Core[244] <= 5; // likewise
|
||||
end
|
||||
else if(WriteEn)
|
||||
Core[DataAddress] <= DataIn;
|
||||
|
||||
endmodule
|
24
RTL/Definitions.sv
Normal file
24
RTL/Definitions.sv
Normal file
@ -0,0 +1,24 @@
|
||||
//This file defines the parameters used in the alu
|
||||
// CSE141L
|
||||
// Rev. 2020.5.27
|
||||
// import package into each module that needs it
|
||||
// packages very useful for declaring global variables
|
||||
package definitions;
|
||||
|
||||
/* Instruction map
|
||||
const logic [2:0]kADD = 3'b000;
|
||||
const logic [2:0]kLSH = 3'b001;
|
||||
const logic [2:0]kRSH = 3'b010;
|
||||
const logic [2:0]kXOR = 3'b011;
|
||||
const logic [2:0]kAND = 3'b100;
|
||||
const logic [2:0]kSUB = 3'b101;
|
||||
const logic [2:0]kCLR = 3'b110;
|
||||
*/
|
||||
// enum names will appear in timing diagram
|
||||
typedef enum logic[2:0] {
|
||||
ADD, LSH, BSH, XOR,
|
||||
AND, SUB, CLR } op_mne;
|
||||
// note: kADD is of type logic[2:0] (3-bit binary)
|
||||
// ADD is of type enum -- equiv., but watch casting
|
||||
// see ALU.sv for how to handle this
|
||||
endpackage // definitions
|
36
RTL/InstFetch.sv
Normal file
36
RTL/InstFetch.sv
Normal file
@ -0,0 +1,36 @@
|
||||
// Design Name: basic_proc
|
||||
// Module Name: InstFetch
|
||||
// Project Name: CSE141L
|
||||
// Description: instruction fetch (pgm ctr) for processor
|
||||
//
|
||||
// Revision: 2019.01.27
|
||||
// Suggested ProgCtr width 10 t0 12 bits
|
||||
module InstFetch #(parameter T=10)( // PC width -- up to 32, if you like
|
||||
input Reset, // reset, init, etc. -- force PC to 0
|
||||
Start, // begin next program in series (request issued by test bench)
|
||||
Clk, // PC can change on pos. edges only
|
||||
BranchAbs, // jump unconditionally to Target value
|
||||
BranchRelEn, // jump conditionally to Target + PC
|
||||
ALU_flag, // flag from ALU, e.g. Zero, Carry, Overflow, Negative (from ARM)
|
||||
input [T-1:0] Target, // jump ... "how high?"
|
||||
output logic [T-1:0] ProgCtr // the program counter register itself
|
||||
);
|
||||
|
||||
// you may wish to use either absolute or relative branching
|
||||
// you may use both, but you will need appropriate control bits
|
||||
// branch/jump is how we handle gosub and return to main
|
||||
// program counter can clear to 0, increment, or jump
|
||||
always_ff @(posedge Clk) // or just always; always_ff is a linting construct
|
||||
if(Reset)
|
||||
ProgCtr <= 0; // for first program; want different value for 2nd or 3rd
|
||||
else if(Start) // hold while start asserted; commence when released
|
||||
ProgCtr <= 0; //or <= ProgCtr; holds at starting value
|
||||
else if(BranchAbs) // unconditional absolute jump
|
||||
ProgCtr <= Target; // how would you make it conditional and/or relative?
|
||||
else if(BranchRelEn && ALU_flag) // conditional relative jump
|
||||
ProgCtr <= Target + ProgCtr; // how would you make it unconditional and/or absolute
|
||||
else
|
||||
ProgCtr <= ProgCtr+'b1; // default increment (no need for ARM/MIPS +4 -- why?)
|
||||
|
||||
endmodule
|
||||
|
32
RTL/InstFetch_TB.sv
Normal file
32
RTL/InstFetch_TB.sv
Normal file
@ -0,0 +1,32 @@
|
||||
module InstFetch_TB();
|
||||
|
||||
logic Reset = 1'b1,
|
||||
Start = 1'b0,
|
||||
Clk = 1'b0,
|
||||
BranchAbs = 1'b0,
|
||||
BranchRelEn = 1'b0,
|
||||
ALU_flag = 1'b0;
|
||||
logic [9:0] Target = 'b1; //10'h3fc;//'1; -4
|
||||
wire [9:0] ProgCtr;
|
||||
|
||||
InstFetch IF1(.*);
|
||||
|
||||
always begin
|
||||
#5ns Clk = 1'b1;
|
||||
#5ns Clk = 1'b0;
|
||||
end
|
||||
|
||||
initial begin
|
||||
#20ns Reset = 1'b0;
|
||||
#20ns Start = 1'b1;
|
||||
#20ns Start = 1'b0;
|
||||
#120ns BranchAbs = 1'b1; // should reset PC to 0
|
||||
#30ns BranchAbs = 1'b0;
|
||||
#250ns BranchRelEn = 1'b1;
|
||||
Target = 'h3fc; // -4
|
||||
#20ns ALU_flag = 1'b1;
|
||||
#40ns ALU_flag = 1'b0;
|
||||
#240ns $stop;
|
||||
end
|
||||
|
||||
endmodule
|
52
RTL/InstROM.sv
Normal file
52
RTL/InstROM.sv
Normal file
@ -0,0 +1,52 @@
|
||||
// Create Date: 15:50:22 10/02/2019
|
||||
// Design Name:
|
||||
// Module Name: InstROM
|
||||
// Project Name: CSE141L
|
||||
// Tool versions:
|
||||
// Description: Verilog module -- instruction ROM template
|
||||
// preprogrammed with instruction values (see case statement)
|
||||
//
|
||||
// Revision: 2020.08.08
|
||||
//
|
||||
module InstROM #(parameter A=12, W=9) (
|
||||
input [A-1:0] InstAddress,
|
||||
output logic[W-1:0] InstOut);
|
||||
|
||||
// (usually recommended) expression
|
||||
// need $readmemh or $readmemb to initialize all of the elements
|
||||
// declare 2-dimensional array, W bits wide, 2**A words deep
|
||||
logic[W-1:0] inst_rom[2**A];
|
||||
always_comb InstOut = inst_rom[InstAddress];
|
||||
|
||||
initial begin // load from external text file
|
||||
$readmemb("machine_code.txt",inst_rom);
|
||||
end
|
||||
|
||||
// Sample instruction format:
|
||||
// {3bit opcode, 3bit rs or rt, 3bit rt, immediate, or branch target}
|
||||
// then use LUT to map 3 bits to 10 for branch target, 8 for immediate
|
||||
|
||||
/* alternative to code shown below, which may be simpler -- either is fine
|
||||
always_comb begin
|
||||
InstOut = 'b0000000000; // default
|
||||
case (InstAddress)
|
||||
//opcode = 0 lhw, rs = 0, rt = 1
|
||||
0 : InstOut = 'b0000000001; // load from address at reg 0 to reg 1
|
||||
// opcode = 1 addi, rs/rt = 1, immediate = 1
|
||||
|
||||
1 : InstOut = 'b0001001001; // addi reg 1 and 1
|
||||
|
||||
// opcode = 2 shw, rs = 0, rt = 1
|
||||
2 : InstOut = 'b0010000001; // sw reg 1 to address in reg 0
|
||||
|
||||
// opcode = 3 beqz, rs = 1, target = 1
|
||||
3 : InstOut = 'b0011001001; // beqz reg1 to absolute address 1
|
||||
|
||||
// opcode = 15 halt
|
||||
4 : InstOut = '1; // equiv to 10'b1111111111 or 'b1111111111 halt
|
||||
// (default case already covered by opening statement)
|
||||
endcase
|
||||
end
|
||||
*/
|
||||
|
||||
endmodule
|
46
RTL/RegFile.sv
Normal file
46
RTL/RegFile.sv
Normal file
@ -0,0 +1,46 @@
|
||||
// Create Date: 2019.01.25
|
||||
// Design Name: CSE141L
|
||||
// Module Name: reg_file
|
||||
// Revision: 2022.05.04
|
||||
// Additional Comments: allows preloading with user constants
|
||||
// This version is fully synthesizable and highly recommended.
|
||||
|
||||
/* parameters are compile time directives
|
||||
this can be an any-width, any-depth reg_file: just override the params!
|
||||
*/
|
||||
module RegFile #(parameter W=8, D=4)( // W = data path width (leave at 8); D = address pointer width
|
||||
input Clk,
|
||||
Reset, // note use of Reset port
|
||||
WriteEn,
|
||||
input [D-1:0] RaddrA, // address pointers
|
||||
RaddrB,
|
||||
Waddr,
|
||||
input [W-1:0] DataIn,
|
||||
output [W-1:0] DataOutA, // showing two different ways to handle DataOutX, for
|
||||
output logic [W-1:0] DataOutB // pedagogic reasons only
|
||||
);
|
||||
|
||||
// W bits wide [W-1:0] and 2**4 registers deep
|
||||
logic [W-1:0] Registers[2**D]; // or just registers[16] if we know D=4 always
|
||||
|
||||
// combinational reads
|
||||
/* can use always_comb in place of assign
|
||||
difference: assign is limited to one line of code, so
|
||||
always_comb is much more versatile
|
||||
*/
|
||||
assign DataOutA = Registers[RaddrA]; // assign & always_comb do the same thing here
|
||||
always_comb DataOutB = Registers[RaddrB]; // can read from addr 0, just like ARM
|
||||
|
||||
// sequential (clocked) writes
|
||||
always_ff @ (posedge Clk)
|
||||
if (Reset) begin
|
||||
for(int i=0; i<2**D; i++)
|
||||
Registers[i] <= 'h0;
|
||||
// we can override this universal clear command with desired initialization values
|
||||
Registers[0] <= 'd30; // loads 30 (=0x1E) into RegFile address 0
|
||||
Registers[2] <= 'b101; // loads 00000101 into RegFile address 2
|
||||
end
|
||||
else if (WriteEn) // works just like data_memory writes
|
||||
Registers[Waddr] <= DataIn;
|
||||
|
||||
endmodule
|
151
RTL/TopLevel.sv
Normal file
151
RTL/TopLevel.sv
Normal file
@ -0,0 +1,151 @@
|
||||
// Revision Date: 2022.05.05
|
||||
// Design Name: BasicProcessor
|
||||
// Module Name: TopLevel
|
||||
// CSE141L -- partial only
|
||||
module TopLevel( // you will have the same 3 ports
|
||||
input Reset, // init/reset, active high
|
||||
Start, // start next program
|
||||
Clk, // clock -- posedge used inside design
|
||||
output logic Ack // done flag from DUT
|
||||
);
|
||||
|
||||
// program counter / instructon fetch connections
|
||||
wire [ 1:0] TargSel; // for branch LUT select
|
||||
wire [ 9:0] PgmCtr, // program counter (wider if you wish)
|
||||
PCTarg;
|
||||
wire [ 8:0] Instruction; // our 9-bit opcode
|
||||
|
||||
// data path connections -- everything is 8 bits wide
|
||||
wire [ 7:0] ReadA, ReadB; // reg_file outputs
|
||||
wire [ 7:0] InA, InB, // ALU operand inputs
|
||||
ALU_out; // ALU result
|
||||
wire [ 7:0] RegWriteValue, // data in to reg file
|
||||
MemWriteValue, // data in to data_memory
|
||||
MemReadValue, // data out from data_memory
|
||||
DatMemAddr , //
|
||||
Immediate; //
|
||||
|
||||
// control wires
|
||||
wire Imm, // inserts Immediate into ALU
|
||||
MemWrite, // data_memory write enable
|
||||
RegWrEn, // reg_file write enable
|
||||
Zero, // ALU output = 0 flag
|
||||
Jump, // to program counter: jump
|
||||
BranchEn; // to program counter: branch enable
|
||||
// ALU status register, analogous to ARM
|
||||
logic PFq, // delayed/stored parity bit from ALU
|
||||
SCq, // delayed/stored shift-carry out flag
|
||||
Zq; // delayed/stored null out flag from ALU
|
||||
logic[15:0] CycleCt; // standalone; NOT PC!
|
||||
|
||||
// Fetch stage = Program Counter + Instruction ROM
|
||||
// "InstFetch" = PC register + branch/increment logic
|
||||
InstFetch IF1 ( // this is the program counter module
|
||||
.Reset (Reset ) , // reset to 0
|
||||
.Start (Start ) , // SystemVerilog shorthand for .grape(grape) is just .grape
|
||||
.Clk (Clk ) , // here, (Clk) is required in Verilog, optional in SystemVerilog
|
||||
.BranchAbs (Jump ) , // jump enable
|
||||
.BranchRelEn (BranchEn) , // branch enable
|
||||
.ALU_flag (Zero ) , //
|
||||
.Target (PCTarg ) , // "where to?" or "how far?" during a jump or branch
|
||||
.ProgCtr (PgmCtr ) // program count = index to instruction memory
|
||||
);
|
||||
|
||||
LUT LUT1(.Addr (TargSel ) ,
|
||||
.Target (PCTarg )
|
||||
);
|
||||
|
||||
// instruction ROM -- holds the machine code selected by program counter
|
||||
// don't change W(9); increase A(10) if your machine code exceeds 1K lines
|
||||
InstROM #(.W(9),.A(10)) IR1(
|
||||
.InstAddress (PgmCtr ) ,
|
||||
.InstOut (Instruction)
|
||||
);
|
||||
|
||||
// Decode stage = Control Decoder + Reg_file
|
||||
// Control decoder
|
||||
Ctrl Ctrl1 (
|
||||
.Instruction (Instruction) , // from instr_ROM
|
||||
// outputs
|
||||
.Jump (Jump ) , // to PC to handle jump/branch instructions
|
||||
.BranchEn (BranchEn ) , // to PC
|
||||
.RegWrEn (RegWrEn ) , // register file write enable
|
||||
.MemWrEn (MemWrite ) , // data memory write enable
|
||||
.LoadInst (LoadInst ) , // selects memory vs ALU output as data input to reg_file
|
||||
.PCTarg (TargSel ) ,
|
||||
.tapSel (tapSel ) ,
|
||||
.DatMemAddr (DatMemAddr ) ,
|
||||
.Ack (Ack ) // "done" flag
|
||||
);
|
||||
|
||||
// reg file -- don't change W(8); may increase to D(4)
|
||||
// I arbitrarily mapped to Instructon fields [5:3] and [2:0]
|
||||
// you do not have to do this!!!
|
||||
RegFile #(.W(8),.D(3)) RF1 ( // D(3) makes this 8 elements deep
|
||||
.Clk ,
|
||||
.WriteEn (RegWrEn) ,
|
||||
.RaddrA (Instruction[5:3]), // see hint below
|
||||
.RaddrB (Instruction[2:0]), // or perhaps (Instruction[2:0]+1);
|
||||
// by choosing Waddr = RaddrA, I am doing write-in-place operations
|
||||
// such as A = A+B, as opposed to C = A+B
|
||||
.Waddr (Instruction[5:3]), //3'b0 // mux above
|
||||
.DataIn (RegWriteValue) ,
|
||||
.DataOutA (ReadA ) ,
|
||||
.DataOutB (ReadB )
|
||||
);
|
||||
// a trick you MAY find useful:
|
||||
// use 2 instructon bits to select 2 adjacent addresses in RegFile
|
||||
// .RaddA ({Instruction[1:0],1'b0}),
|
||||
// .RaddB ({Instruction[1:0],1'b1}),
|
||||
|
||||
// logic[3:0] Tap_ptr; // tap pattern selector
|
||||
// sample LUT from a different program
|
||||
logic[7:0] Immediate; // tap pattern itself
|
||||
Immediate_LUT IL1(.addr(Instruction[5:3]), .datOut(Immediate));
|
||||
|
||||
assign InA = Imm? Immediate : ReadA; // connect RF out to ALU in
|
||||
assign InB = ReadB; // interject switch/mux if needed/desired
|
||||
assign MemWriteValue = ReadB;
|
||||
// controlled by Ctrl1 -- must be high for load from data_mem; otherwise usually low
|
||||
assign RegWriteValue = LoadInst? MemReadValue : ALU_out; // 2:1 switch into reg_file
|
||||
ALU ALU1 (
|
||||
.InputA (InA), //(ReadA),
|
||||
.InputB (InB),
|
||||
.SC_in (PFq), // registered version of output flag
|
||||
.OP (Instruction[8:6]),
|
||||
.Out (ALU_out),//regWriteValue),
|
||||
.PF (PF), // output parity status flag
|
||||
.Zero (Zero), // null output status flag
|
||||
.SC_out (SCout), // shift/carry output flag
|
||||
); // other flags as desired?
|
||||
|
||||
// equiv. to ARM ALU status register
|
||||
// store flags for next clock cycle
|
||||
always @(posedge Clk) begin
|
||||
SCq <= SCout;
|
||||
PFq <= PF;
|
||||
Zq <= Zero;
|
||||
end
|
||||
|
||||
DataMem DM1(
|
||||
.DataAddress (ReadA) ,
|
||||
.WriteEn (MemWrite),
|
||||
.DataIn (MemWriteValue),
|
||||
.DataOut (MemReadValue) ,
|
||||
.Clk (Clk) ,
|
||||
.Reset (Reset)
|
||||
);
|
||||
|
||||
//always_comb chosen_bit = MemReadValue[5:2];
|
||||
|
||||
/* count number of instructions executed
|
||||
not part of main design, potentially useful
|
||||
This one halts when Ack is high
|
||||
*/
|
||||
always_ff @(posedge Clk)
|
||||
if (Reset == 1) // if(start)
|
||||
CycleCt <= 0;
|
||||
else if(Ack == 0) // if(!halt)
|
||||
CycleCt <= CycleCt+16'b1;
|
||||
|
||||
endmodule
|
78
RTL/TopLevelLab2.sv
Normal file
78
RTL/TopLevelLab2.sv
Normal file
@ -0,0 +1,78 @@
|
||||
// team name quarter
|
||||
module TopLevel( // you will have the same 3 ports
|
||||
input Reset, // init/reset, active high
|
||||
Start, // start next program
|
||||
Clk, // clock -- posedge used inside design
|
||||
output logic Ack // done flag from DUT
|
||||
);
|
||||
|
||||
|
||||
InstFetch IF1 ( // this is the program counter module
|
||||
.Reset (Reset ) , // reset to 0
|
||||
.Start (Start ) , // SystemVerilog shorthand for .grape(grape) is just .grape
|
||||
.Clk (Clk ) , // here, (Clk) is required in Verilog, optional in SystemVerilog
|
||||
.BranchAbs (Jump ) , // jump enable
|
||||
.BranchRelEn (BranchEn) , // branch enable
|
||||
.ALU_flag (Zero ) , //
|
||||
.Target (PCTarg ) , // "where to?" or "how far?" during a jump or branch
|
||||
.ProgCtr (PgmCtr ) // program count = index to instruction memory
|
||||
);
|
||||
|
||||
LUT LUT1(.Addr (TargSel ) ,
|
||||
.Target (PCTarg )
|
||||
);
|
||||
|
||||
|
||||
// instruction ROM -- holds the machine code pointed to by program counter
|
||||
InstROM #(.W(9),.A(10)) IR1(
|
||||
.InstAddress (PgmCtr ) ,
|
||||
.InstOut (Instruction)
|
||||
);
|
||||
|
||||
// in place c = a+c ADD R0 R1 R0
|
||||
// reg file
|
||||
RegFile #(.W(8),.D(3)) RF1 ( // D(3) makes this 8 elements deep
|
||||
.Clk ,
|
||||
.WriteEn (RegWrEn) ,
|
||||
.RaddrA (Instruction[5:3]), //3'b0 //concatenate with 0 to give us 4 bits
|
||||
.RaddrB (Instruction[2:0]), // (Instruction[2:0]+1);
|
||||
.Waddr (Instruction[5:3]), //3'b0 // mux above
|
||||
.DataIn (RegWriteValue) ,
|
||||
// outputs
|
||||
.DataOutA (ReadA ) ,
|
||||
.DataOutB (ReadB )
|
||||
);
|
||||
|
||||
ALU ALU1 (
|
||||
.InputA (InA),
|
||||
.InputB (InB),
|
||||
.SC_in (PFq),
|
||||
.OP (Instruction[8:6]),
|
||||
// outputs
|
||||
.Out (ALU_out),//regWriteValue),
|
||||
.PF (PF),
|
||||
.Zero // status flag; may have others, if desired
|
||||
);
|
||||
|
||||
always @(posedge Clk)
|
||||
PFq <= PF;
|
||||
|
||||
|
||||
DataMem DM1(
|
||||
// inputs
|
||||
.Clk (Clk) ,
|
||||
.Reset (Reset) ,
|
||||
.DataAddress (ReadA) ,
|
||||
.WriteEn (MemWrite),
|
||||
.DataIn (MemWriteValue),
|
||||
// outputs
|
||||
.DataOut (MemReadValue)
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
endmodule
|
71
RTL/TopLevel_tb.sv
Normal file
71
RTL/TopLevel_tb.sv
Normal file
@ -0,0 +1,71 @@
|
||||
// Create Date: 2017.01.25
|
||||
// Design Name: TopLevel Test Bench
|
||||
// Module Name: TopLevel_tb.v
|
||||
// CSE141L
|
||||
// This is NOT synthesizable; use for logic simulation only
|
||||
// Verilog Test Fixture created for module: TopLevel
|
||||
|
||||
module TopLevel_tb; // Lab 17
|
||||
|
||||
// To DUT Inputs
|
||||
bit Init = 'b1,
|
||||
Req, // start
|
||||
Clk; // logic Clk; // inits to 1'bx
|
||||
// logic Clk = 1'b0;
|
||||
|
||||
// From DUT Outputs
|
||||
wire Ack; // done flag
|
||||
|
||||
// Instantiate the Device Under Test (DUT)
|
||||
TopLevel DUT (
|
||||
.Reset (Init) ,
|
||||
.Start (Req ) ,
|
||||
.Clk (Clk ) ,
|
||||
.Ack (Ack )
|
||||
);
|
||||
|
||||
initial begin
|
||||
#10ns Init = 'b0;
|
||||
#10ns Req = 'b1;
|
||||
// Initialize DUT's data memory
|
||||
#10ns for(int i=0; i<256; i++) begin
|
||||
DUT.DM1.Core[i] = 8'h0; // clear data_mem
|
||||
end
|
||||
DUT.DM1.Core[1] = 8'h03; // MSW of operand A
|
||||
DUT.DM1.Core[2] = 8'hff;
|
||||
DUT.DM1.Core[3] = 8'hff; // MSW of operand B
|
||||
DUT.DM1.Core[4] = 8'hfb;
|
||||
DUT.DM1.Core[128] = 8'h00; // preload constants
|
||||
// ...
|
||||
DUT.DM1.Core[255] = 8'h00;
|
||||
// students may also pre_load desired constants into DM
|
||||
// Initialize DUT's register file
|
||||
for(int j=0; j<16; j++)
|
||||
DUT.RF1.Registers[j] = 8'b0; // default -- clear it
|
||||
// students may pre-load desired constants into the reg_file
|
||||
// $readmemb("machine_code.txt",inst);
|
||||
// for(int k=0; k<1024; k++)
|
||||
// DUT.IR1.inst_rom[k] = inst[k];
|
||||
|
||||
|
||||
// launch prodvgram in DUT
|
||||
#10ns Req = 0;
|
||||
// Wait for done flag, then display results
|
||||
wait (Ack);
|
||||
#10ns $displayh(DUT.DM1.Core[5],
|
||||
DUT.DM1.Core[6],"_",
|
||||
DUT.DM1.Core[7],
|
||||
DUT.DM1.Core[8]);
|
||||
// $display("instruction = %d %t",DUT.PC,$time);
|
||||
#10ns $stop; // $finish;
|
||||
end
|
||||
|
||||
always begin // clock period = 10 Verilog time units
|
||||
#5ns Clk = 'b1;
|
||||
#5ns Clk = 'b0;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
// always #5ns Clk = ~Clk;
|
34
RTL/prog_ctr2.sv
Normal file
34
RTL/prog_ctr2.sv
Normal file
@ -0,0 +1,34 @@
|
||||
// Design Name: basic_proc
|
||||
// Module Name: InstFetch
|
||||
// Project Name: CSE141L
|
||||
// Description: instruction fetch (pgm ctr) for processor
|
||||
//
|
||||
// Revision: 2019.01.27
|
||||
//
|
||||
module InstFetch(
|
||||
input Reset, // reset, init, etc. -- force PC to 0
|
||||
Start, // begin next program in series (request issued by test bench)
|
||||
Clk, // PC can change on pos. edges only
|
||||
BranchAbs, // jump unconditionally to Target value
|
||||
ALU_flag, // flag from ALU, e.g. Zero, Carry, Overflow, Negative (from ARM)
|
||||
input [9:0] Target, // jump ... "how high?"
|
||||
output logic [9:0] ProgCtr // the program counter register itself
|
||||
);
|
||||
|
||||
// program counter can clear to 0, increment, or jump
|
||||
always_ff @(posedge Clk) // or just always; always_ff is a linting construct
|
||||
if(Reset)
|
||||
ProgCtr <= 0; // for first program; want different value for 2nd or 3rd
|
||||
else if(Start) // hold while start asserted; commence when released
|
||||
ProgCtr <= 0;//ProgCtr;
|
||||
else if(BranchAbs) // unconditional absolute jump
|
||||
ProgCtr <= Target; // how would you make it conditional and/or relative?
|
||||
else
|
||||
ProgCtr <= ProgCtr+'b1; // default increment (no need for ARM/MIPS +4 -- why?)
|
||||
|
||||
endmodule
|
||||
|
||||
/* Note about Start: if your programs are spread out, with a gap in your machine code listing, you will want
|
||||
to make Start cause an appropriate jump. If your programs are packed sequentially, such that program 2 begins
|
||||
right after Program 1 ends, then you won't need to do anything special here.
|
||||
*/
|
Reference in New Issue
Block a user