Prepping shell and reference solutions.

This commit is contained in:
Steve Hoover 2021-02-17 17:33:13 -05:00
parent 74d2ba2733
commit aa0e1a756b
2 changed files with 47 additions and 213 deletions

View File

@ -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

45
risc-v_solutions.tlv Normal file
View File

@ -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