diff --git a/RTL/ALU.sv b/RTL/ALU.sv new file mode 100644 index 0000000..4a6f28b --- /dev/null +++ b/RTL/ALU.sv @@ -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 +*/ \ No newline at end of file diff --git a/RTL/Ctrl.sv b/RTL/Ctrl.sv new file mode 100644 index 0000000..8083863 --- /dev/null +++ b/RTL/Ctrl.sv @@ -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 + diff --git a/RTL/DataMem.sv b/RTL/DataMem.sv new file mode 100644 index 0000000..b02a6fa --- /dev/null +++ b/RTL/DataMem.sv @@ -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 diff --git a/RTL/Definitions.sv b/RTL/Definitions.sv new file mode 100644 index 0000000..83693f3 --- /dev/null +++ b/RTL/Definitions.sv @@ -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 diff --git a/RTL/InstFetch.sv b/RTL/InstFetch.sv new file mode 100644 index 0000000..95fdd2e --- /dev/null +++ b/RTL/InstFetch.sv @@ -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 + diff --git a/RTL/InstFetch_TB.sv b/RTL/InstFetch_TB.sv new file mode 100644 index 0000000..ad95c4f --- /dev/null +++ b/RTL/InstFetch_TB.sv @@ -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 \ No newline at end of file diff --git a/RTL/InstROM.sv b/RTL/InstROM.sv new file mode 100644 index 0000000..ce9934b --- /dev/null +++ b/RTL/InstROM.sv @@ -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 diff --git a/RTL/RegFile.sv b/RTL/RegFile.sv new file mode 100644 index 0000000..9586f08 --- /dev/null +++ b/RTL/RegFile.sv @@ -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 diff --git a/RTL/TopLevel.sv b/RTL/TopLevel.sv new file mode 100644 index 0000000..434327a --- /dev/null +++ b/RTL/TopLevel.sv @@ -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 \ No newline at end of file diff --git a/RTL/TopLevelLab2.sv b/RTL/TopLevelLab2.sv new file mode 100644 index 0000000..212e532 --- /dev/null +++ b/RTL/TopLevelLab2.sv @@ -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 \ No newline at end of file diff --git a/RTL/TopLevel_tb.sv b/RTL/TopLevel_tb.sv new file mode 100644 index 0000000..22a4671 --- /dev/null +++ b/RTL/TopLevel_tb.sv @@ -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; \ No newline at end of file diff --git a/RTL/prog_ctr2.sv b/RTL/prog_ctr2.sv new file mode 100644 index 0000000..c864636 --- /dev/null +++ b/RTL/prog_ctr2.sv @@ -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. +*/ \ No newline at end of file