From d3872a0fe1558205120a0ca15286a5573dc70403 Mon Sep 17 00:00:00 2001 From: Steve Hoover Date: Tue, 9 Feb 2021 18:22:48 -0500 Subject: [PATCH] Refinements to full_riscv.tlv and copied to lib/risc-v_shell_lib.tlv to serve as reference solution and library. --- full_riscv.tlv | 348 +++++++++++++--------------- lib/risc-v_shell_lib.tlv | 478 +++++++++++++++++++++++++++------------ 2 files changed, 491 insertions(+), 335 deletions(-) diff --git a/full_riscv.tlv b/full_riscv.tlv index 82a7f45..ad727e1 100644 --- a/full_riscv.tlv +++ b/full_riscv.tlv @@ -2,6 +2,9 @@ \SV m4_include_lib(['https://raw.githubusercontent.com/stevehoover/warp-v_includes/2d6d36baa4d2bc62321f982f78c8fe1456641a43/risc-v_defs.tlv']) +// v====================== lib/risc-v_shell_lib.tlv =======================v + +// Configuration for WARP-V definitions. m4+definitions([' m4_define_vector(['M4_WORD'], 32) m4_define(['M4_EXT_I'], 1) @@ -9,81 +12,63 @@ m4+definitions([' m4_define(['M4_NUM_INSTRS'], 0) m4_echo(m4tlv_riscv_gen__body()) + + // A single-line M4 macro instantiated at the end of the asm code. + // It actually produces a definition of an SV macro that instantiates the IMem conaining the program (that can be parsed without \SV_plus). + m4_define(['m4_asm_end'], ['`define READONLY_MEM(ADDR, DATA) assign DATA \= instrs[ADDR[\$clog2(\$size(instrs)) + 1 : 2]]; logic [31:0] instrs [0:M4_NUM_INSTRS-1]; assign instrs \= '{m4_instr0['']m4_forloop(['m4_instr_ind'], 1, M4_NUM_INSTRS, [', m4_echo(['m4_instr']m4_instr_ind)'])};']) ']) - -\TLV fill_imem() - // The program in an instruction memory. - \SV_plus - logic [31:0] instrs [0:M4_NUM_INSTRS-1]; - `define READONLY_MEM(ADDR, DATA) assign DATA = instrs[ADDR[\$clog2(\$size(instrs)) + 1 : 2]]; // Verilog macro for use by students - assign instrs = '{ - m4_instr0['']m4_forloop(['m4_instr_ind'], 1, M4_NUM_INSTRS, [', m4_echo(['m4_instr']m4_instr_ind)']) - }; - logic sticky_zero; - assign sticky_zero = 0; - $valid = !*failed; - `BOGUS_USE($valid) - -\TLV rf(_entries, _width, $_reset, $_port1_en, $_port1_index, $_port1_data, $_port2_en, $_port2_index, $$_port2_data, $_port3_en, $_port3_index, $$_port3_data) - m4_ifelse_block(m4_sp_graph_dangerous, 1, [''], [' - /rf_viz - $ANY = /top<>0$ANY; - $viz_rf_reset = m4_argn(3, $@); - $viz_rf_wr_en = m4_argn(4, $@); - $viz_rf_wr_index[\$clog2(_entries)-1:0] = m4_argn(5, $@); - $viz_rf_wr_data[_width-1:0] = m4_argn(6, $@); - $viz_rf_rd_en1 = m4_argn(7, $@); - $viz_rf_rd_index1[\$clog2(_entries)-1:0] = m4_argn(8, $@); - - $viz_rf_rd_en2 = m4_argn(10, $@); - $viz_rf_rd_index2[\$clog2(_entries)-1:0] = m4_argn(11, $@); +// Register File +\TLV rf(_entries, _width, $_reset, $_port1_en, $_port1_index, $_port1_data, $_port2_en, $_port2_index, $_port2_data, $_port3_en, $_port3_index, $_port3_data) + $rf_wr_en = m4_argn(4, $@); + $rf_wr_index[\$clog2(_entries)-1:0] = m4_argn(5, $@); + $rf_wr_data[_width-1:0] = m4_argn(6, $@); + + $rf_rd_en1 = m4_argn(7, $@); + $rf_rd_index1[\$clog2(_entries)-1:0] = m4_argn(8, $@); + + $rf_rd_en2 = m4_argn(10, $@); + $rf_rd_index2[\$clog2(_entries)-1:0] = m4_argn(11, $@); /xreg[_entries-1:0] - $ANY = /top/rf_viz<>0$ANY; - $wr = $viz_rf_wr_en && ($viz_rf_wr_index == #xreg); - $value[_width-1:0] = $viz_rf_reset ? #xreg : - >>1$wr ? >>1$viz_rf_wr_data : - $RETAIN; + <<1$value[_width-1:0] = /top$_reset ? #xreg : + /top$rf_wr_en && (/top$rf_wr_index == #xreg) + ? /top$rf_wr_data : + $RETAIN; - $$_port2_data[_width-1:0] = /top/rf_viz<>0$viz_rf_rd_en1 ? /xreg[/top/rf_viz<>0$viz_rf_rd_index1]$value : 'X; - $$_port3_data[_width-1:0] = /top/rf_viz<>0$viz_rf_rd_en2 ? /xreg[/top/rf_viz<>0$viz_rf_rd_index2]$value : 'X; - ']) + $_port2_data[_width-1:0] = $rf_rd_en1 ? /xreg[$rf_rd_index1]$value : 'X; + $_port3_data[_width-1:0] = $rf_rd_en2 ? /xreg[$rf_rd_index2]$value : 'X; + +// Data Memory +\TLV dmem(_entries, _width, $_reset, $_port1_en, $_port1_index, $_port1_data, $_port2_en, $_port2_index, $_port2_data) + // Allow expressions for most inputs, so define input signals. + $dmem_wr_en = m4_argn(4, $@); + $dmem_wr_index[\$clog2(_entries)-1:0] = m4_argn(5, $@); + $dmem_wr_data[_width-1:0] = m4_argn(6, $@); - -\TLV dmem(_entries, _width, $_reset, $_port1_en, $_port1_index, $_port1_data, $_port2_en, $_port2_index, $$_port2_data) - m4_ifelse_block(m4_sp_graph_dangerous, 1, [''], [' - /dmem_viz - $ANY = /top<>0$ANY; - $viz_dmem_reset = m4_argn(3, $@); - - $viz_dmem_wr_en = m4_argn(4, $@); - $viz_dmem_wr_index[\$clog2(_entries)-1:0] = m4_argn(5, $@); - $viz_dmem_wr_data[_width-1:0] = m4_argn(6, $@); - - $viz_dmem_rd_en = m4_argn(7, $@); - $viz_dmem_rd_index[\$clog2(_entries)-1:0] = m4_argn(8, $@); + $dmem_rd_en = m4_argn(7, $@); + $dmem_rd_index[\$clog2(_entries)-1:0] = m4_argn(8, $@); /dmem[_entries-1:0] - $ANY = /top/dmem_viz<>0$ANY; - $wr = $viz_dmem_wr_en && ($viz_dmem_wr_index == #dmem); - $value[_width-1:0] = $viz_dmem_reset ? #dmem : - >>1$wr ? >>1$viz_dmem_wr_data : - $RETAIN; + <<1$value[_width-1:0] = /top$_reset ? #dmem : + /top$dmem_wr_en && (/top$dmem_wr_index == #dmem) + ? /top$dmem_wr_data : + $RETAIN; + + $_port2_data[_width-1:0] = $dmem_rd_en ? /dmem[$dmem_rd_index]$value : 'X; - $$_port2_data[_width-1:0] = /top/dmem_viz<>0$viz_dmem_rd_en ? /dmem[/top/dmem_viz<>0$viz_dmem_rd_index]$value : 'X; - ']) - \TLV cpu_viz() - m4_ifelse_block(m4_sp_graph_dangerous, 1, [''], [' // String representations of the instructions for debug. \SV_plus + // A default signal for ones that are not found. + logic sticky_zero; + assign sticky_zero = 0; + // Instruction strings from the assembler. logic [40*8-1:0] instr_strs [0:M4_NUM_INSTRS]; assign instr_strs = '{m4_asm_mem_expr "END "}; /cpuviz - $fetch_instr_str[40*8-1:0] = *instr_strs\[/top$pc[\$clog2(M4_NUM_INSTRS+1)+1:2]\]; \viz_alpha initEach() { let imem_header = new fabric.Text("📒 Instr. Memory", { @@ -114,60 +99,69 @@ m4+definitions([' fontWeight: 800, fontFamily: "monospace" }) - let error_header = new fabric.Text("🚨 Missing Signals", { + + let missing = new fabric.Text("", { + top: 420, + left: -400, + fontSize: 16, + fontWeight: 500, + fontFamily: "monospace", + fill: "purple" + }) + let missing_sigs = new fabric.Group( + [new fabric.Text("🚨 Missing Signals", { top: 350, left: -400, fontSize: 18, fontWeight: 800, fill: "red", fontFamily: "monospace" - }) - let error_box = new fabric.Rect({ + }), + new fabric.Rect({ top: 400, left: -500, fill: "#ffffe0", width: 400, height: 300, stroke: "black" - }) - return {objects: {imem_header, decode_header, rf_header, dmem_header, error_header, error_box}}; + }), + missing + ], + {visible: false} + ) + return {missing, + objects: {imem_header, decode_header, rf_header, dmem_header, missing_sigs}}; }, renderEach: function() { - debugger - // - var missing_list = ""; - let sticky_zero = this.svSigRef(`sticky_zero`); - siggen = (name) => { - var sig = this.svSigRef(`L0_${name}_a0`) + var missing_list = ""; // String of missing signals. + let sticky_zero = this.svSigRef(`sticky_zero`); // A default zero-valued signal. + // Attempt to look up a signal, using sticky_zero as default and updating missing_list if expected. + siggen = (name, full_name, expected = true) => { + var sig = this.svSigRef(full_name ? full_name : `L0_${name}_a0`) if (sig == null) { missing_list += `◾ $${name} \n`; sig = sticky_zero; } return sig } - + // Look up signal, and it's ok if it doesn't exist. siggen_rf_dmem = (name, scope) => { - var sig = this.svSigRef(`${scope}_${name}_a0`) - if (sig == null) { - sig = sticky_zero; - } - return sig + return siggen(name, scope, false) } + // Determine which is_xxx signal is asserted. siggen_mnemonic = () => { - instrs = ["lui", "auipc", "jal", "jalr", "beq", "bne", "blt", "bge", "bltu", "bgeu", "lb", "lh", "lw", "lbu", "lhu", "sb", "sh", "sw", "addi", "slti", "sltiu", "xori", "ori", "andi", "slli", "srli", "srai", "add", "sub", "sll", "slt", "sltu", "xor", "srl", "sra", "or", "and", "csrrw", "csrrs", "csrrc", "csrrwi", "csrrsi", "csrrci", "load", "store"]; - for(i=0;i> 2), + top: 18 * (pc.asInt() / 4), left: -295, - fill: color, + fill: "blue", fontSize: 14, fontFamily: "monospace" }) - let pc_arrow = new fabric.Line([23, 18 * (pc.asInt() >> 2) + 6, 46, 35], { + let pc_arrow = new fabric.Line([23, 18 * (pc.asInt() / 4) + 6, 46, 35], { stroke: "#d0e8ff", strokeWidth: 2 }) @@ -235,20 +225,9 @@ m4+definitions([' strokeWidth: 3, visible: dmem_wr_en.asBool() }) - // - // Fetch Instruction - // - // TODO: indexing only works in direct lineage. let fetchInstr = new fabric.Text('|fetch/instr_mem[$Pc]$instr'.asString(), { // TODO: make indexing recursive. - //let fetchInstr = new fabric.Text('$raw'.asString("--"), { - // top: 50, - // left: 90, - // fill: color, - // fontSize: 14, - // fontFamily: "monospace" - //}); - // - // Instruction with values. - // + + + // Instruction with values let regStr = (valid, regNum, regValue) => { return valid ? `r${regNum}` : `rX` // valid ? `r${regNum} (${regValue})` : `rX` @@ -272,9 +251,12 @@ m4+definitions([' fontSize: 14, fontFamily: "monospace" }); + + // Animate fetch (and provide onChange behavior for other animation). - let fetch_instr_viz = new fabric.Text('$fetch_instr_str'.asString(), { + let fetch_instr_str = siggen(`instr_strs(${pc.asInt() >> 2})`, `instr_strs(${pc.asInt() >> 2})`).asString("UNKNOWN fetch instr") + let fetch_instr_viz = new fabric.Text(fetch_instr_str, { top: 18 * (pc.asInt() >> 2), left: -272, fill: "blue", @@ -387,21 +369,16 @@ m4+definitions([' }, 1000) } - let missing_fill = new fabric.Text(missing_list, { - top: 420, - left: -480, - fontSize: 16, - fontWeight: 500, - fontFamily: "monospace", - fill: "purple" - }) + // Missing signals + if (missing_list) { + this.getInitObject("missing_sigs").setVisible(true) + this.fromInit().missing.setText(missing_list) + } - return {objects: [pcPointer, pc_arrow, rs1_arrow, rs2_arrow, rd_arrow, instrWithValues, fetch_instr_viz, src1_value_viz, src2_value_viz, result_shadow, result_viz, ld_arrow, st_arrow, load_viz, store_viz, missing_fill]}; + return {objects: [pcPointer, pc_arrow, rs1_arrow, rs2_arrow, rd_arrow, instrWithValues, fetch_instr_viz, src1_value_viz, src2_value_viz, result_shadow, result_viz, ld_arrow, st_arrow, load_viz, store_viz]}; } /imem[m4_eval(M4_NUM_INSTRS-1):0] // TODO: Cleanly report non-integer ranges. - $instr[31:0] = *instrs\[#imem\]; - $instr_str[40*8-1:0] = *instr_strs[imem]; \viz_alpha initEach() { let binary = new fabric.Text("", { @@ -419,6 +396,8 @@ m4+definitions([' return {objects: {binary: binary, disassembled: disassembled}} }, renderEach: function() { + let siggen = (name) => {return this.svSigRef(`${name}`) == null ? this.svSigRef(`sticky_zero`) : this.svSigRef(`${name}`)} + // Instruction memory is constant, so just create it once. let reset = this.svSigRef(`L0_reset_a0`); let pc = this.svSigRef(`L0_pc_a0`) == null ? this.svSigRef(`sticky_zero`) : this.svSigRef(`L0_pc_a0`); @@ -428,8 +407,8 @@ m4+definitions([' } if (!global.instr_mem_drawn[this.getIndex()]) { global.instr_mem_drawn[this.getIndex()] = true - let binary_str = '$instr'.asBinaryStr(NaN) - let disassembled_str = '$instr_str'.asString() + let binary_str = siggen(`instrs(${this.getIndex()})`).asBinaryStr(NaN) + let disassembled_str = siggen(`instr_strs(${this.getIndex()})`).asString("") disassembled_str = disassembled_str.slice(0, -5) //debugger this.getInitObject("binary").setText(binary_str) @@ -445,22 +424,23 @@ m4+definitions([' }, renderEach: function() { siggen = (name) => this.svSigRef(`${name}`) == null ? this.svSigRef(`sticky_zero`) : this.svSigRef(`${name}`); - let rf_rd_en1 = siggen(`RfViz_viz_rf_rd_en1_a0`); - let rf_rd_index1 = siggen(`RfViz_viz_rf_rd_index1_a0`); - let rf_rd_en2 = siggen(`RfViz_viz_rf_rd_en1_a0`); - let rf_rd_index2 = siggen(`RfViz_viz_rf_rd_index2_a0`); - let rf_wr_index = siggen(`RfViz_viz_rf_wr_index_a0`); - let wr = siggen(`L1_Xreg[${this.getIndex()}].L1_wr_a0`); - let value = siggen(`Xreg_value_a0(${this.getIndex()})`); + + let rf_rd_en1 = siggen(`L0_rf_rd_en1_a0`) + let rf_rd_index1 = siggen(`L0_rf_rd_index1_a0`) + let rf_rd_en2 = siggen(`L0_rf_rd_en1_a0`) + let rf_rd_index2 = siggen(`L0_rf_rd_index2_a0`) + let rf_wr_index = siggen(`rf_wr_index_a0`) + let wr = siggen(`L1_Xreg[${this.getIndex()}].L1_wr_a0`) + let value = siggen(`Xreg_value_a0(${this.getIndex()})`) let rd = (rf_rd_en1.asBool(false) && rf_rd_index1.asInt() == this.getIndex()) || - (rf_rd_en2.asBool(false) && rf_rd_index2.asInt() == this.getIndex()); + (rf_rd_en2.asBool(false) && rf_rd_index2.asInt() == this.getIndex()) let mod = wr.asBool(false); - let wr_color = mod && rf_wr_index.asInt() == this.getIndex(); - let reg = parseInt(this.getIndex()); - let regIdent = reg.toString().padEnd(2, " "); - let newValStr = regIdent + ": "; + let wr_color = mod && rf_wr_index.asInt() == this.getIndex() + let reg = parseInt(this.getIndex()) + let regIdent = reg.toString().padEnd(2, " ") + let newValStr = regIdent + ": " let reg_str = new fabric.Text(regIdent + ": " + value.asInt(NaN).toString(), { top: 18 * this.getIndex() - 40, left: 316, @@ -488,9 +468,9 @@ m4+definitions([' renderEach: function() { siggen = (name) => this.svSigRef(`${name}`) == null ? this.svSigRef(`sticky_zero`) : this.svSigRef(`${name}`); - let dmem_rd_en = siggen(`DmemViz_viz_dmem_rd_en_a0`); - let dmem_rd_index = siggen(`DmemViz_viz_dmem_rd_index_a0`); - let dmem_wr_index = siggen(`DmemViz_viz_dmem_wr_index_a0`); + let dmem_rd_en = siggen(`L0_dmem_rd_en_a0`); + let dmem_rd_index = siggen(`L0_dmem_rd_index_a0`); + let dmem_wr_index = siggen(`L0_dmem_wr_index_a0`); let wr = siggen(`L1_Dmem[${this.getIndex()}].L1_wr_a0`); let value = siggen(`Dmem_value_a0(${this.getIndex()})`); @@ -519,8 +499,8 @@ m4+definitions([' } return {objects: [dmem_str]} } - ']) +// ^===================================================================^ \SV m4_makerchip_module // (Expanded in Nav-TLV pane.) @@ -557,13 +537,9 @@ m4+definitions([' m4_asm(LW, r4, r6, 0) // Optional: m4_asm(JAL, r7, 11111111111111101000) // Done. Jump to itself (infinite loop). (Up to 20-bit signed immediate plus implicit 0 bit (unlike JALR) provides byte address; last immediate bit should also be 0) + m4_asm_end() - m4_define_hier(['M4_IMEM'], M4_NUM_INSTRS) - m4+fill_imem() - - //|cpu - //1 - PC - //@1 + //1 - PC $reset = *reset; $next_pc[31:0] = $reset ? '0 : $taken_br ? $br_tgt_pc : //9 @@ -573,26 +549,25 @@ m4+definitions([' $pc[31:0] = >>1$next_pc; //2 - IMEM - Read - //@1 `READONLY_MEM($pc, $$instr[31:0]) - + //3 - Decode Logic - RISBUJ $is_i_instr = $instr[6:2] ==? 5'b0000x || $instr[6:2] ==? 5'b001x0 || $instr[6:2] ==? 5'b11001 ; - + $is_r_instr = $instr[6:2] ==? 5'b01011 || $instr[6:2] ==? 5'b011x0 || $instr[6:2] ==? 5'b10100 ; - + $is_s_instr = $instr[6:2] ==? 5'b0100x; - + $is_b_instr = $instr[6:2] ==? 5'b11000; - + $is_j_instr = $instr[6:2] ==? 5'b11011; - + $is_u_instr = $instr[6:2] ==? 5'b0x101; - + //4 - Instr Fields $funct7[6:0] = $instr[31:25]; $funct3[2:0] = $instr[14:12]; @@ -601,7 +576,7 @@ m4+definitions([' $rd[4:0] = $instr[11:7]; $opcode[6:0] = $instr[6:0]; `BOGUS_USE($funct7 $funct3 $rs1 $rs2 $rd $opcode) - + $funct7_valid = $is_r_instr; $funct3_valid = $is_r_instr || $is_i_instr || $is_s_instr || $is_b_instr; $rs1_valid = $is_r_instr || $is_i_instr || $is_s_instr || $is_b_instr; @@ -609,7 +584,7 @@ m4+definitions([' $rd_valid = $is_r_instr || $is_i_instr || $is_u_instr || $is_j_instr; $imm_valid = $is_i_instr || $is_s_instr || $is_b_instr || $is_u_instr || $is_j_instr; `BOGUS_USE($funct7_valid $funct3_valid $rs1_valid $rs2_valid $rd_valid $imm_valid) - + //5 - Imm $imm[31:0] = $is_i_instr ? {{21{$instr[31]}}, $instr[30:20]} : $is_s_instr ? {{21{$instr[31]}}, $instr[30:25], $instr[11:7]} : @@ -618,7 +593,7 @@ m4+definitions([' $is_j_instr ? {{12{$instr[31]}}, $instr[19:12], $instr[20], $instr[30:21], 1'b0} : 32'b0 ; `BOGUS_USE($imm) - + //6 - Decode Instr Name $dec_bits[10:0] = {$funct7[5], $funct3, $opcode}; $is_beq = $dec_bits ==? 11'bx_000_1100011; @@ -627,22 +602,22 @@ m4+definitions([' $is_bge = $dec_bits ==? 11'bx_101_1100011; $is_bltu = $dec_bits ==? 11'bx_110_1100011; $is_bgeu = $dec_bits ==? 11'bx_111_1100011; - + $is_addi = $dec_bits ==? 11'bx_000_0010011; $is_add = $dec_bits ==? 11'b0_000_0110011; `BOGUS_USE($is_beq $is_bne $is_blt $is_bge $is_bltu $is_bgeu $is_addi $is_add) - + //7 - RF Read //$rf_rd_en1 = $rs1_valid; //$rf_rd_index1[4:0] = $rs1; //$src1_value[31:0] = $rf_rd_data1; - + //$rf_rd_en2 = $rs2_valid; //$rf_rd_index2[4:0] = $rs2; //$src2_value[31:0] = $rf_rd_data2; - + //`BOGUS_USE($src1_value $src2_value) - + //8 - ALU //$result[31:0] = $is_addi ? $src1_value + $imm : // $is_add ? $src1_value + $src2_value : @@ -650,7 +625,7 @@ m4+definitions([' //$rf_wr_en = $rd_valid && ($rd != 5'b0); //$rf_wr_index[4:0] = $rd; //$rf_wr_data[31:0] = $is_load ? $ld_data : $result; // 14 - + //9- Branch $taken_br = $is_beq ? ($src1_value == $src2_value) : $is_bne ? ($src1_value != $src2_value) : @@ -659,26 +634,26 @@ m4+definitions([' $is_bltu ? ($src1_value < $src2_value) : $is_bgeu ? ($src1_value >= $src2_value) : 1'b0; - + $br_tgt_pc[31:0] = $pc + $imm; - + // 10 - Stop //*passed = |cpu/xreg[10]>>5$value == (1+2+3+4+5+6+7+8+9); - + //11 $is_lui = $dec_bits ==? 11'bx_xxx_0110111 ; $is_auipc = $dec_bits ==? 11'bx_xxx_0010111 ; $is_jal = $dec_bits ==? 11'bx_xxx_1101111 ; $is_jalr = $dec_bits ==? 11'bx_000_1100111 ; - + $is_load = $opcode == 7'b0000011 ; - + $is_sb = $dec_bits ==? 11'bx_000_0100011 ; $is_sh = $dec_bits ==? 11'bx_001_0100011 ; $is_sw = $dec_bits ==? 11'bx_010_0100011 ; - + $is_slti = $dec_bits ==? 11'bx_010_0010011 ; - + //12 $result[31:0] = $is_addi || $is_load || $is_s_instr ? $src1_value + $imm : // 14 $is_add ? $src1_value + $src2_value : @@ -692,7 +667,7 @@ m4+definitions([' $is_jump = $is_jal || $is_jalr; $jalr_tgt_pc[31:0] = $src1_value + $imm; - + //14 //$dmem_wr_en = $is_s_instr; //$dmem_rd_en1 = $is_load; @@ -700,18 +675,18 @@ m4+definitions([' //$dmem_wr_index[4:0] = $result[6:2]; //$dmem_wr_data[31:0] = $src2_value; //$ld_data[31:0] = $dmem_rd_data1; - + //*passed = |cpu/xreg[4]>>5$value == 0; // YOUR CODE HERE // ... - + // Note: Because of the magic we are using for visualisation, if visualisation is enabled below, // be sure to avoid having unassigned signals (which you might be using for random inputs) // other than those specifically expected in the labs. You'll get strange errors for these. - + // Assert these to end simula/toption (before Makerchip cycle limit). - *passed = *cyc_cnt > 60; + *passed = *cyc_cnt > 50; *failed = 1'b0; // Macro instantiations for: @@ -720,11 +695,10 @@ m4+definitions([' // o data memory // o CPU visualization //|cpu - m4+rf(32, 32, $reset, $rd_valid && ($rd != 5'b0), $rd, $is_load ? $ld_data : $result, $rs1_valid, $rs1, $$src1_value[31:0], $rs2_valid, $rs2, $$src2_value[31:0]) - //m4+rf(32, 32, $reset, $rd_valid && ($rd != 5'b0), $rd, $result, $rs1_valid, $rs1, $$src1_value[31:0], $rs2_valid, $rs2, $$src2_value[31:0]) - m4+dmem(32, 32, $reset, $is_s_instr, $result[6:2], $src2_value, $is_load, $result[6:2], $$ld_data[31:0]) + m4+rf(32, 32, $reset, $rd_valid && ($rd != 5'b0), $rd, $is_load ? $ld_data : $result, $rs1_valid, $rs1, $src1_value[31:0], $rs2_valid, $rs2, $src2_value[31:0]) + //m4+rf(32, 32, $reset, $rd_valid && ($rd != 5'b0), $rd, $result, $rs1_valid, $rs1, $src1_value[31:0], $rs2_valid, $rs2, $src2_value[31:0]) + m4+dmem(32, 32, $reset, $is_s_instr, $result[6:2], $src2_value, $is_load, $result[6:2], $ld_data[31:0]) - m4+cpu_viz() // For visualisation, argument should be at least equal to the last stage of CPU logic - // @4 would work for all labs + m4+cpu_viz() \SV endmodule diff --git a/lib/risc-v_shell_lib.tlv b/lib/risc-v_shell_lib.tlv index b5a93d4..63f9ba4 100644 --- a/lib/risc-v_shell_lib.tlv +++ b/lib/risc-v_shell_lib.tlv @@ -2,6 +2,9 @@ \SV m4_include_lib(['https://raw.githubusercontent.com/stevehoover/warp-v_includes/2d6d36baa4d2bc62321f982f78c8fe1456641a43/risc-v_defs.tlv']) +// v====================== lib/risc-v_shell_lib.tlv =======================v + +// Configuration for WARP-V definitions. m4+definitions([' m4_define_vector(['M4_WORD'], 32) m4_define(['M4_EXT_I'], 1) @@ -9,81 +12,63 @@ m4+definitions([' m4_define(['M4_NUM_INSTRS'], 0) m4_echo(m4tlv_riscv_gen__body()) + + // A single-line M4 macro instantiated at the end of the asm code. + // It actually produces a definition of an SV macro that instantiates the IMem conaining the program (that can be parsed without \SV_plus). + m4_define(['m4_asm_end'], ['`define READONLY_MEM(ADDR, DATA) assign DATA \= instrs[ADDR[\$clog2(\$size(instrs)) + 1 : 2]]; logic [31:0] instrs [0:M4_NUM_INSTRS-1]; assign instrs \= '{m4_instr0['']m4_forloop(['m4_instr_ind'], 1, M4_NUM_INSTRS, [', m4_echo(['m4_instr']m4_instr_ind)'])};']) ']) - -\TLV fill_imem() - // The program in an instruction memory. - \SV_plus - logic [31:0] instrs [0:M4_NUM_INSTRS-1]; - `define READONLY_MEM(ADDR, DATA) assign DATA = instrs[ADDR[\$clog2(\$size(instrs)) + 1 : 2]]; // Verilog macro for use by students - assign instrs = '{ - m4_instr0['']m4_forloop(['m4_instr_ind'], 1, M4_NUM_INSTRS, [', m4_echo(['m4_instr']m4_instr_ind)']) - }; - logic sticky_zero; - assign sticky_zero = 0; - $valid = !*failed; - `BOGUS_USE($valid) - -\TLV rf(_entries, _width, $_reset, $_port1_en, $_port1_index, $_port1_data, $_port2_en, $_port2_index, $$_port2_data, $_port3_en, $_port3_index, $$_port3_data) - m4_ifelse_block(m4_sp_graph_dangerous, 1, [''], [' - /rf_viz - $ANY = /top<>0$ANY; - $viz_rf_reset = m4_argn(3, $@); - $viz_rf_wr_en = m4_argn(4, $@); - $viz_rf_wr_index[\$clog2(_entries)-1:0] = m4_argn(5, $@); - $viz_rf_wr_data[_width-1:0] = m4_argn(6, $@); - $viz_rf_rd_en1 = m4_argn(7, $@); - $viz_rf_rd_index1[\$clog2(_entries)-1:0] = m4_argn(8, $@); - - $viz_rf_rd_en2 = m4_argn(10, $@); - $viz_rf_rd_index2[\$clog2(_entries)-1:0] = m4_argn(11, $@); +// Register File +\TLV rf(_entries, _width, $_reset, $_port1_en, $_port1_index, $_port1_data, $_port2_en, $_port2_index, $_port2_data, $_port3_en, $_port3_index, $_port3_data) + $rf_wr_en = m4_argn(4, $@); + $rf_wr_index[\$clog2(_entries)-1:0] = m4_argn(5, $@); + $rf_wr_data[_width-1:0] = m4_argn(6, $@); + + $rf_rd_en1 = m4_argn(7, $@); + $rf_rd_index1[\$clog2(_entries)-1:0] = m4_argn(8, $@); + + $rf_rd_en2 = m4_argn(10, $@); + $rf_rd_index2[\$clog2(_entries)-1:0] = m4_argn(11, $@); /xreg[_entries-1:0] - $ANY = /top/rf_viz<>0$ANY; - $wr = $viz_rf_wr_en && ($viz_rf_wr_index == #xreg); - $value[_width-1:0] = $viz_rf_reset ? #xreg : - >>1$wr ? >>1$viz_rf_wr_data : - $RETAIN; + <<1$value[_width-1:0] = /top$_reset ? #xreg : + /top$rf_wr_en && (/top$rf_wr_index == #xreg) + ? /top$rf_wr_data : + $RETAIN; - $$_port2_data[_width-1:0] = /top/rf_viz<>0$viz_rf_rd_en1 ? /xreg[/top/rf_viz<>0$viz_rf_rd_index1]$value : 'X; - $$_port3_data[_width-1:0] = /top/rf_viz<>0$viz_rf_rd_en2 ? /xreg[/top/rf_viz<>0$viz_rf_rd_index2]$value : 'X; - ']) + $_port2_data[_width-1:0] = $rf_rd_en1 ? /xreg[$rf_rd_index1]$value : 'X; + $_port3_data[_width-1:0] = $rf_rd_en2 ? /xreg[$rf_rd_index2]$value : 'X; + +// Data Memory +\TLV dmem(_entries, _width, $_reset, $_port1_en, $_port1_index, $_port1_data, $_port2_en, $_port2_index, $_port2_data) + // Allow expressions for most inputs, so define input signals. + $dmem_wr_en = m4_argn(4, $@); + $dmem_wr_index[\$clog2(_entries)-1:0] = m4_argn(5, $@); + $dmem_wr_data[_width-1:0] = m4_argn(6, $@); - -\TLV dmem(_entries, _width, $_reset, $_port1_en, $_port1_index, $_port1_data, $_port2_en, $_port2_index, $$_port2_data) - m4_ifelse_block(m4_sp_graph_dangerous, 1, [''], [' - /dmem_viz - $ANY = /top<>0$ANY; - $viz_dmem_reset = m4_argn(3, $@); - - $viz_dmem_wr_en = m4_argn(4, $@); - $viz_dmem_wr_index[\$clog2(_entries)-1:0] = m4_argn(5, $@); - $viz_dmem_wr_data[_width-1:0] = m4_argn(6, $@); - - $viz_dmem_rd_en = m4_argn(7, $@); - $viz_dmem_rd_index[\$clog2(_entries)-1:0] = m4_argn(8, $@); + $dmem_rd_en = m4_argn(7, $@); + $dmem_rd_index[\$clog2(_entries)-1:0] = m4_argn(8, $@); /dmem[_entries-1:0] - $ANY = /top/dmem_viz<>0$ANY; - $wr = $viz_dmem_wr_en && ($viz_dmem_wr_index == #dmem); - $value[_width-1:0] = $viz_dmem_reset ? #dmem : - >>1$wr ? >>1$viz_dmem_wr_data : - $RETAIN; + <<1$value[_width-1:0] = /top$_reset ? #dmem : + /top$dmem_wr_en && (/top$dmem_wr_index == #dmem) + ? /top$dmem_wr_data : + $RETAIN; + + $_port2_data[_width-1:0] = $dmem_rd_en ? /dmem[$dmem_rd_index]$value : 'X; - $$_port2_data[_width-1:0] = /top/dmem_viz<>0$viz_dmem_rd_en ? /dmem[/top/dmem_viz<>0$viz_dmem_rd_index]$value : 'X; - ']) - \TLV cpu_viz() - m4_ifelse_block(m4_sp_graph_dangerous, 1, [''], [' // String representations of the instructions for debug. \SV_plus + // A default signal for ones that are not found. + logic sticky_zero; + assign sticky_zero = 0; + // Instruction strings from the assembler. logic [40*8-1:0] instr_strs [0:M4_NUM_INSTRS]; assign instr_strs = '{m4_asm_mem_expr "END "}; /cpuviz - $fetch_instr_str[40*8-1:0] = *instr_strs\[/top$pc[\$clog2(M4_NUM_INSTRS+1)+1:2]\]; \viz_alpha initEach() { let imem_header = new fabric.Text("📒 Instr. Memory", { @@ -114,60 +99,69 @@ m4+definitions([' fontWeight: 800, fontFamily: "monospace" }) - let error_header = new fabric.Text("🚨 Missing Signals", { + + let missing = new fabric.Text("", { + top: 420, + left: -400, + fontSize: 16, + fontWeight: 500, + fontFamily: "monospace", + fill: "purple" + }) + let missing_sigs = new fabric.Group( + [new fabric.Text("🚨 Missing Signals", { top: 350, left: -400, fontSize: 18, fontWeight: 800, fill: "red", fontFamily: "monospace" - }) - let error_box = new fabric.Rect({ + }), + new fabric.Rect({ top: 400, left: -500, fill: "#ffffe0", width: 400, height: 300, stroke: "black" - }) - return {objects: {imem_header, decode_header, rf_header, dmem_header, error_header, error_box}}; + }), + missing + ], + {visible: false} + ) + return {missing, + objects: {imem_header, decode_header, rf_header, dmem_header, missing_sigs}}; }, renderEach: function() { - debugger - // - var missing_list = ""; - let sticky_zero = this.svSigRef(`sticky_zero`); - siggen = (name) => { - var sig = this.svSigRef(`L0_${name}_a0`) + var missing_list = ""; // String of missing signals. + let sticky_zero = this.svSigRef(`sticky_zero`); // A default zero-valued signal. + // Attempt to look up a signal, using sticky_zero as default and updating missing_list if expected. + siggen = (name, full_name, expected = true) => { + var sig = this.svSigRef(full_name ? full_name : `L0_${name}_a0`) if (sig == null) { missing_list += `◾ $${name} \n`; sig = sticky_zero; } return sig } - + // Look up signal, and it's ok if it doesn't exist. siggen_rf_dmem = (name, scope) => { - var sig = this.svSigRef(`${scope}_${name}_a0`) - if (sig == null) { - sig = sticky_zero; - } - return sig + return siggen(name, scope, false) } + // Determine which is_xxx signal is asserted. siggen_mnemonic = () => { - instrs = ["lui", "auipc", "jal", "jalr", "beq", "bne", "blt", "bge", "bltu", "bgeu", "lb", "lh", "lw", "lbu", "lhu", "sb", "sh", "sw", "addi", "slti", "sltiu", "xori", "ori", "andi", "slli", "srli", "srai", "add", "sub", "sll", "slt", "sltu", "xor", "srl", "sra", "or", "and", "csrrw", "csrrs", "csrrc", "csrrwi", "csrrsi", "csrrci", "load", "store"]; - for(i=0;i> 2), + top: 18 * (pc.asInt() / 4), left: -295, - fill: color, + fill: "blue", fontSize: 14, fontFamily: "monospace" }) - let pc_arrow = new fabric.Line([23, 18 * (pc.asInt() >> 2) + 6, 46, 35], { + let pc_arrow = new fabric.Line([23, 18 * (pc.asInt() / 4) + 6, 46, 35], { stroke: "#d0e8ff", strokeWidth: 2 }) @@ -235,20 +225,9 @@ m4+definitions([' strokeWidth: 3, visible: dmem_wr_en.asBool() }) - // - // Fetch Instruction - // - // TODO: indexing only works in direct lineage. let fetchInstr = new fabric.Text('|fetch/instr_mem[$Pc]$instr'.asString(), { // TODO: make indexing recursive. - //let fetchInstr = new fabric.Text('$raw'.asString("--"), { - // top: 50, - // left: 90, - // fill: color, - // fontSize: 14, - // fontFamily: "monospace" - //}); - // - // Instruction with values. - // + + + // Instruction with values let regStr = (valid, regNum, regValue) => { return valid ? `r${regNum}` : `rX` // valid ? `r${regNum} (${regValue})` : `rX` @@ -272,9 +251,12 @@ m4+definitions([' fontSize: 14, fontFamily: "monospace" }); + + // Animate fetch (and provide onChange behavior for other animation). - let fetch_instr_viz = new fabric.Text('$fetch_instr_str'.asString(), { + let fetch_instr_str = siggen(`instr_strs(${pc.asInt() >> 2})`, `instr_strs(${pc.asInt() >> 2})`).asString("UNKNOWN fetch instr") + let fetch_instr_viz = new fabric.Text(fetch_instr_str, { top: 18 * (pc.asInt() >> 2), left: -272, fill: "blue", @@ -387,21 +369,16 @@ m4+definitions([' }, 1000) } - let missing_fill = new fabric.Text(missing_list, { - top: 420, - left: -480, - fontSize: 16, - fontWeight: 500, - fontFamily: "monospace", - fill: "purple" - }) + // Missing signals + if (missing_list) { + this.getInitObject("missing_sigs").setVisible(true) + this.fromInit().missing.setText(missing_list) + } - return {objects: [pcPointer, pc_arrow, rs1_arrow, rs2_arrow, rd_arrow, instrWithValues, fetch_instr_viz, src1_value_viz, src2_value_viz, result_shadow, result_viz, ld_arrow, st_arrow, load_viz, store_viz, missing_fill]}; + return {objects: [pcPointer, pc_arrow, rs1_arrow, rs2_arrow, rd_arrow, instrWithValues, fetch_instr_viz, src1_value_viz, src2_value_viz, result_shadow, result_viz, ld_arrow, st_arrow, load_viz, store_viz]}; } /imem[m4_eval(M4_NUM_INSTRS-1):0] // TODO: Cleanly report non-integer ranges. - $instr[31:0] = *instrs\[#imem\]; - $instr_str[40*8-1:0] = *instr_strs[imem]; \viz_alpha initEach() { let binary = new fabric.Text("", { @@ -419,6 +396,8 @@ m4+definitions([' return {objects: {binary: binary, disassembled: disassembled}} }, renderEach: function() { + let siggen = (name) => {return this.svSigRef(`${name}`) == null ? this.svSigRef(`sticky_zero`) : this.svSigRef(`${name}`)} + // Instruction memory is constant, so just create it once. let reset = this.svSigRef(`L0_reset_a0`); let pc = this.svSigRef(`L0_pc_a0`) == null ? this.svSigRef(`sticky_zero`) : this.svSigRef(`L0_pc_a0`); @@ -428,8 +407,8 @@ m4+definitions([' } if (!global.instr_mem_drawn[this.getIndex()]) { global.instr_mem_drawn[this.getIndex()] = true - let binary_str = '$instr'.asBinaryStr(NaN) - let disassembled_str = '$instr_str'.asString() + let binary_str = siggen(`instrs(${this.getIndex()})`).asBinaryStr(NaN) + let disassembled_str = siggen(`instr_strs(${this.getIndex()})`).asString("") disassembled_str = disassembled_str.slice(0, -5) //debugger this.getInitObject("binary").setText(binary_str) @@ -445,22 +424,23 @@ m4+definitions([' }, renderEach: function() { siggen = (name) => this.svSigRef(`${name}`) == null ? this.svSigRef(`sticky_zero`) : this.svSigRef(`${name}`); - let rf_rd_en1 = siggen(`RfViz_viz_rf_rd_en1_a0`); - let rf_rd_index1 = siggen(`RfViz_viz_rf_rd_index1_a0`); - let rf_rd_en2 = siggen(`RfViz_viz_rf_rd_en1_a0`); - let rf_rd_index2 = siggen(`RfViz_viz_rf_rd_index2_a0`); - let rf_wr_index = siggen(`RfViz_viz_rf_wr_index_a0`); - let wr = siggen(`L1_Xreg[${this.getIndex()}].L1_wr_a0`); - let value = siggen(`Xreg_value_a0(${this.getIndex()})`); + + let rf_rd_en1 = siggen(`L0_rf_rd_en1_a0`) + let rf_rd_index1 = siggen(`L0_rf_rd_index1_a0`) + let rf_rd_en2 = siggen(`L0_rf_rd_en1_a0`) + let rf_rd_index2 = siggen(`L0_rf_rd_index2_a0`) + let rf_wr_index = siggen(`rf_wr_index_a0`) + let wr = siggen(`L1_Xreg[${this.getIndex()}].L1_wr_a0`) + let value = siggen(`Xreg_value_a0(${this.getIndex()})`) let rd = (rf_rd_en1.asBool(false) && rf_rd_index1.asInt() == this.getIndex()) || - (rf_rd_en2.asBool(false) && rf_rd_index2.asInt() == this.getIndex()); + (rf_rd_en2.asBool(false) && rf_rd_index2.asInt() == this.getIndex()) let mod = wr.asBool(false); - let wr_color = mod && rf_wr_index.asInt() == this.getIndex(); - let reg = parseInt(this.getIndex()); - let regIdent = reg.toString().padEnd(2, " "); - let newValStr = regIdent + ": "; + let wr_color = mod && rf_wr_index.asInt() == this.getIndex() + let reg = parseInt(this.getIndex()) + let regIdent = reg.toString().padEnd(2, " ") + let newValStr = regIdent + ": " let reg_str = new fabric.Text(regIdent + ": " + value.asInt(NaN).toString(), { top: 18 * this.getIndex() - 40, left: 316, @@ -488,9 +468,9 @@ m4+definitions([' renderEach: function() { siggen = (name) => this.svSigRef(`${name}`) == null ? this.svSigRef(`sticky_zero`) : this.svSigRef(`${name}`); - let dmem_rd_en = siggen(`DmemViz_viz_dmem_rd_en_a0`); - let dmem_rd_index = siggen(`DmemViz_viz_dmem_rd_index_a0`); - let dmem_wr_index = siggen(`DmemViz_viz_dmem_wr_index_a0`); + let dmem_rd_en = siggen(`L0_dmem_rd_en_a0`); + let dmem_rd_index = siggen(`L0_dmem_rd_index_a0`); + let dmem_wr_index = siggen(`L0_dmem_wr_index_a0`); let wr = siggen(`L1_Dmem[${this.getIndex()}].L1_wr_a0`); let value = siggen(`Dmem_value_a0(${this.getIndex()})`); @@ -519,4 +499,206 @@ m4+definitions([' } return {objects: [dmem_str]} } - ']) + +// ^===================================================================^ + +\SV + m4_makerchip_module // (Expanded in Nav-TLV pane.) + +\TLV + + // /====================\ + // | Sum 1 to 9 Program | + // \====================/ + // + // Program for MYTH Workshop to test RV32I + // Add 1,2,3,...,9 (in that order). + // + // Regs: + // r10 (a0): In: 0, Out: final sum + // r12 (a2): 10 + // r13 (a3): 1..10 + // r14 (a4): Sum + // + // External to function: + m4_asm(ADD, r10, r0, r0) // Initialize r10 (a0) to 0. + // Function: + m4_asm(ADD, r14, r10, r0) // Initialize sum register a4 with 0x0 + m4_asm(ADDI, r12, r10, 1010) // Store count of 10 in register a2. + m4_asm(ADD, r13, r10, r0) // Initialize intermediate sum register a3 with 0 + // Loop: + m4_asm(ADD, r14, r13, r14) // Incremental addition + m4_asm(ADDI, r13, r13, 1) // Increment intermediate register by 1 + m4_asm(BLT, r13, r12, 1111111111000) // If a3 is less than a2, branch to label named + m4_asm(ADD, r10, r14, r0) // Store final result to register a0 so that it can be read by main program + m4_asm(ADDI, r1, r0, 101) + m4_asm(ORI, r6, r0, 0) + m4_asm(SW, r6, r1, 0) + m4_asm(LW, r4, r6, 0) + // Optional: + m4_asm(JAL, r7, 11111111111111101000) // Done. Jump to itself (infinite loop). (Up to 20-bit signed immediate plus implicit 0 bit (unlike JALR) provides byte address; last immediate bit should also be 0) + m4_asm_end() + + //1 - PC + $reset = *reset; + $next_pc[31:0] = $reset ? '0 : + $taken_br ? $br_tgt_pc : //9 + $is_jal ? $br_tgt_pc : // 13 + $is_jalr ? $jalr_tgt_pc : // 13 + $pc + 32'd4 ; + $pc[31:0] = >>1$next_pc; + + //2 - IMEM - Read + `READONLY_MEM($pc, $$instr[31:0]) + + //3 - Decode Logic - RISBUJ + $is_i_instr = $instr[6:2] ==? 5'b0000x || + $instr[6:2] ==? 5'b001x0 || + $instr[6:2] ==? 5'b11001 ; + + $is_r_instr = $instr[6:2] ==? 5'b01011 || + $instr[6:2] ==? 5'b011x0 || + $instr[6:2] ==? 5'b10100 ; + + $is_s_instr = $instr[6:2] ==? 5'b0100x; + + $is_b_instr = $instr[6:2] ==? 5'b11000; + + $is_j_instr = $instr[6:2] ==? 5'b11011; + + $is_u_instr = $instr[6:2] ==? 5'b0x101; + + //4 - Instr Fields + $funct7[6:0] = $instr[31:25]; + $funct3[2:0] = $instr[14:12]; + $rs1[4:0] = $instr[19:15]; + $rs2[4:0] = $instr[24:20]; + $rd[4:0] = $instr[11:7]; + $opcode[6:0] = $instr[6:0]; + `BOGUS_USE($funct7 $funct3 $rs1 $rs2 $rd $opcode) + + $funct7_valid = $is_r_instr; + $funct3_valid = $is_r_instr || $is_i_instr || $is_s_instr || $is_b_instr; + $rs1_valid = $is_r_instr || $is_i_instr || $is_s_instr || $is_b_instr; + $rs2_valid = $is_r_instr || $is_s_instr || $is_b_instr ; + $rd_valid = $is_r_instr || $is_i_instr || $is_u_instr || $is_j_instr; + $imm_valid = $is_i_instr || $is_s_instr || $is_b_instr || $is_u_instr || $is_j_instr; + `BOGUS_USE($funct7_valid $funct3_valid $rs1_valid $rs2_valid $rd_valid $imm_valid) + + //5 - Imm + $imm[31:0] = $is_i_instr ? {{21{$instr[31]}}, $instr[30:20]} : + $is_s_instr ? {{21{$instr[31]}}, $instr[30:25], $instr[11:7]} : + $is_b_instr ? {{20{$instr[31]}}, $instr[7], $instr[30:25], $instr[11:8], 1'b0} : + $is_u_instr ? {$instr[31:12], 12'b0} : + $is_j_instr ? {{12{$instr[31]}}, $instr[19:12], $instr[20], $instr[30:21], 1'b0} : + 32'b0 ; + `BOGUS_USE($imm) + + //6 - Decode Instr Name + $dec_bits[10:0] = {$funct7[5], $funct3, $opcode}; + $is_beq = $dec_bits ==? 11'bx_000_1100011; + $is_bne = $dec_bits ==? 11'bx_001_1100011; + $is_blt = $dec_bits ==? 11'bx_100_1100011; + $is_bge = $dec_bits ==? 11'bx_101_1100011; + $is_bltu = $dec_bits ==? 11'bx_110_1100011; + $is_bgeu = $dec_bits ==? 11'bx_111_1100011; + + $is_addi = $dec_bits ==? 11'bx_000_0010011; + $is_add = $dec_bits ==? 11'b0_000_0110011; + `BOGUS_USE($is_beq $is_bne $is_blt $is_bge $is_bltu $is_bgeu $is_addi $is_add) + + //7 - RF Read + //$rf_rd_en1 = $rs1_valid; + //$rf_rd_index1[4:0] = $rs1; + //$src1_value[31:0] = $rf_rd_data1; + + //$rf_rd_en2 = $rs2_valid; + //$rf_rd_index2[4:0] = $rs2; + //$src2_value[31:0] = $rf_rd_data2; + + //`BOGUS_USE($src1_value $src2_value) + + //8 - ALU + //$result[31:0] = $is_addi ? $src1_value + $imm : + // $is_add ? $src1_value + $src2_value : + // 32'bx; + //$rf_wr_en = $rd_valid && ($rd != 5'b0); + //$rf_wr_index[4:0] = $rd; + //$rf_wr_data[31:0] = $is_load ? $ld_data : $result; // 14 + + //9- Branch + $taken_br = $is_beq ? ($src1_value == $src2_value) : + $is_bne ? ($src1_value != $src2_value) : + $is_blt ? (($src1_value < $src2_value) ^ ($src1_value[31] != $src2_value[31])) : + $is_bge ? (($src1_value >= $src2_value) ^ ($src1_value[31] != $src2_value[31])) : + $is_bltu ? ($src1_value < $src2_value) : + $is_bgeu ? ($src1_value >= $src2_value) : + 1'b0; + + $br_tgt_pc[31:0] = $pc + $imm; + + // 10 - Stop + //*passed = |cpu/xreg[10]>>5$value == (1+2+3+4+5+6+7+8+9); + + //11 + $is_lui = $dec_bits ==? 11'bx_xxx_0110111 ; + $is_auipc = $dec_bits ==? 11'bx_xxx_0010111 ; + $is_jal = $dec_bits ==? 11'bx_xxx_1101111 ; + $is_jalr = $dec_bits ==? 11'bx_000_1100111 ; + + $is_load = $opcode == 7'b0000011 ; + + $is_sb = $dec_bits ==? 11'bx_000_0100011 ; + $is_sh = $dec_bits ==? 11'bx_001_0100011 ; + $is_sw = $dec_bits ==? 11'bx_010_0100011 ; + + $is_slti = $dec_bits ==? 11'bx_010_0010011 ; + + //12 + $result[31:0] = $is_addi || $is_load || $is_s_instr ? $src1_value + $imm : // 14 + $is_add ? $src1_value + $src2_value : + $is_lui ? {$imm[31:12], 12'b0} : + $is_auipc ? $pc + $imm : + $is_jal ? $pc + 32'd4 : + $is_jalr ? $pc + 32'd4 : + $is_slti ? (($src1_value[31] == $imm[31]) ? $src1_value < $imm : {31'b0, $src1_value[31]}) : + 32'bx; + //13 + $is_jump = $is_jal || $is_jalr; + $jalr_tgt_pc[31:0] = $src1_value + $imm; + + + //14 + //$dmem_wr_en = $is_s_instr; + //$dmem_rd_en1 = $is_load; + //$dmem_rd_index1[4:0] = $result[6:2]; + //$dmem_wr_index[4:0] = $result[6:2]; + //$dmem_wr_data[31:0] = $src2_value; + //$ld_data[31:0] = $dmem_rd_data1; + + //*passed = |cpu/xreg[4]>>5$value == 0; + // YOUR CODE HERE + // ... + + // Note: Because of the magic we are using for visualisation, if visualisation is enabled below, + // be sure to avoid having unassigned signals (which you might be using for random inputs) + // other than those specifically expected in the labs. You'll get strange errors for these. + + + // Assert these to end simula/toption (before Makerchip cycle limit). + *passed = *cyc_cnt > 50; + *failed = 1'b0; + + // Macro instantiations for: + // o instruction memory + // o register file + // o data memory + // o CPU visualization + //|cpu + m4+rf(32, 32, $reset, $rd_valid && ($rd != 5'b0), $rd, $is_load ? $ld_data : $result, $rs1_valid, $rs1, $src1_value[31:0], $rs2_valid, $rs2, $src2_value[31:0]) + //m4+rf(32, 32, $reset, $rd_valid && ($rd != 5'b0), $rd, $result, $rs1_valid, $rs1, $src1_value[31:0], $rs2_valid, $rs2, $src2_value[31:0]) + m4+dmem(32, 32, $reset, $is_s_instr, $result[6:2], $src2_value, $is_load, $result[6:2], $ld_data[31:0]) + + m4+cpu_viz() +\SV + endmodule