From aa0e1a756b1d9e9106a0af958a659b5324a27095 Mon Sep 17 00:00:00 2001 From: Steve Hoover Date: Wed, 17 Feb 2021 17:33:13 -0500 Subject: [PATCH] Prepping shell and reference solutions. --- lib/risc-v_shell_lib.tlv | 215 +-------------------------------------- risc-v_solutions.tlv | 45 ++++++++ 2 files changed, 47 insertions(+), 213 deletions(-) create mode 100644 risc-v_solutions.tlv diff --git a/lib/risc-v_shell_lib.tlv b/lib/risc-v_shell_lib.tlv index df2fe0e..5fa1b02 100644 --- a/lib/risc-v_shell_lib.tlv +++ b/lib/risc-v_shell_lib.tlv @@ -16,16 +16,6 @@ m4+definitions([' // 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) logic [31:0] instrs [0:M4_NUM_INSTRS-1]; assign DATA \= instrs[ADDR[\$clog2(\$size(instrs)) + 1 : 2]]; assign instrs \= '{m4_instr0['']m4_forloop(['m4_instr_ind'], 1, M4_NUM_INSTRS, [', m4_echo(['m4_instr']m4_instr_ind)'])};']) - - m4_define(['m4_lab'], 0) - m4_define(['m4_define_labs'], [' - m4_define(['M4_$1_LAB'], m4_lab) - m4_define(['m4_lab'], m4_eval(m4_lab + 1)) - m4_ifelse(['$1'], [''], [''], ['m4_define_labs(m4_shift($@))']) - ']) - m4_define_labs(START, PC, IMEM, INSTR_TYPE, FIELDS, IMM, SUBSET_INSTRS, RF_MACRO, RF_READ, SUBSET_ALU, RF_WRITE, TAKEN_BR, BR_REDIR, TB, - TEST_PROG, ALL_INSTRS, FULL_ALU, JUMP, LD_ST_ADDR, DMEM, LD_DATA, DONE) - m4_define(['m4_reached'], ['m4_eval(M4_LAB >= M4_$1_LAB), 1']) ']) @@ -733,6 +723,7 @@ m4+definitions([' m4_asm_end() m4_define(['M4_MAX_CYC'], 70) +// (A copy of this appears in the shell code.) \TLV sum_prog() // /====================\ // | Sum 1 to 9 Program | @@ -769,211 +760,9 @@ m4+definitions([' // Possible choices for M4_LAB. // START, PC, IMEM, INSTR_TYPE, FIELDS, IMM, SUBSET_INSTRS, RF_MACRO, RF_READ, SUBSET_ALU, RF_WRITE, TAKEN_BR, BR_REDIR, TB, // TEST_PROG, ALL_INSTRS, FULL_ALU, JUMP, LD_ST_ADDR, DMEM, LD_DATA, DONE - m4_default(['M4_LAB'], M4_DONE_LAB) + m4_default(['M4_LAB'], M4_PC_LAB) // @@@@@@@@@@@@@@@@@@@@@@@@@@@@@ /* Built for LAB: M4_LAB */ - - m4_ifelse(m4_reached(['TEST_PROG']), ['m4_define(['M4_VIZ_BASE'], 16)']) // (Note that immediate values are shown in disassembled instructions in binary and signed decimal in decoder regardless of this setting.) - m4_define(['m4_prog_macro'], m4_ifelse(m4_reached(['TEST_PROG']), ['test_prog'], ['sum_prog'])) - m4+m4_prog_macro() - - //-------------------------------------- - - m4_ifelse_block(m4_reached(['PC']), [' - $reset = *reset; - $next_pc[31:0] = $reset ? '0 : - m4_ifelse_block(m4_reached(['BR_REDIR']), [' - $taken_br ? $br_tgt_pc : - ']) - m4_ifelse_block(m4_reached(['JUMP']), [' - $is_jal ? $br_tgt_pc : - $is_jalr ? $jalr_tgt_pc : - ']) - $pc + 32'd4 ; - $pc[31:0] = >>1$next_pc; - ']) - - m4_ifelse_block(m4_reached(['IMEM']), [' - `READONLY_MEM($pc, $$instr[31:0]) - ']) - - m4_ifelse_block(m4_reached(['INSTR_TYPE']), [' - $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; - ']) - - m4_ifelse_block(m4_reached(['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]; - - $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; - ']) - - m4_ifelse_block(m4_reached(['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 ; - ']) - - m4_ifelse_block(m4_reached(['SUBSET_INSTRS']), [' - $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; - ']) - - m4_ifelse_block(m4_reached(['RF_WRITE']), [' - m4_define(['m4_rf_wr_en'], ['$rd_valid']) - m4_define(['m4_rf_wr_index'], ['$rd']) - m4_define(['m4_rf_wr_data'], ['$result']) - '], [' - m4_define(['m4_rf_wr_en'], ['$rf_wr_en']) - m4_define(['m4_rf_wr_index'], ['$rf_wr_index']) - m4_define(['m4_rf_wr_data'], ['$rf_wr_data']) - ']) - m4_ifelse_block(m4_reached(['FULL_ALU']), [' - $sltu_rslt = $src1_value < $src2_value; - $sltiu_rslt = $src1_value < $imm; - ']) - m4_ifelse_block(m4_reached(['SUBSET_ALU']), [' - $result[31:0] = $is_addi ? $src1_value + $imm : - $is_add ? $src1_value + $src2_value : - m4_ifelse_block(m4_reached(['FULL_ALU']), [' - $is_andi ? $src1_value & $imm : - $is_ori ? $src1_value | $imm : - $is_xori ? $src1_value ^ $imm : - $is_slli ? $src1_value << $imm[5:0] : - $is_srli ? $src1_value >> $imm[5:0] : - $is_and ? $src1_value & $src2_value : - $is_or ? $src1_value | $src2_value : - $is_xor ? $src1_value ^ $src2_value : - $is_sub ? $src1_value - $src2_value : - $is_sll ? $src1_value << $src2_value[4:0] : - $is_srl ? $src1_value >> $src2_value[4:0] : - $is_sltu ? $sltu_rslt : - $is_sltiu ? $sltiu_rslt : - $is_lui ? {$imm[31:12], 12'b0} : - $is_auipc ? $pc + $imm : - $is_jal ? $pc + 32'd4 : - $is_jalr ? $pc + 32'd4 : - $is_srai ? {{32{$src1_value[31]}}, $src1_value} >> $imm[4:0] : - $is_slt ? (($src1_value[31] == $src2_value[31]) ? $sltu_rslt : {31'b0, $src1_value[31]}) : - $is_slti ? (($src1_value[31] == $imm[31]) ? $sltiu_rslt : {31'b0, $src1_value[31]}) : - $is_sra ? {{32{$src1_value[31]}}, $src1_value} >> $src2_value[4:0] : - ']) - m4_ifelse_block(m4_reached(['LD_ST_ADDR']), [' - $is_load || $is_s_instr ? $src1_value + $imm : - ']) - 32'b0; - m4_define(['m4_rf_wr_en'], ['$rd_valid && ($rd != 5'b0)']) - ']) - - - m4_ifelse_block(m4_reached(['TAKEN_BR']), [' - $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; - ']) - - m4_ifelse_block(m4_reached(['ALL_INSTRS']), [' - $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_slti = $dec_bits ==? 11'bx_010_0010011 ; - - $is_sltiu = $dec_bits ==? 11'bx_011_0010011 ; - $is_xori = $dec_bits ==? 11'bx_100_0010011 ; - $is_ori = $dec_bits ==? 11'bx_110_0010011 ; - $is_andi = $dec_bits ==? 11'bx_111_0010011 ; - $is_slli = $dec_bits ==? 11'b0_001_0010011 ; - $is_srli = $dec_bits ==? 11'b0_101_0010011 ; - $is_srai = $dec_bits ==? 11'b1_101_0010011 ; - $is_sub = $dec_bits ==? 11'b1_000_0110011 ; - $is_sll = $dec_bits ==? 11'b0_001_0110011 ; - $is_slt = $dec_bits ==? 11'b0_010_0110011 ; - $is_sltu = $dec_bits ==? 11'b0_011_0110011 ; - $is_xor = $dec_bits ==? 11'b0_100_0110011 ; - $is_srl = $dec_bits ==? 11'b0_101_0110011 ; - $is_sra = $dec_bits ==? 11'b1_101_0110011 ; - $is_or = $dec_bits ==? 11'b0_110_0110011 ; - $is_and = $dec_bits ==? 11'b0_111_0110011 ; - ']) - - m4_ifelse_block(m4_reached(['JUMP']), [' - $jalr_tgt_pc[31:0] = $src1_value + $imm; - ']) - - m4_ifelse_block(m4_reached(['LD_DATA']), [' - m4_define(['m4_rf_wr_data'], ['$is_load ? $ld_data : $result']) - ']) - - // Assert these to end simulation (before Makerchip cycle limit). - m4_ifelse_block(m4_reached(['TB']), [' - m4+tb() - '], [' - *passed = 1'b0; - ']) - *failed = *cyc_cnt > M4_MAX_CYC; - - // Macro instantiations for: - // o instruction memory - // o register file - // o data memory - // o CPU visualization - //|cpu - m4_ifelse_block(m4_reached(['RF_READ']), [' - m4+rf(32, 32, $reset, m4_rf_wr_en, m4_rf_wr_index, m4_rf_wr_data, $rs1_valid, $rs1, $src1_value[31:0], $rs2_valid, $rs2, $src2_value[31:0]) - '], m4_reached(['RF_MACRO']), [' - m4+rf(32, 32, $reset, $wr_en, $wr_index, $wr_data, $rd1_en, $rd1_index, $rd1_data, $rd2_en, $rd2_index, $rd2_data) - ']) - m4_ifelse_block(m4_reached(['DMEM']), [' - m4+dmem(32, 32, $reset, $is_s_instr, $result[6:2], $src2_value, $is_load, $result[6:2], $ld_data) - ']) - - //m4+rf(32, 32, $reset, $wr_en, $wr_index, $wr_data, $rd1_en, $rd1_index, $rd1_data, $rd2_en, $rd2_index, $rd2_data) - //m4+dmem(32, 32, $reset, $wr_en, $wr_addr, $wr_data, $rd_en, $rd_addr, $wr_data) - m4+cpu_viz() \SV endmodule diff --git a/risc-v_solutions.tlv b/risc-v_solutions.tlv new file mode 100644 index 0000000..a530e1e --- /dev/null +++ b/risc-v_solutions.tlv @@ -0,0 +1,45 @@ +\m4_TLV_version 1d: tl-x.org +\SV + + // ================================================== + // For use in the Building a RISC-V CPU Core Course. + // Provides reference solutions without visibility to source code. + // ================================================== + + // ---------------------------------- + // Instructions: + // - When stuck on a particular lab, select the lab at the bottom of this file, + // and compile/simulate. + // - A reference solution will build, but the source code will not be visible. + // - You may use waveforms, diagrams, and visualization to understand the proper circuit, but you + // will have to come up with the code. Logic expression syntax can be found by hovering over the + // signal assignment in the diagram. + // - Course updates can be found here: https://github.com/stevehoover/LF-Building-a-RISC-V-CPU-Core + // ---------------------------------- + + // Include solutions. + m4_include_makerchip_hidden(['LF_workshop_solutions.private.tlv']) + +\SV + // Macro providing required top-level module definition, random + // stimulus support, and Verilator config. + m4_makerchip_module // (Expanded in Nav-TLV pane.) +\TLV + + + //=================\ + // Choose Your Lab | + //=================/ + + // Specify which lab you are on by providing a macro argument... + m4+hidden_solution(START) + // ...from these: + // Chapter 4: + // START, PC, IMEM, INSTR_TYPE, FIELDS, IMM, SUBSET_INSTRS, + // RF_MACRO, RF_READ, SUBSET_ALU, RF_WRITE, TAKEN_BR, BR_REDIR, TB, + // Chapter 5: + // TEST_PROG, ALL_INSTRS, FULL_ALU, JUMP, LD_ST_ADDR, DMEM, LD_DATA, DONE + + +\SV + endmodule \ No newline at end of file