populate better starting rtl code

This commit is contained in:
Arthur Lu 2022-08-13 15:34:01 -07:00
parent 31b077c5f2
commit be156765f3
14 changed files with 374 additions and 496 deletions

View File

@ -1,55 +1,46 @@
// Create Date: 2018.10.15
// Module Name: ALU // Module Name: ALU
// Project Name: CSE141L // Project Name: CSE141L
// //
// Revision 2022.04.30
// Additional Comments: // Additional Comments:
// combinational (unclocked) ALU // combinational (unclocked) ALU
import definitions::*; // includes package "definitions"
// includes package "Definitions"
// be sure to adjust "Definitions" to match your final set of ALU opcodes
import Definitions::*;
module ALU #(parameter W=8)( module ALU #(parameter W=8)(
input [W-1:0] InputA, // data inputs input [W-1:0] InputA, // data inputs
InputB, InputB,
input op_mne OP, // ALU opcode, part of microcode
input SC_in, // shift or carry in input SC_in, // shift or carry in
input [ 2:0] OP, // ALU opcode, part of microcode output logic [W-1:0] Out, // data output
output logic [W-1:0] Out, // or: output reg [7:0] OUT, output logic Zero, // output = zero flag !(Out)
output logic PF, // reduction parity Parity, // outparity flag ^(Out)
output logic Zero, // output = zero flag Odd, // output odd flag (Out[0])
output logic SC_out // shift or carry out SC_out // shift or carry out
// you may provide additional status flags as inputs, if desired // you may provide additional status flags, if desired
// comment out or delete any you don't need
); );
op_mne op_mnemonic; // type enum: used for convenient waveform viewing
// InputA = current LFSR state
// InputB = tap_pattern
always_comb begin always_comb begin
Out = 0; // No Op = default
SC_out = 0; // No Op = default // add desired ALU ops, delete or comment out any you don't need
Out = 8'b0; // don't need NOOP? Out = 8'bx
SC_out = 1'b0; // will flag any illegal opcodes
case(OP) case(OP)
kADD : {SC_out,Out} = {1'b0,InputA} + InputB; // add ADD : {SC_out,Out} = InputA + InputB + SC_in; // unsigned add with carry-in and carry-out
kLSH : {SC_out,Out} = {InputA[7:0],SC_in}; // shift left, fill in with SC_in LSH : {SC_out,Out} = {InputA[7:0],SC_in}; // shift left, fill in with SC_in, fill SC_out with InputA[7]
// for logical left shift, tie SC_in = 0 // for logical left shift, tie SC_in = 0
kRSH : {Out,SC_out} = {SC_in, InputA[7:0]}; // shift right RSH : {Out,SC_out} = {SC_in, InputA[7:0]}; // shift right
kXOR : Out = InputA ^ InputB; // exclusive OR XOR : Out = InputA ^ InputB; // bitwise exclusive OR
kAND : Out = InputA & InputB; // bitwise AND AND : Out = InputA & InputB; // bitwise AND
SUB : {SC_out,Out} = InputA + (~InputB) + 1; // InputA - InputB;
CLR : {SC_out,Out} = 'b0;
endcase endcase
end end
always_comb // assign Zero = !Out; assign Zero = ~|Out; // reduction NOR Zero = !Out;
case(Out) assign Parity = ^Out; // reduction XOR
'b0 : Zero = 1'b1; assign Odd = Out[0]; // odd/even -- just the value of the LSB
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 endmodule
/* InputA=10101010 SC_in = 1
kLSH Out = 01010101
*/

View File

@ -1,25 +1,53 @@
// CSE141L // CSE141L
import definitions::*; import Definitions::*;
// control decoder (combinational, not clocked) // control decoder (combinational, not clocked)
// inputs from instrROM, ALU flags // inputs from instrROM, ALU flags
// outputs to program_counter (fetch unit) // outputs to program_counter (fetch unit)
module Ctrl ( module Ctrl (
input[ 8:0] Instruction, // machine code input[ 8:0] Instruction, // machine code
input[ 7:0] DatMemAddr, input[ 7:0] DatMemAddr,
output logic Jump , output logic Branch ,
BranchEn , BranchEn ,
RegWrEn , // write to reg_file (common) RegWrEn , // write to reg_file (common)
MemWrEn , // write to mem (store only) MemWrEn , // write to mem (store only)
LoadInst , // mem or ALU to reg_file ? LoadInst , // mem or ALU to reg_file ?
PCTarg , TapSel ,
tapSel , Ack , // "done w/ program"
Ack // "done w/ program" output logic[1:0] PCTarg,
// output logic[2:0] ALU_inst // output logic[2:0] ALU_inst
); );
/* ***** All numerical values are completely arbitrary and for illustration only ***** /* ***** All numerical values are completely arbitrary and for illustration only *****
*/ */
// alternative -- case format
always_comb begin
// list the defaults here
Branch = 'b0;
BranchEn = 'b0;
RegWrEn = 'b1;
MemWrEn = 'b0;
LoadInst = 'b0;
TapSel ' 'b0; //
PCTarg = 'b0; // branch "where to?"
case(Instruction[8:6]) // list just the exceptions
3'b000: begin
MemWrEn = 'b1; // store, maybe
RegWrEn = 'b0;
end
3'b001: LoadInst = 'b1; // load
3'b010: begin end
3'b011: begin end
3'b100: begin end
3'b101: begin end
3'b110: begin end
// no default case needed -- covered before "case"
endcase
end
assign Ack = ProgCtr == 971;
// alternative Ack = Instruction == 'b111_000_111
// ALU commands // ALU commands
//assign ALU_inst = Instruction[2:0]; //assign ALU_inst = Instruction[2:0];
@ -35,12 +63,12 @@ assign LoadInst = Instruction[8:6]==3'b110; // calls out load specially
assign tapSel = LoadInst && DatMemAddr=='d62; assign tapSel = LoadInst && DatMemAddr=='d62;
// jump enable command to program counter / instruction fetch module on right shift command // jump enable command to program counter / instruction fetch module on right shift command
// equiv to simply: assign Jump = Instruction[2:0] == kRSH; // equiv to simply: assign Jump = Instruction[2:0] == RSH;
always_comb always_comb
if(Instruction[2:0] == kRSH) if(Instruction[2:0] == RSH)
Jump = 1; Branch = 1;
else else
Jump = 0; Branch = 0;
// branch every time instruction = 9'b?????1111; // branch every time instruction = 9'b?????1111;
assign BranchEn = &Instruction[3:0]; assign BranchEn = &Instruction[3:0];
@ -50,7 +78,7 @@ assign BranchEn = &Instruction[3:0];
assign PCTarg = Instruction[3:2]; assign PCTarg = Instruction[3:2];
// reserve instruction = 9'b111111111; for Ack // reserve instruction = 9'b111111111; for Ack
assign Ack = &Instruction; assign Ack = &Instruction; // = ProgCtr == 385;
endmodule endmodule

View File

@ -1,39 +1,50 @@
// Create Date: 2017.01.25 // Create Date: 2017.01.25
// Revision: 2022.05.04 made data width parametric // Design Name: CSE141L
// Design Name:
// Module Name: DataMem // Module Name: DataMem
// single address pointer for both read and write // Last Update: 2022.01.13
// CSE141L
module DataMem #(parameter W=8, D=8)( // Memory can only read (LDR) or write (STR) on each Clk cycle, so there is a single
// address pointer for both read and write operations.
//
// Parameters:
// - A: Address Width. This controls the number of entries in memory
// - W: Data Width. This controls the size of each entry in memory
// This memory can hold `(2**A) * W` bits of data.
//
// WI22 is a 256-entry single-byte (8 bit) data memory.
module DataMem #(parameter W=8, A=8) ( // do not change W=8
input Clk, input Clk,
Reset, // again, note use of Reset for preloads Reset, // initialization
WriteEn, WriteEn, // write enable
input [D-1:0] DataAddress, // 8-bit-wide pointer to 256-deep memory input [A-1:0] DataAddress, // A-bit-wide pointer to 256-deep memory
input [W-1:0] DataIn, // 8-bit-wide data path, also input [W-1:0] DataIn, // W-bit-wide data path, also
output logic[W-1:0] DataOut); output logic[W-1:0] DataOut
);
logic [W-1:0] Core[2**D]; // 8x256 two-dimensional array -- the memory itself // 8x256 two-dimensional array -- the memory itself
logic [W-1:0] core[2**A];
always_comb // reads are combinational // reads are combinational
DataOut = Core[DataAddress]; always_comb
DataOut = core[DataAddress];
/* optional way to plant constants into DataMem at startup // writes are sequential
initial always_ff @ (posedge Clk)
$readmemh("dataram_init.list", Core); /*
*/ // Reset response is needed only for initialization.
always_ff @ (posedge Clk) // writes are sequential // (see inital $readmemh above for another choice)
/*( 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, // If you do not need to preload your data memory with any constants,
and go straight to if(WriteEn) ... // you may omit the `if (Reset) ... else` and go straight to `if(WriteEn)`
*/ */
if(Reset) begin if(Reset) begin
// you may initialize your memory w/ constants, if you wish // Preload desired constants into data_mem[128:255]
for(int i=128;i<256;i++) core[128] <= 'b1;
Core[ i] <= 0; core[129] <= 'hff;
Core[ 16] <= 254; // overrides the 0 ***sample only*** core[130] <= 'd64;
Core[244] <= 5; // likewise
end end
else if(WriteEn) else if(WriteEn) // store
Core[DataAddress] <= DataIn; // Do the actual writes
core[DataAddress] <= DataIn;
endmodule endmodule

View File

@ -1,24 +1,16 @@
//This file defines the parameters used in the alu //This file defines the parameters used in the alu
// CSE141L // CSE141L
// Rev. 2020.5.27 // Rev. 2022.5.27
// import package into each module that needs it // import package into each module that needs it
// packages very useful for declaring global variables // packages very useful for declaring global variables
package definitions; // need > 8 instructions?
// typedef enum logic[3:0] and expand the list of enums
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 // enum names will appear in timing diagram
// ADD = 3'b000; LSH = 3'b001; etc. 3'b111 is undefined here
typedef enum logic[2:0] { typedef enum logic[2:0] {
ADD, LSH, BSH, XOR, ADD, LSH, RSH, XOR,
AND, SUB, CLR } op_mne; 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 endpackage // definitions

26
RTL/Immediate_LUT.sv Normal file
View File

@ -0,0 +1,26 @@
/* CSE141L
possible lookup table for PC target
leverage a few-bit pointer to a wider number
Lookup table acts like a function: here Target = f(Addr);
in general, Output = f(Input); lots of potential applications
*/
module Immediate_LUT #(PC_width = 10)(
input [ 2:0] addr,
output logic[PC_width-1:0] datOut
);
always_comb begin
datOut = 'h001; // default to 1 (or PC+1 for relative)
case(addr)
2'b00: datOut = 'hfc; // -4, i.e., move back 16 lines of machine code
2'b01: datOut = 'h03;
2'b10: datOut = 'h07;
endcase
end
endmodule
// 3fc = 1111111100 -4
// PC 0000001000 8
// 0000000100 4

View File

@ -3,13 +3,13 @@
// Project Name: CSE141L // Project Name: CSE141L
// Description: instruction fetch (pgm ctr) for processor // Description: instruction fetch (pgm ctr) for processor
// //
// Revision: 2019.01.27 // Revision: 2021.11.27
// Suggested ProgCtr width 10 t0 12 bits // Suggested ProgCtr width 10 t0 12 bits
module InstFetch #(parameter T=10)( // PC width -- up to 32, if you like module InstFetch #(parameter T=10)( // PC width -- up to 32, if you like
input Reset, // reset, init, etc. -- force PC to 0 input Reset, // reset, init, etc. -- force PC to 0
Start, // begin next program in series (request issued by test bench) Start, // begin next program in series (request issued by test bench)
Clk, // PC can change on pos. edges only Clk, // PC can change on pos. edges only
BranchAbs, // jump unconditionally to Target value BranchAbs, // jump conditionally to Target value
BranchRelEn, // jump conditionally to Target + PC BranchRelEn, // jump conditionally to Target + PC
ALU_flag, // flag from ALU, e.g. Zero, Carry, Overflow, Negative (from ARM) ALU_flag, // flag from ALU, e.g. Zero, Carry, Overflow, Negative (from ARM)
input [T-1:0] Target, // jump ... "how high?" input [T-1:0] Target, // jump ... "how high?"
@ -19,13 +19,14 @@ module InstFetch #(parameter T=10)( // PC width -- up to 32, if you like
// you may wish to use either absolute or relative branching // you may wish to use either absolute or relative branching
// you may use both, but you will need appropriate control bits // you may use both, but you will need appropriate control bits
// branch/jump is how we handle gosub and return to main // branch/jump is how we handle gosub and return to main
// program counter can clear to 0, increment, or jump // program counter can clear to 0, increment, or branch
// for unconditional branching, "ALU_flag" input should be driven by 1
always_ff @(posedge Clk) // or just always; always_ff is a linting construct always_ff @(posedge Clk) // or just always; always_ff is a linting construct
if(Reset) if(Reset)
ProgCtr <= 0; // for first program; want different value for 2nd or 3rd ProgCtr <= 0; // for first program; want different value for 2nd or 3rd
else if(Start) // hold while start asserted; commence when released else if(Start) // hold while start asserted; commence when released
ProgCtr <= 0; //or <= ProgCtr; holds at starting value ProgCtr <= 0; //or <= ProgCtr; holds at starting value
else if(BranchAbs) // unconditional absolute jump else if(BranchAbs && ALU_flag // unconditional absolute jump
ProgCtr <= Target; // how would you make it conditional and/or relative? ProgCtr <= Target; // how would you make it conditional and/or relative?
else if(BranchRelEn && ALU_flag) // conditional relative jump else if(BranchRelEn && ALU_flag) // conditional relative jump
ProgCtr <= Target + ProgCtr; // how would you make it unconditional and/or absolute ProgCtr <= Target + ProgCtr; // how would you make it unconditional and/or absolute

View File

@ -1,32 +0,0 @@
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

View File

@ -6,14 +6,18 @@
// Description: Verilog module -- instruction ROM template // Description: Verilog module -- instruction ROM template
// preprogrammed with instruction values (see case statement) // preprogrammed with instruction values (see case statement)
// //
// Revision: 2020.08.08 // Revision: 2021.08.08
// //
// A = program counter width
// W = machine code width -- do not change for CSE141L
module InstROM #(parameter A=12, W=9) ( module InstROM #(parameter A=12, W=9) (
input [A-1:0] InstAddress, input [A-1:0] InstAddress,
output logic[W-1:0] InstOut); output logic[W-1:0] InstOut);
// (usually recommended) expression // (usually recommended) expression
// need $readmemh or $readmemb to initialize all of the elements // need $readmemh or $readmemb to initialize all of the elements
// This version will work best with assemblers, but you can try the alternative starting line 33
// This version is also by far the easiest if you have a long program scrip.
// declare 2-dimensional array, W bits wide, 2**A words deep // declare 2-dimensional array, W bits wide, 2**A words deep
logic[W-1:0] inst_rom[2**A]; logic[W-1:0] inst_rom[2**A];
always_comb InstOut = inst_rom[InstAddress]; always_comb InstOut = inst_rom[InstAddress];

View File

@ -1,151 +0,0 @@
// 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

View File

@ -1,78 +0,0 @@
// 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

View File

@ -1,71 +0,0 @@
// 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;

35
RTL/dummy_DUT.sv Normal file
View File

@ -0,0 +1,35 @@
// skeletal starter code top level of your DUT
module top_level(
input clk, init, req,
output logic ack);
logic mem_wen;
logic[7:0] mem_addr,
mem_in,
mem_out;
logic[11:0] pctr; // temporary program counter
// populate with program counter, instruction ROM, reg_file (if used),
// accumulator (if used),
DataMem DM(.Clk (clk),
.Reset (init),
.WriteEn (mem_wen),
.DataAddress (mem_addr),
.DataIn (mem_in),
.DataOut (mem_out));
// temporary circuit to provide ack (done) flag to test bench
// remove or greatly increase the match value once you get a
// proper ack
always @(posedge clk)
if(init || req)
pctr <= 'h0;
else
pctr <= pctr+'h1;
assign ack = pctr=='h256; // pctr needed to trigger ack (arbitary time)
endmodule

View File

@ -1,34 +0,0 @@
// 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.
*/

156
RTL/program1_tb1.sv Normal file
View File

@ -0,0 +1,156 @@
// program1_tb
// testbench for programmable message encryption (Program #1)
// CSE141L
// runs program 1 (encrypt a message)
module encrypt_tb () ;
// DUT interface -- four one-bit wires, three to DUT, one from
bit clk , // advances simulation step-by-step
init = 1'b1 , // init (reset) command to DUT
start = 1'b1 ; // request (start program) command to DUT
wire done ; // acknowledge (program done) flag returned by DUT
// test bench parameters
logic[7:0] pre_length ; // number of space char. before message itself, sent to data_mem[61]
logic[7:0] message1[54] , // original raw message, in binary, up to 54 characters in length
msg_padded1[64], // original message, plus pre- and post-padding w/ ASCII spaces
msg_crypto1[64]; // encrypted message returned by DUT
logic[7:0] lfsr_ptrn , // choses one of 9 maximal length 7-tap shift reg. patterns
LFSR_ptrn[9] , // the 9 candidate maximal-length 7-bit LFSR tap ptrns themselves
lfsr1[64] , // states of program 1 encrypting LFSR
LFSR_init ; // one of 127 possible NONZERO starting states for encrypting LFSR
int score ; // count of correctly encyrpted characters
// our original American Standard Code for Information Interchange message follows
// note in practice your design should be able to handle ANY ASCII string that is
// restricted to characters between space (0x20) and script f (0x9f) and shorter than
// 55 characters in length
string str1 = "Mr. Watson, come here. I want to see you."; // sample program 1 input
// string str1 = " Knowledge comes, but wisdom lingers. "; // alternative inputs
// string str1 = " 01234546789abcdefghijklmnopqrstuvwxyz. "; // (make up your own,
// string str1 = " f A joke is a very serious thing."; // as well)
// string str1 = " Ajoke "; //
// string str1 = "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@";
// string str1 = " Knowledge comes, but wisdom lingers. "; //
// displayed encrypted string will go here:
string str_enc1[64]; // program 1 desired output will go here
int strlen; // length of incoming message string itself, before padding
logic[3:0] pt_no; // select LFSR pattern, index value 0 through 8
int file_no; // output file tag (set to 1 for write to console/transcript)
// the 9 possible 7-tap maximal-length feedback tap patterns from which to choose
assign LFSR_ptrn[0] = 8'h60; // (0)110_0000
assign LFSR_ptrn[1] = 8'h48;
assign LFSR_ptrn[2] = 8'h78;
assign LFSR_ptrn[3] = 8'h72;
assign LFSR_ptrn[4] = 8'h6A;
assign LFSR_ptrn[5] = 8'h69;
assign LFSR_ptrn[6] = 8'h5C;
assign LFSR_ptrn[7] = 8'h7E; // (0)111_1110
assign LFSR_ptrn[8] = 8'h7B;
always_comb begin
pt_no = 0;//$random; // or select a specific pattern ([0] and [1] are simplest to debug
if(pt_no>8) pt_no[3] = 0; // restrict pt_no to 0 through 8
lfsr_ptrn = LFSR_ptrn[pt_no]; // look up and engage the selected pattern; to data_mem[62]
end
// now select a starting LFSR state -- any nonzero value will do
always_comb begin
LFSR_init = 'b1;//$random>>2; // or set a specific value, such as 7'b1, for easier debug
if(!LFSR_init) LFSR_init = 7'b1; // prevents illegal starting state = 7'b0;
end
// set preamble length for the program run (always > 9 but < 26)
always_comb begin
pre_length = 10;//$random>>10 ; // number of space characters ahead of message; the >>10 changes the random value
if(pre_length < 10) pre_length = 10; // prevents pre_length < 10
else if(pre_length > 26) pre_length = 26;
end
// ***** instantiate your own top level design here *****
top_level dut(
.clk (clk ), // input: use your own port names, if different
.init (init ), // input: some prefer to call this ".reset"
.req (start), // input: launch program
.ack (done ) // output: "program run complete"
);
initial begin
//***** pre-load your instruction ROM here or inside itself *****
// $readmemb("encoder.bin", dut.instr_rom.rom);
// you may also pre-load desired constants, etc. into
// your data_mem here -- the upper addresses are reserved for your use
// dut.data_mem.DM[128]=8'hfe; //whatever constants you want
// to display to console, change this line to file_no = 'b1;
file_no = 'b1; // display to console instead of file
// file_no = $fopen("msg_enocder_out.txt","w"); // create your output file
#0ns strlen = str1.len; // length of string 1 (# characters between " ")
if(strlen>54) strlen = 54; // clip message at 54 characters
// program 1 -- precompute encrypted message
lfsr1[0] = LFSR_init; // any nonzero value (zero may be helpful for debug)
$fdisplay(file_no,"run encryption program; original message = ");
$fdisplay(file_no,"%s",str1); // print original message in transcript window
$fdisplay(file_no,"pt_no = %d",pt_no);
$fdisplay(file_no,"LFSR_ptrn = 0x%h, LFSR_init = 0x%h",lfsr_ptrn,LFSR_init);
// will subtract 0x20 from each preamble and each message character
for(int j=0; j<64; j++) // pre-fill message_padded with ASCII space characters
msg_padded1[j] = 8'h20; //
for(int l=0; l<strlen; l++) // overwrite up to 54 of these spaces w/ message itself
msg_padded1[pre_length+l] = str1[l]; // test bench does the -0x20 offset now
// compute and store the LFSR sequence
for (int ii=0;ii<63;ii++)
lfsr1[ii+1] = {(lfsr1[ii][5:0]),(^(lfsr1[ii]&lfsr_ptrn))};
// encrypt the message character-by-character, then prepend the parity
// testbench will change on falling clocks to avoid race conditions at rising clocks
for (int i=0; i<64; i++) begin
msg_crypto1[i] = ((msg_padded1[i]-32) ^ lfsr1[i]);
msg_crypto1[i][7] = 'b0;//^msg_crypto1[i][6:0]; // prepend parity bit into MSB
$fdisplay(file_no,"i=%d, msg_pad=0x%h, lfsr=%b msg_crypt w/ parity = 0x%h",
i,msg_padded1[i],lfsr1[i],msg_crypto1[i]);
// for display purposes only, add 8'h20 to avoid nonprintable characters (<8'h20)
str_enc1[i] = string'(msg_crypto1[i][6:0]+'h20);
end
$fdisplay(file_no,"encrypted string = ");
for(int jj=0; jj<64; jj++)
$fwrite(file_no,"%s",str_enc1[jj]);
$fdisplay(file_no,"\n");
// run encryption program
// ***** load operands into your data memory *****
// ***** use your instance name for data memory and its internal core *****
for(int m=0; m<61; m++)
dut.DM.core[m] = 8'h0; // pad memory w/ ASCII space characters
for(int m=0; m<strlen; m++)
dut.DM.core[m] = (str1[m]-8'h20); // overwrite/copy original string into device's data memory[0:strlen-1]
dut.DM.core[61] = pre_length; // number of bytes preceding message
dut.DM.core[62] = lfsr_ptrn; // LFSR feedback tap positions (9 permissible patterns)
dut.DM.core[63] = LFSR_init; // LFSR starting state (nonzero)
#20ns init = 1'b0; // suggestion: reset = 1 forces your program counter to 0
#10ns start = 1'b0; // request/start = 1 holds your program counter
#60ns; // wait for 6 clock cycles of nominal 10ns each
wait(done); // wait for DUT's ack/done flag to go high
// #2000ns;
#10ns $fdisplay(file_no,"");
$fdisplay(file_no,"program 1:");
// ***** reads your results and compares to test bench
// ***** use your instance name for data memory and its internal core *****
// the +'h20 restores the -32 bias, for better display visuals
for(int n=0; n<64; n++) begin
if(msg_crypto1[n]==dut.DM.core[n+64]) begin
$fdisplay(file_no,"%d bench msg: %s %h dut msg: %h",
n, msg_crypto1[n][6:0]+8'h20, msg_crypto1[n], dut.DM.core[n+64]);
score++;
end
else
$fdisplay(file_no,"%d bench msg: %s %h dut msg: %h OOPS!",
n, msg_crypto1[n][6:0]+8'h20, msg_crypto1[n], dut.DM.core[n+64]);
end
$fdisplay(file_no,"score = %d/64",score);
#20ns $fclose(file_no);
#20ns $stop;
end
always begin // continuous loop
#5ns clk = 1; // clock tick
#5ns clk = 0; // clock tock
end
endmodule