/* Copyright 2021-2024 Philippos Papaphilippou You are free to use, learn from, modify and distribute this creative work under the following conditions: 1. No code, text, or other elements of this work can be used as an input to models for the purposes of training. Generative A.I. and language models are prohibited from using this work. These do not include search engines and related tools whose main purpose is to index and appropriately point to the original source and author. 2. It comes under no warranties. 3. Any modification to the code shall be made available in the style of GNU General Public License v2.0 (GPL-2.0), but published under the same license (not GPL-2.0, and clause 7 still refers to the original copyright holder). 4. A proper attribution of the author (copyright holder) is required when the work is used. (If applicable, it would be appreciated to cite the related academic publication that introduced the work.) 5. It cannot be used for commercial purposes unless specific permission is given by the author. 6. A redistribution shall include this license in its entirety. 7. The author has the right to change this license for future versions of this work, as well as to update and clarify the author's original intentions of the current version, such as with regard to what is considered "fair use" by the author for future entities and technologies. */ //`define XLEN 32 // (not yet other than 32) `define IADDR_bits 21 `define DADDR_bits 30 // >= IADDR_bits `define VLEN 256 `define VLEN_Log2 $clog2(`VLEN) `define NumVregisters 4 // (-1 for register 0, up to 8 -1 registers) `define Rtype 0 // No immediate `define Itype 1 `define Stype 2 `define Btype 3 `define Utype 4 // 20-bit immediate `define Jtype 5 // Instruction decode is done asynchronusly as it happens in the same cycle module IDecoder(instr, iformat, rs1, rs2, rd, immediate, alui_en, auipc_en, load_en, absolute_pc, m_inst, counters, simd_inst, c1_en, c2_en, c3_en); input [31:0] instr; output reg [2:0] iformat; output [4:0] rs1; output [4:0] rs2; output [4:0] rd; output reg [31:0] immediate; output reg alui_en; output reg auipc_en; output reg load_en; output reg absolute_pc; output reg m_inst; output reg counters; output reg simd_inst; output reg c1_en; output reg c2_en; output reg c3_en; assign rs1 = instr[19:15]; assign rs2 = instr[24:20]; assign rd = instr[11: 7]; always @(*) begin case (instr[6:2]) 5'h18: iformat = `Btype; // beq, bne, blt, bge, bltu, bgeu, 5'h19: iformat = `Itype; // jalr, * 5'h1b: iformat = `Jtype; // jal, * 5'h0d: iformat = `Utype; // lui, * 5'h05: iformat = `Utype; // auipc,* 5'h04: iformat = `Itype; // addi, slli, slti, sltiu, xori, srli, srai, ori, andi, 5'h0c: iformat = `Rtype; // add, sub, sll, slt, sltu, xor, srl, sra, or, and, // mul, mulh, mulhsu, mulhu, div, divu, rem, remu 5'h00: iformat = `Itype; // lb, lh, lw, lbu, lhu, 5'h08: iformat = `Stype; // sb, sh, sw, 5'h03: iformat = `Itype; // fence, fence.i * 5'h1c: iformat = `Itype; // CSR (rdcycle, rdtime, rdinstret, rdcycleh, rdtimeh, rdinstreth) 5'h02: iformat = `Rtype; // Custom instruction 0 (c0_lv, c0_sv) 5'h0A: iformat = `Itype; // Custom instruction 1 (c1 (for c1_merge in the example)) 5'h16: iformat = `Itype; // Custom instruction 2 (c2 (for c2_sort or c2_prefix in the example)) 5'h1E: iformat = `Itype; // Custom instruction 3 (c3) default begin iformat =`Rtype; end endcase case (iformat) //`Rtype: `Itype: immediate = {{21{instr[31]}}, instr[30:25], instr[24:21], instr[20]}; `Stype: immediate = {{21{instr[31]}}, instr[30:25], instr[11:8], instr[7]}; `Btype: immediate = {{20{instr[31]}}, instr[7], instr[30:25], instr[11:8], 1'b0}; `Utype: immediate = {instr[31], instr[30:20],instr[19:12], 12'b0}; `Jtype: immediate = {{12{instr[31]}}, instr[19:12], instr[20], instr[30:25], instr[24:21], 1'b0}; default: immediate = 0; endcase alui_en=0; auipc_en=0; load_en=0; absolute_pc=0; m_inst=0; counters=0; simd_inst=0; c1_en=0; c2_en=0; c3_en=0; case (instr[6:2]) 5'h00: load_en=1; 5'h05: auipc_en=1; // auipc, 5'h19: begin alui_en=1; absolute_pc=1; end 5'h1b: begin end// jalr, 5'h04: alui_en=1; // addi, slli, slti, sltiu, xori, srli, srai, ori, andi, 5'h0c: begin alui_en=!instr[25]; // add, sub, sll, slt, sltu, xor, srl, sra, or, and, m_inst=instr[25]; // mul, mulh, mulhsu, mulhu, div, divu, rem, remu end 5'h1c: counters=1; 5'h02: begin load_en=instr[14:12]==0; simd_inst=1; end 5'h0A: begin c1_en=1; simd_inst=1; end 5'h16: begin c2_en=1; simd_inst=1; end 5'h1E: begin c3_en=1; simd_inst=1; end default:; endcase end endmodule // IDecoder // Integer ALU for the base registers module ALUint(data1, data2, func, result); input [31:0] data1; input [31:0] data2; input [3:0] func; output reg [31:0] result; wire[32:0] sub; assign sub = data1-data2; wire sign_swap = data1[31]!=data2[31]; always @(*) begin if (`DEB)$display("%h func(%h) %h", data1, func, data2); case (func[2:0]) 3'h0: begin if (func[3]==0) result = data1 + data2; // add(i) else result = sub; // sub (func 0 with instr[30]==1 & not imm) (subi not available) end 3'h1: result = data1 << data2[4:0];// sll(i) 3'h2: result = (sub[32]==1)^(sign_swap);// ($signed(data1) < $signed(data2)); // slt(i) 3'h3: result = (sub[32]==1); // slt(i)u 3'h4: result = data1 ^ data2; // xor(i) 3'h5: begin if (func[3]==0) result = data1 >> data2[4:0];// srl(i) else result = $signed(data1) >>> data2[4:0];// sra(i) (func 5 with instr[30]==1) end 3'h6: result = data1 | data2; // or(i) 3'h7: result = data1 & data2;// and(i) default: result=0; endcase end endmodule // ALUint // ALU for the "M" extension (behaviourial) module ALUintM(clk, reset, valid, rdin, data1, data2, func, result, rd, ready, accepting); input clk, reset, valid; input [4:0] rdin; input [31:0] data1; input [31:0] data2; input [3:0] func; output reg [31:0] result; output reg [4:0] rd; output reg ready; output reg accepting; reg [63:0] num1; reg [63:0] num2; always @(*) begin case (func) 3'h0: begin num1 ={32'b0,data1}; num2 = {32'b0,data2}; end // mul 3'h1: begin num1 ={{32{data1[31]}},data1}; num2 = {{32{data2[31]}},data2}; end // mulh 3'h2: begin num1 ={{32{data1[31]}},data1}; num2 = {32'b0,data2}; end // mulhu 3'h3: begin num1 ={32'b0,data1}; num2 = {32'b0,data2}; end // mulhsu default: begin num1 = data1; num2 = data2; end endcase end reg [63:0] product; reg [1:0] clk2; reg [2:0] pend_f; reg [63:0] data1s; reg [63:0] data2s; reg pend; reg pend2; always @(posedge clk) begin if (reset) begin clk2<=0; pend<=0; pend2=0; pend_f<=0; accepting<=1; end else begin clk2<=clk2+1; if (valid) begin if (`DEB)$display ("ALUintM %h %h",num1,num2,data1,data2 ); data1s<=num1; data2s<=num2; pend2=valid; rd<=rdin; pend_f<=func; accepting<=0; end if (pend2 && (clk2==2'b01)) begin pend<=1; pend2=0; end ready<=0; if (clk2==2'b01 && pend) begin pend<=0; ready<=1; accepting<=1; end end end wire lc = clk2[1]; //(clk2==2'b11); // worked with past Vivado version (?) always @(posedge lc) begin product = data1s * data2s; case (pend_f) 3'h0: result <= product[31:0]; // mul 3'h1: result <= product[63:32]; // mulh 3'h2: result <= product[63:32]; // mulhu 3'h3: result <= product[63:32]; // mulhsu 3'h4: result <= $signed(data1s[31:0])/$signed(data2s[31:0]); // div 3'h5: result <= data1s[31:0]/data2s[31:0]; // divu 3'h6: result <= $signed(data1s[31:0])%$signed(data2s[31:0]); // rem 3'h7: result <= data1s[31:0]%data2s[31:0]; // remu default: result<=0; endcase if (`DEB)if (valid)$display("ALUM %d %d = %d, func %d", data1, data2, result, func); end endmodule // ALUintM // Separate ALU for the branch operations module ALUbranch(data1, data2, func, result); input [32:0] data1; input [32:0] data2; input [2:0] func; output reg result; wire[32:0] sub; assign sub = data1-data2; wire sign_swap = data1[31]!=data2[31]; always @(*) begin case (func) 3'h0: result = sub==0; // beq 3'h1: result = sub!=0; // bne 3'h4: begin result = (sub[32]==1)^(sign_swap); if (`DEB)$display("blt> %h %h %h", data1, data2, result); end // blt 3'h5: begin result = (sub[32]==0)^(sign_swap); if (`DEB)$display("bge> %h %h %h", data1, data2, result); end // bge 3'h6: result = sub[32]==1; // bltu 3'h7:begin result = sub[32]==0; if (`DEB) $display("bgeu> %h %h %h", data1, data2, result); end // bgeu default: result = 0; endcase end endmodule // ALUbranch // Asynchronus PC logic (so that the next PC is available to IL1 beforehand, for no delay on IL1 hits) module PClogic (clk, reset, next_direction, next_step, PC, PCnext); input clk, reset; input [1:0] next_direction; input [`IADDR_bits-1:0] next_step; // sign-extended input [`IADDR_bits-1:0] PC; output reg [`IADDR_bits-1:0] PCnext; always @(*) begin begin case (next_direction) 2'h0: PCnext = PC; 2'h1: PCnext = PC + 4; 2'h2: PCnext = PC + next_step; 2'h3: PCnext = next_step; endcase end end endmodule // PClogic module Core (clk, reset, cycles, addrA, dinA, readyI, StartAddress, StackPointer, addrB, dinB, doutB, enB, weB, readyB, accepting, debug ); input clk, reset; output [31:0] cycles; // carry cycle count only for debugging, hence the 32-bit limit output [`IADDR_bits-1:0] addrA; input wire [32-1:0] dinA; input wire readyI; input wire [`IADDR_bits-1:0] StartAddress; input wire [`DADDR_bits-1:0] StackPointer; output reg [`DADDR_bits-1:0] addrB; input wire [`VLEN-1:0] dinB; output reg [`VLEN-1:0] doutB; output reg enB; output reg [`VLEN/8-1:0] weB; input readyB; input accepting; output debug; reg [48-1:0] cycle_counter; reg [48-1:0] instr_counter; reg [`IADDR_bits-1:0] PC; wire [`IADDR_bits-1:0] PCnext; wire [31:0] instr; reg halt; reg [31:0] reg_file [31:0]; assign debug=halt;//PC; wire [1:0] next_direction; wire [`IADDR_bits-1:0] next_step; wire [2:0] func3; assign func3=instr[14:12]; PClogic pcl(clk, reset, next_direction, next_step, PC, PCnext); assign addrA = PCnext; assign instr = dinA; wire alui_enable, auipc_enable, load_enable, absolute_pc, m_inst; wire [2:0] iformat; wire [31:0] immediate; wire [4:0] rs1; wire [4:0] rs2; wire [4:0] rd; wire counters; wire simd_inst; wire c1_en, c2_en, c3_en; wire [`DADDR_bits-1:0] daddr; assign daddr=reg_file[rs1]+(simd_inst?reg_file[rs2]:immediate); IDecoder ide (instr, iformat, rs1, rs2, rd, immediate, alui_enable, auipc_enable, load_enable, absolute_pc, m_inst, counters, simd_inst, c1_en, c2_en, c3_en); // Logic for deciding next PC behaviour, according to the instruction type (iformat), // ALU branch result (branch_take), and when there is a stall (halt) etc. wire branch_take; wire [31:0] alu_dst; wire dir_bit1; assign dir_bit1 = absolute_pc || ((iformat==`Jtype) || (branch_take && (iformat==`Btype))); wire dir_bit0; assign dir_bit0 = (iformat!=`Jtype) && !(branch_take && (iformat==`Btype)); assign next_direction = {dir_bit1, dir_bit0}&{!(halt|reset), !(halt|reset)}; assign next_step= absolute_pc?{daddr[`DADDR_bits-1:1],1'b0}:immediate; wire [`IADDR_bits-1:0] auipc; assign auipc = PC+immediate; wire [`IADDR_bits-1:0] pc4; assign pc4=PC+4; // Select the appropriate operands for ALUint, such as according to if it adds the immediate field wire [31:0] alu_rs1; assign alu_rs1 = reg_file[rs1]; wire [31:0] alu_rs2; assign alu_rs2 = (iformat==`Itype || iformat==`Stype)?immediate:reg_file[rs2]; wire [3:0] alu_func; assign alu_func = {instr[30]&&!(iformat==`Itype&&func3==0),func3}; ALUint alu0 (alu_rs1, alu_rs2, alu_func, alu_dst); ALUbranch alu1 (alu_rs1, alu_rs2, func3, branch_take); // Separate ALU for the "M" instruction wire [4:0] m_rd; wire m_ready; wire [31:0] m_res; wire m_acc; ALUintM alu2 (clk, reset, m_inst&!halt, rd, alu_rs1, alu_rs2, alu_func, m_res, m_rd, m_ready, m_acc); integer i; reg was_en2, readok; // 4 outstanding reads (must be in order) (but not very pipelined at the moment) reg [1:0] read_rq_i_in; reg [2+3-1:0] read_rq_filter [3:0]; reg [1+4:0] read_rq_reg [3:0]; // one more bit to say if vector reg [1:0] read_rq_i_out; wire [4:0] rd_read; assign rd_read = read_rq_reg[read_rq_i_out]; wire rd_read_v; assign rd_read_v = read_rq_reg[read_rq_i_out][5]; wire [2+3-1:0] rd_filter; assign rd_filter = read_rq_filter[read_rq_i_out]; reg reg_pend [31:0]; reg [`VLEN-1:0] reg_file_v [`NumVregisters-1:0]; reg reg_pend_v [`NumVregisters-1:0]; wire [2:0] vrs1; assign vrs1 = instr[31:29]; wire [2:0] vrd1; assign vrd1 = instr[28:26]; wire [2:0] vrs2; assign vrs2 = instr[25:23]; wire [2:0] vrd2; assign vrd2 = instr[22:20]; wire fetch_wait; assign fetch_wait = ((!accepting) || ((read_rq_i_in+1)%4==read_rq_i_out)); wire c1_not_accepting; // very specific to merge, can be removed for others (but also below) // Stall logic, according to the instruction type, as there are different data dependancy checks always @(*) begin case (iformat) `Rtype: halt =!readyI|| reg_pend[rs1] || reg_pend[rs2] ||reg_pend[rd] || (m_inst&&!m_acc) || (simd_inst && (reg_pend_v[vrd1] ||reg_pend_v[vrs1] || fetch_wait )); `Itype: halt =!readyI|| reg_pend[rs1] ||reg_pend[rd]|| (load_enable && (fetch_wait)) || ( simd_inst && (reg_pend_v[vrs1] || reg_pend_v[vrs2] //||reg_pend_v[vrd1] || reg_pend_v[vrd2] || c1_not_accepting) ); `Stype: halt =!readyI|| reg_pend[rs1] || reg_pend[rs2] || (!accepting); `Btype: halt =!readyI|| reg_pend[rs1] || reg_pend[rs2]; `Utype: halt=!readyI||reg_pend[rd]; `Jtype: halt=!readyI||reg_pend[rd]; default: halt=!readyI; endcase end // Registers holding the input data for all custom SIMD instructions wire [`VLEN-1:0] c_inA; assign c_inA = reg_file_v[vrs1]; wire [`VLEN-1:0] c_inB; assign c_inB = reg_file_v[vrs2]; wire [31:0] c_in; assign c_in = reg_file [ rs1]; wire [2:0] c_rd1; assign c_rd1=vrd1; wire [2:0] c_rd2; assign c_rd2=vrd2; wire [4:0] c_rd; assign c_rd =rd; // **** Custom instructions placeholder **** wire [`VLEN-1:0] c1_outA; wire [`VLEN-1:0] c1_outB; wire [2:0] c1_out_rd1; wire [2:0] c1_out_rd2; wire c1_out_v; wire c1_out; wire [4:0] c1_out_rd; wire c1_out_sv; Merger2x8x32bit // This can be commented out if not used c1_merg (clk, reset, c_rd, c_rd1, c_rd2, c1_en&&!(halt), c_inA, c_inB, c1_out_v, c1_outA, c1_outB, c1_out_rd, c1_out_rd1, c1_out_rd2, c1_out_sv, c1_out, c1_not_accepting); wire [`VLEN-1:0] c2_outA; wire [`VLEN-1:0] c2_outB; wire [2:0] c2_out_rd1; wire [2:0] c2_out_rd2; wire c2_out_v; Sorter1x8x32bit // Can be removed or replaced with PrefixSum1x8x32bit etc. //PrefixSum1x8x32bit c2_s (clk, reset, c_rd1, c2_en&&!(halt), c_inA, c2_out_v, c2_outA, c2_out_rd1 ); /////// Instantiation of the dummy template /////// wire [`VLEN-1:0] c3_outA; wire [`VLEN-1:0] c3_outB; wire [2:0] c3_out_rd1; wire [2:0] c3_out_rd2; wire c3_out_v; wire [31:0] c3_out; wire [4:0] c3_out_rd; C3_custom_SIMD_instruction c3 (clk, reset, c3_en&&!(halt), c_rd, c_rd1, c_rd2, c_in, c_inA, c_inB, c3_out_v, c3_out_rd, c3_out_rd1, c3_out_rd2, c3_out, c3_outA, c3_outB); // **** Custom instructions placeholder end **** assign cycles=cycle_counter; always @(posedge clk) begin if (reset) begin for (i=0; i<32; i=i+1) begin reg_file[i]<=0; reg_pend[i]<=0; end for (i=0; i<`NumVregisters; i=i+1) begin reg_file_v[i]<=0; reg_pend_v[i]<=0; end reg_file[2] <= StackPointer; PC<=StartAddress; enB<=0; weB<=0; cycle_counter<=0; instr_counter<=0; read_rq_i_in<=0; read_rq_i_out<=0; for (i=0; i<4; i=i+1) begin read_rq_filter[i]<=0; read_rq_reg[i]<=0; end end else begin cycle_counter<=cycle_counter+48'b1; enB<=0; weB<=0; // On a valid result from custom instruction C1, update the registers, and mark them non-pending if(c1_out_v) begin reg_file_v[c1_out_rd1]<=c1_outA; reg_file_v[c1_out_rd2]<=c1_outB; reg_pend_v[c1_out_rd1]<=0; reg_pend_v[c1_out_rd2]<=0; if(`DEB) $display("C1_PEND finished %d",cycle_counter+1); end if (c1_out_sv) begin // specific to merge, but a similar approach can be used if results are ready on different times reg_file[c1_out_rd]<=c1_out; reg_pend[c1_out_rd]<=0; end // On a valid result from custom instruction C2, update the registers, and mark them non-pending if(c2_out_v) begin reg_file_v[c2_out_rd1]<=c2_outA; reg_pend_v[c2_out_rd1]<=0; if(`DEB) $display("C2_PEND finished %d",cycle_counter+1); end // On a valid result from custom instruction C3, update the registers, and mark them non-pending if(c3_out_v) begin reg_file[c3_out_rd]<=c3_out; reg_pend[c3_out_rd]<=0; reg_file_v[c3_out_rd1]<=c3_outA; reg_pend_v[c3_out_rd1]<=0; reg_file_v[c3_out_rd2]<=c3_outB; reg_pend_v[c3_out_rd2]<=0; if(`DEB) $display("C3_PEND finished %d",cycle_counter+1); end // On a valid result from an "M" instruction, store it and mark it non-pending if (m_ready) begin reg_file[m_rd]<=m_res; reg_pend[m_rd]<=0; if (`DEB)$display("MULTI %d -> x%d, cycle: %d, instr %d", m_res, m_rd, cycle_counter, instr_counter); if(`DEB)$display("MULT_PEND finished %d",cycle_counter+1); end // On arriving reads from caches if (readyB) begin read_rq_i_out<=read_rq_i_out+1; if(`DEB)$display("LOAD_PEND finished %d",cycle_counter+1); // If it is for a 32-bit register, manipulate it according to the requested format if (!rd_read_v) begin reg_pend[rd_read]<=0; if (`DEB)$display("x%d released cyc%d %h",rd_read,cycle_counter, dinB); case(rd_filter[2:0]) 3'h0: reg_file[rd_read]<= // lb {{24{dinB[ 7]}},dinB[ 7:0]}; {{24{dinB[(rd_filter[4:3]+1)*8-1]}}, dinB[(rd_filter[4:3]+1)*8-1-:8]}; 3'h1: reg_file[rd_read]<= // lh {{16{dinB[15]}},dinB[15:0]}; {{16{dinB[(rd_filter[4] +1)*16-1]}}, dinB[(rd_filter[4] +1)*16-1-:16]}; 3'h2: reg_file[rd_read]<=dinB; // lw 3'h4: reg_file[rd_read]<= // lbu {24'b0, dinB[ 7:0]}; {24'b0, dinB[(rd_filter[4:3]+1)*8-1-:8]}; 3'h5: reg_file[rd_read]<= // lhu {16'b0, dinB[15:0]}; {16'b0, dinB[(rd_filter[4] +1)*16-1-:16]}; default: ; endcase if (`DEB)if ( ((rd_filter[2:0]==1)&&(rd_filter[3]==1)) || ((rd_filter[2:0]==5)&&(rd_filter[3]==1)) || ((rd_filter[2:0]==2)&&(rd_filter[4:3]!=0)) ) $display("ERROR: alignment"); if (`DEB)$display("reading",rd_read,read_rq_reg[read_rq_i_out],read_rq_i_out," ",dinB," ",rd_filter ); // If it was from a vector load, then allignement is assumed end else begin reg_pend_v[rd_read]<=0; reg_file_v[rd_read]<=dinB; if (`DEB)$display("SIMD read %h to v%d cyc%d",dinB, rd_read,cycle_counter); end end // If there is no stall proceed to update PC and do the rest of the tasks happening in a cycle if (!halt) begin PC<=PCnext; instr_counter<=instr_counter+1; if (`DEB)$display("%h %h %h %h %h %h %h %h |%h", reg_file[10], reg_file[11], reg_file[12], reg_file[13], reg_file[9], reg_file[13], reg_file[14], reg_file[15], doutB); if (`DEB)$display("PC: %h ( %d ) %h Instr: %h x %d %d %d im%h fun%d dad%h ha%d cyc %d", PC,PC,PCnext, instr, rs1, rs2,rd,immediate, alu_func,addrB, halt,cycle_counter); // According to the istruction type, bahave differently case (iformat) `Rtype: begin reg_file[rd]<=alu_dst; if (`DEB)if(alui_enable)$display("%d(%d_%d)->x%d, cycle: %d, instr %d ",alu_dst,alu_rs1,alu_rs2, rd, cycle_counter, instr_counter); reg_pend[rd]<=0; if (simd_inst && (func3==2)) begin if (`DEB)$display("SIMDwrite %h from v%d daddr %h cyc%d PC%h", reg_file_v[vrs1],vrs1, daddr,cycle_counter,PC); doutB <= reg_file_v[vrs1]; weB<={(`VLEN/8){1'b1}}; addrB <= {daddr[`DADDR_bits-1:`VLEN_Log2-3],{(`VLEN_Log2-3){1'b0}} }; end end `Itype: begin if (alui_enable) begin reg_file[rd] <= alu_dst; if (`DEB)$display("%h->x%d from %h %h PC %h",alu_dst, rd,alu_rs1, alu_rs2,PC); end if (absolute_pc) begin reg_file[rd] <= pc4; end if (counters) begin if (`DEB)$display("Counter %h %h -> x%d imm %b",instr_counter, cycle_counter , rd, {immediate[7],immediate[1:0]}); case({immediate[7],immediate[1:0]}) 3'b000: reg_file[rd] <=cycle_counter [31: 0]; // rdcycle 3'b001: reg_file[rd] <=cycle_counter [31: 0]<<3; // rdtime (8 ns per cycle for 125 MHz) 3'b010: reg_file[rd] <=instr_counter [31: 0]; // rdinstret 3'b100: reg_file[rd] <=cycle_counter [47:32]; // rdcycleh 3'b101: reg_file[rd] <=cycle_counter [47:32+3]; // rdtimeh (8 ns per cycle for 125 MHz) 3'b110: reg_file[rd] <=instr_counter [47:32]; //rdinstreth endcase end reg_pend[rd]<=0; if (simd_inst) begin reg_pend[rd]<=1; reg_pend_v[vrd1]<=1; reg_pend_v[vrd2]<=1; end end `Stype: begin // For stores, update the write bits for the DL1 (weB) and data (doutB), according to the command doutB <= reg_file[rs2]; case(func3) 3'h0: begin // sb weB<=(1'b1)<