diff --git a/bench/serv_ctrl_tb.v b/bench/serv_ctrl_tb.v index 01505cb..3800aeb 100644 --- a/bench/serv_ctrl_tb.v +++ b/bench/serv_ctrl_tb.v @@ -3,9 +3,9 @@ module serv_ctrl_tb; reg clk = 1'b1; reg go; - reg instr; - reg jal; - + wire en; + wire jump; + wire [31:0] pc_data; wire pc_valid; reg pc_ready = 1'b1; @@ -24,20 +24,26 @@ module serv_ctrl_tb; vlog_tb_utils vtu(); + serv_decode decode + ( + .clk (clk), + .i_go (go), + .i_instr (instruction), + .o_ctrl_jump (jump), + .o_ctrl_en (en), + .o_imm (offset), + .o_rd_from_ctrl ()); + serv_ctrl #(.RESET_PC (32'h464)) dut ( - .clk (clk), - .i_go (go), - .i_instr (instr), - .i_jal (jal), - .i_reg11 (reg11), - .i_reg2012 (reg2012[0]), - .o_reg2012_en (reg2012_en), - .o_rd (rd), - .o_rd_valid (rd_valid), - .o_pc_data (pc_data), + .clk (clk), + .i_en (en), + .i_jump (jump), + .i_offset (offset), + .o_rd (rd), + .o_i_dat (pc_data), .o_pc_valid (pc_valid), .i_pc_ready (pc_ready)); @@ -48,17 +54,16 @@ module serv_ctrl_tb; initial begin instruction = 32'h3d80006f; - instruction = 32'h0080706f; - reg11 = instruction[20]; - reg2012 = {instruction[31],instruction[19:12]}; + //instruction = 32'h0080706f; offset = {instruction[31], instruction[19:12], instruction[20], instruction[30:21],1'b0}; $display("Reconstructured offset %08x", offset); + en <= 1'b1; for (idx=0;idx < 31;idx=idx+1) begin - go <= (idx == 19); //Check this + go <= (idx == 20); //Check this instr <= instruction[idx]; jal <= (idx > 7); if (reg2012_en) reg2012 <= (reg2012 >> 1); diff --git a/bench/serv_decode_tb.v b/bench/serv_decode_tb.v new file mode 100644 index 0000000..8189999 --- /dev/null +++ b/bench/serv_decode_tb.v @@ -0,0 +1,55 @@ +`default_nettype none +module serv_decode_tb; + reg clk = 1'b1; + + reg [31:0] i_rd_dat = 32'd0; + reg i_rd_vld = 1'b0; + wire i_rd_rdy; + + wire ctrl_en; + wire ctrl_jump; + wire [4:0] rd_addr; + wire [4:0] rs1_addr; + wire [4:0] rs2_addr; + wire imm; + wire offset_source; + wire [1:0] rd_source; + + reg [31:0] tb_imm; + + always #5 clk <= !clk; + + vlog_tb_utils vtu(); + + serv_decode decode + ( + .clk (clk), + .i_i_rd_dat (i_rd_dat), + .i_i_rd_vld (i_rd_vld), + .o_i_rd_rdy (i_rd_rdy), + .o_ctrl_en (ctrl_en), + .o_ctrl_jump (ctrl_jump), + .o_rf_rd_addr (rd_addr), + .o_rf_rs1_addr (rs1_addr), + .o_rf_rs2_addr (rs2_addr), + .o_imm (imm), + .o_offset_source (offset_source), + .o_rd_source (rd_source)); + + initial begin + @(posedge clk); + i_rd_dat <= 32'h3d80006f; + i_rd_vld <= 1'b1; + @(posedge clk); + @(posedge i_rd_rdy); + @(posedge clk); + $display("imm = %08x", tb_imm); + + $finish; + end + always @(posedge clk) begin + if (ctrl_en) + tb_imm <= {imm, tb_imm[31:1]}; + end + +endmodule diff --git a/bench/serv_top_tb.v b/bench/serv_top_tb.v new file mode 100644 index 0000000..281ec88 --- /dev/null +++ b/bench/serv_top_tb.v @@ -0,0 +1,92 @@ +`default_nettype none +module serv_top_tb; + reg clk = 1'b1; + + wire [31:0] i_ca_adr; + wire i_ca_vld; + wire i_ca_rdy; + wire [31:0] i_rd_dat; + wire i_rd_vld; + wire i_rd_rdy; + + wire d_ca_cmd; + wire [31:0] d_ca_adr; + wire d_ca_vld; + wire d_ca_rdy; + wire [31:0] d_dm_dat; + wire [3:0] d_dm_msk; + wire d_dm_vld; + wire d_dm_rdy; + wire [31:0] d_rd_dat; + wire d_rd_vld; + wire d_rd_rdy; + + reg [1023:0] firmware_file; + + reg [31:0] pc; + reg [31:0] instruction; + + always #5 clk <= !clk; + + camd_ram + #(.memfile ("firmware.hex"), + .depth (16384*4)) + i_mem + (.clk_i (clk), + .rst_i (1'b0), + .ca_adr_i (i_ca_adr), + .ca_cmd_i (1'b0/*i_ca_cmd*/), + .ca_vld_i (i_ca_vld), + .ca_rdy_o (i_ca_rdy), + .dm_dat_i (/*i_dm_dat*/), + .dm_msk_i (/*i_dm_msk*/), + .dm_vld_i (/*i_dm_vld*/), + .dm_rdy_o (/*i_dm_rdy*/), + .rd_dat_o (i_rd_dat), + .rd_vld_o (i_rd_vld), + .rd_rdy_i (i_rd_rdy)); + + camd_ram + #(.memfile ("firmware.hex"), + .depth (16384*4)) + d_mem + (.clk_i (clk), + .rst_i (1'b0), + .ca_adr_i (d_ca_adr), + .ca_cmd_i (d_ca_cmd), + .ca_vld_i (d_ca_vld), + .ca_rdy_o (d_ca_rdy), + .dm_dat_i (d_dm_dat), + .dm_msk_i (d_dm_msk), + .dm_vld_i (d_dm_vld), + .dm_rdy_o (d_dm_rdy), + .rd_dat_o (d_rd_dat), + .rd_vld_o (d_rd_vld), + .rd_rdy_i (d_rd_rdy)); + + vlog_tb_utils vtu(); + + serv_top + #(.RESET_PC (32'd8)) + dut + ( + .clk (clk), + .o_i_ca_adr (i_ca_adr), + .o_i_ca_vld (i_ca_vld), + .i_i_ca_rdy (i_ca_rdy), + .i_i_rd_dat (i_rd_dat), + .i_i_rd_vld (i_rd_vld), + .o_i_rd_rdy (i_rd_rdy), + .o_d_ca_cmd (d_ca_cmd), + .o_d_ca_adr (d_ca_adr), + .o_d_ca_vld (d_ca_vld), + .i_d_ca_rdy (d_ca_rdy), + .o_d_dm_dat (d_dm_dat), + .o_d_dm_msk (d_dm_msk), + .o_d_dm_vld (d_dm_vld), + .i_d_dm_rdy (d_dm_rdy), + .i_d_rd_dat (d_rd_dat), + .i_d_rd_vld (d_rd_vld), + .o_d_rd_rdy (d_rd_rdy)); + +endmodule diff --git a/data/dummy.pcf b/data/dummy.pcf new file mode 100644 index 0000000..e69de29 diff --git a/rtl/camd_ram.v b/rtl/camd_ram.v new file mode 100644 index 0000000..66deec5 --- /dev/null +++ b/rtl/camd_ram.v @@ -0,0 +1,55 @@ +module camd_ram + #(//camd parameters + parameter AW = 32, + parameter DW = 32, + //Memory parameters + parameter depth = 256, + parameter aw = $clog2(depth), + parameter memfile = "") + (input clk_i, + input rst_i, + + input [AW-1:0] ca_adr_i, //FIXME width = AW-clog2(WB_DW/8) + input ca_cmd_i, + input ca_vld_i, + output ca_rdy_o, + + input [DW-1:0] dm_dat_i, + input [DW/8-1:0] dm_msk_i, + input dm_vld_i, + output dm_rdy_o, + + output [DW-1:0] rd_dat_o, + output reg rd_vld_o, + input rd_rdy_i); + + wire ca_en = ca_vld_i & ca_rdy_o; + wire dm_en = dm_vld_i & dm_rdy_o; + wire ram_we = ca_en & dm_en; + + assign ca_rdy_o = 1'b1; + assign dm_rdy_o = 1'b1; + + wire [aw-1:2] raddr; + reg [aw-1:2] latched_raddr; + assign raddr = ca_en ? ca_adr_i[aw-1:2] : latched_raddr; + + always @(posedge clk_i) begin + if (ca_en) + latched_raddr <= ca_adr_i[aw-1:2]; + rd_vld_o <= 1'b0; + if (ca_en & !ca_cmd_i) + rd_vld_o <= 1'b1; + end + wb_ram_generic + #(.depth(depth/4), + .memfile (memfile)) + ram0 + (.clk (clk_i), + .we ({4{ram_we}} & dm_msk_i), + .din (dm_dat_i), + .waddr (ca_adr_i[aw-1:2]), + .raddr (raddr), + .dout (rd_dat_o)); + +endmodule diff --git a/rtl/ser_add.v b/rtl/ser_add.v index d1913ec..798c040 100644 --- a/rtl/ser_add.v +++ b/rtl/ser_add.v @@ -1,17 +1,15 @@ module ser_add ( - input clk, - input a, - input b, - input clear, - output reg q = 1'b0); + input clk, + input a, + input b, + input clr, + output q); - reg carry = 1'b0; - wire c = carry & ~clear; + reg c = 1'b0; - always @(posedge clk) begin - q <= a ^ b ^ c; - carry <= a&b | a&c | b&c; - end + assign q = a ^ b ^ c; + always @(posedge clk) + c <= !clr & (a&b | a&c | b&c); endmodule diff --git a/rtl/serv_alu.v b/rtl/serv_alu.v index 96ac6b9..c1bb7e1 100644 --- a/rtl/serv_alu.v +++ b/rtl/serv_alu.v @@ -1,14 +1,12 @@ `default_nettype none module serv_alu ( - input clk, - input i_d, - input i_go, - input i_funct3_valid, - input i_rs1, - output o_rs_en, - output o_rd, - output o_rd_valid); + input clk, + input i_en, + input [2:0] i_funct3, + input i_rs1, + input i_op_b, + output o_rd); localparam [2:0] ADDI = 3'b000, @@ -18,52 +16,17 @@ module serv_alu ORI = 3'b110, ANDI = 3'b111; - wire [2:0] funct3; - - shift_reg #(3) shift_reg_funct3 - ( - .clk (clk), - .i_d (i_d), - .i_en (i_funct3_valid), - .o_q (funct3[0]), - .o_par (funct3[2:1])); - - wire op_b; wire result_add; - assign op_b = i_d; //FIXME mux for rs2 - - assign o_rs_en = running; - ser_add ser_add ( - .clk (clk), - .a (i_rs1), - .b (op_b), - .clear (i_go), - .q (result_add)); + .clk (clk), + .a (i_rs1), + .b (i_op_b), + .clr (!i_en), + .q (result_add)); - assign o_rd = (funct3 == ADDI) ? result_add : 1'b0; - assign o_rd_valid = (cnt > 0); + assign o_rd = (i_funct3 == ADDI) ? result_add : 1'b0; - reg [5:0] cnt = 6'd0; - reg done; - reg running = 1'd0; - - always @(posedge clk) begin - cnt <= 6'd0; - done <= 1'b0; - - if (i_go) - running <= 1'b1; - else if (cnt == 32) begin - running <= 1'b0; - done <= 1'b1; - end - - if (running) begin - cnt <= cnt + 1; - end - end endmodule diff --git a/rtl/serv_ctrl.v b/rtl/serv_ctrl.v index 38ad23a..5aafde1 100644 --- a/rtl/serv_ctrl.v +++ b/rtl/serv_ctrl.v @@ -2,56 +2,36 @@ module serv_ctrl ( input clk, - input i_go, - input i_instr, - input i_jal, - input i_reg11, - input i_reg2012, - output o_reg2012_en, + input i_en, + input i_jump, + input i_offset, output o_rd, - output o_rd_valid, - output [31:0] o_pc_data, - output reg o_pc_valid = 1'b1, - input i_pc_ready); + output [31:0] o_i_ca_adr, + output reg o_i_ca_vld = 1'b0, + input i_i_ca_rdy); parameter RESET_PC = 32'd8; - localparam [2:0] - NULL = 3'd0, - INSTR = 3'd1, - REG11 = 3'd2, - REG2012 = 3'd3, - SIGNBIT = 3'd4; - - wire offset; - - reg signbit = 1'd0; - - reg [5:0] cnt = 5'd0; - - reg new_pc_sel = 1'b0; wire pc_plus_4; wire pc_plus_offset; - reg pc_plus_offset_clr = 1'b0; wire plus_4; - wire pc_plus_4_clr; - reg running = 1'b0; + wire pc; + wire new_pc; - reg [2:0] offset_source; - - assign pc_plus_4_clr = (cnt == 0); - assign plus_4 = (cnt == 2); + assign plus_4 = en_2r & !en_3r; + assign o_i_ca_adr[0] = pc; + ser_add ser_add_pc_plus_4 ( - .clk (clk), - .a (plus_4), - .b (o_pc_data[0]), - .clear (pc_plus_4_clr), - .q (pc_plus_4)); + .clk (clk), + .a (pc), + .b (plus_4), + .clr (!i_en), + .q (pc_plus_4)); shift_reg #( @@ -60,71 +40,36 @@ module serv_ctrl pc_reg ( .clk (clk), - .i_en (running), + .i_en (i_en), .i_d (new_pc), - .o_q (o_pc_data[0]), - .o_par (o_pc_data[31:1]) + .o_q (pc), + .o_par (o_i_ca_adr[31:1]) ); - assign new_pc = new_pc_sel ? pc_plus_offset : pc_plus_4; - + assign new_pc = i_jump ? pc_plus_offset : pc_plus_4; assign o_rd = pc_plus_4; - assign o_rd_valid = running & i_jal; - always @(cnt, i_jal, running) begin - offset_source = NULL; - new_pc_sel = 1'b0; - if (i_jal) begin - new_pc_sel = 1'b1; - if (cnt < 10) - offset_source = INSTR; - else if (cnt < 11) - offset_source = REG11; - else if (cnt < 20) - offset_source = REG2012; - else - offset_source = SIGNBIT; - end - end - - wire o_reg11_en = (offset_source == REG11); - wire o_reg2012_en = (offset_source == REG2012); - - assign offset = (offset_source == INSTR) ? i_instr : - (offset_source == REG11) ? i_reg11 : - (offset_source == REG2012) ? i_reg2012 : - (offset_source == SIGNBIT) ? signbit : - 1'b0; - ser_add ser_add_pc_plus_offset ( - .clk (clk), - .a (o_pc_data[0]), //FIXME Need a mux before this - .b (offset), - .clear (pc_plus_offset_clr), - .q (pc_plus_offset)); + .clk (clk), + .a (pc), + .b (i_offset), + .clr (!i_en), + .q (pc_plus_offset)); - reg done = 1'b0; + reg en_r = 1'b1; + reg en_2r = 1'b0; + reg en_3r = 1'b0; always @(posedge clk) begin - cnt <= 6'd0; - done <= 1'b0; - - if (i_go) - running <= 1'b1; - else if (cnt == 32) begin - running <= 1'b0; - done <= 1'b1; - end - - if (running) begin - cnt <= cnt + 1; - end + en_r <= i_en; + en_2r <= en_r; + en_3r <= en_2r; - if (done) - o_pc_valid <= 1'b1; - if (o_pc_valid & i_pc_ready) - o_pc_valid <= 1'b0; + if (en_r & !i_en) + o_i_ca_vld <= 1'b1; + else if (o_i_ca_vld & i_i_ca_rdy) + o_i_ca_vld <= 1'b0; end endmodule diff --git a/rtl/serv_decode.v b/rtl/serv_decode.v index 75ba02f..9e4facb 100644 --- a/rtl/serv_decode.v +++ b/rtl/serv_decode.v @@ -1,67 +1,129 @@ module serv_decode ( - input clk, - input i_go, - input i_instr, - output o_imm_31_12, - output o_imm_11_0, - output o_rd, - output o_field_rs2, - output o_field_rs1, - output o_funct3, - output o_funct7, - output o_jal, - output o_opimm, - output o_alu_go, - output o_ctrl_go); + input clk, + input [31:0] i_i_rd_dat, + input i_i_rd_vld, + output reg o_i_rd_rdy = 1'b1, + output o_ctrl_en, + output o_ctrl_jump, + output [2:0] o_funct3, + output o_rf_rd_en, + output [4:0] o_rf_rd_addr, + output o_rf_rs_en, + output [4:0] o_rf_rs1_addr, + output [4:0] o_rf_rs2_addr, + output o_mem_en, + output o_mem_init, + output o_mem_dat_valid, + input i_mem_busy, + output reg o_imm, + output o_offset_source, + output o_op_b_source, + output [1:0] o_rd_source); +`include "serv_params.vh" + + + localparam [1:0] + IDLE = 2'd0, + MEM_INIT = 2'd1, + MEM_WAIT = 2'd2, + RUN = 2'd3; + localparam [4:0] + OP_LOAD = 5'b00000, OP_OPIMM = 5'b00100, + OP_LUI = 5'b01101, OP_JAL = 5'b11011; + reg [1:0] state = 2'd0; - reg [8:0] barrel [0:31]; - reg [4:0] cnt = 5'd0; - reg running = 1'b0; + reg [4:0] cnt = 5'd0; - wire opcode_valid; - wire halt; + wire running; + wire mem_op; + assign mem_op = (opcode == OP_LOAD); + + assign o_ctrl_en = running; + assign o_ctrl_jump = (opcode == OP_JAL); + + assign o_rf_rd_en = running & ((opcode == OP_JAL) | + (opcode == OP_OPIMM) | + (opcode == OP_LUI)); + assign o_rf_rs_en = (running & (opcode == OP_OPIMM)) | + (state == MEM_INIT); + assign o_mem_en = mem_op & cnt_en; + assign o_mem_init = (state == MEM_INIT); + + assign o_rf_rd_addr = i_i_rd_dat[11:7]; + assign o_funct3 = i_i_rd_dat[14:12]; + assign o_rf_rs1_addr = i_i_rd_dat[19:15]; + assign o_rf_rs2_addr = i_i_rd_dat[24:20]; + assign o_offset_source = (opcode == OP_JAL) ? OFFSET_SOURCE_IMM : 1'b0; + + assign o_op_b_source = (opcode == OP_OPIMM) ? OP_B_SOURCE_IMM : 1'b0; + + assign o_mem_dat_valid = (o_funct3[1:0] == 2'b00) ? cnt < 8 : + (o_funct3[1:0] == 2'b01) ? cnt < 16 : 1'b1; + wire [4:0] opcode = i_i_rd_dat[6:2]; - wire [8:0] cur = barrel[cnt]; + + assign o_rd_source = (opcode == OP_JAL) ? RD_SOURCE_CTRL : + (opcode == OP_OPIMM) ? RD_SOURCE_ALU : + (opcode == OP_LUI) ? RD_SOURCE_IMM : 2'b00; - assign o_imm_31_12 = cur[8]; - assign o_imm_11_0 = cur[7]; - assign o_rd = cur[6]; - assign o_field_rs2 = cur[5] & (1'b0); - assign o_field_rs1 = cur[4] & (1'b0); - assign o_funct3 = cur[3]; - assign o_funct7 = cur[2]; - assign opcode_valid = cur[1]; - assign halt = cur[0]; - - initial begin - $readmemb("decode.mem", barrel); + always @(cnt, opcode) begin + o_imm = 1'bx; + if (opcode == OP_JAL) + if (cnt > 19) o_imm = i_i_rd_dat[31]; + else if (cnt > 11) o_imm = i_i_rd_dat[cnt]; + else if (cnt > 10) o_imm = i_i_rd_dat[20]; + else if (cnt > 0) o_imm = i_i_rd_dat[cnt+20]; + else o_imm = 1'b0; + else if (opcode == OP_OPIMM) + if (cnt > 10) o_imm = i_i_rd_dat[31]; + else o_imm = i_i_rd_dat[cnt+20]; + else if (opcode == OP_LUI) + if (cnt > 11) o_imm = i_i_rd_dat[cnt]; + else o_imm = 1'b0; + else if (opcode == OP_LOAD) + if (cnt > 10) o_imm = i_i_rd_dat[31]; + else o_imm = i_i_rd_dat[cnt+20]; end - reg [4:0] opcode = 5'd0; - - assign o_jal = (opcode == OP_JAL); - assign o_ctrl_go = (cnt == 19); - assign o_opimm = (opcode == OP_OPIMM); - assign o_alu_go = o_opimm & (cnt == 19); + wire go = i_i_rd_vld & o_i_rd_rdy; + + wire cnt_en = (state == RUN) | (state == MEM_INIT); + + wire cnt_done = cnt == 31; + assign running = (state == RUN); -// shift_reg #(5) shift_reg_opcode - always @(posedge clk) begin - if (opcode_valid) - opcode <= {opcode[3:0], i_instr}; - cnt <= cnt + (i_go | running); - if (i_go) - running <= 1'd1; - else if (halt) begin - running <= 1'd0; - cnt <= 1'b0; + state <= state; + case (state) + IDLE : begin + if (go) + state <= mem_op ? MEM_INIT : RUN; + end + MEM_INIT : + if (cnt_done) + state <= MEM_WAIT; + MEM_WAIT : + if (!i_mem_busy) + state <= RUN; + RUN : begin + if (cnt_done) + state <= IDLE; + end + endcase + + cnt <= cnt + {4'd0,cnt_en}; + + if (go) begin + o_i_rd_rdy <= 1'b0; + end else if (cnt_done & (state == RUN)) begin + o_i_rd_rdy <= 1'b1; end end diff --git a/rtl/serv_mem_if.v b/rtl/serv_mem_if.v new file mode 100644 index 0000000..61a5b2f --- /dev/null +++ b/rtl/serv_mem_if.v @@ -0,0 +1,87 @@ +`default_nettype none +module serv_mem_if + ( + input i_clk, + input i_en, + input i_init, + input i_dat_valid, + input i_cmd, + input [2:0] i_funct3, + input i_rs1, + input i_rs2, + input i_imm, + output o_rd, + output reg o_busy = 1'b0, + //External interface + output o_d_ca_cmd, + output [31:0] o_d_ca_adr, + output reg o_d_ca_vld = 1'b0, + input i_d_ca_rdy, + output [31:0] o_d_dm_dat, + output [3:0] o_d_dm_msk, + output o_d_dm_vld, + input i_d_dm_rdy, + input [31:0] i_d_rd_dat, + input i_d_rd_vld, + output o_d_rd_rdy); + + reg en_r; + wire adr; + reg [31:0] dat = 32'd0; + reg signbit = 1'b0; + + ser_add ser_add_rs1_plus_imm + ( + .clk (i_clk), + .a (i_rs1), + .b (i_imm), + .clr (!i_en), + .q (adr)); + + shift_reg #(32) shift_reg_adr + ( + .clk (i_clk), + .i_en (i_en), + .i_d (adr), + .o_q (o_d_ca_adr[0]), + .o_par (o_d_ca_adr[31:1]) + ); + + assign o_d_ca_cmd = i_cmd; + + wire is_signed = i_funct3[2]; + assign o_rd = i_dat_valid ? dat[0] : is_signed & signbit; + + assign o_d_rd_rdy = !i_en; //Likely bug, but probably doesn't matter + + wire is_half = i_funct3[1]; + wire is_byte = !(|i_funct3[1:0]); + wire [1:0] bytepos = o_d_ca_adr[3:2]; + wire upper_half = bytepos[1]; + + always @(posedge i_clk) begin + signbit <= dat[0]; + + if (i_en & i_init) + o_busy <= 1'b1; + else if (i_d_rd_vld & o_d_rd_rdy) begin + dat[31:16] <= i_d_rd_dat[31:16]; + dat[15:8] <= (is_half & upper_half) ? i_d_rd_dat[31:24] : i_d_rd_dat[15:8]; + dat[7:0] <= (is_byte & (bytepos == 2'b11)) ? i_d_rd_dat[31:24] : + (is_byte & (bytepos == 2'b10)) ? i_d_rd_dat[23:16] : + (is_half & upper_half) ? i_d_rd_dat[23:16] : + (is_byte & (bytepos == 2'b01)) ? i_d_rd_dat[15:8] : + i_d_rd_dat[7:0]; + o_busy <= 1'b0; + end + + en_r <= i_en; + if (o_d_ca_vld & i_d_ca_rdy) + o_d_ca_vld <= 1'b0; + else if (en_r & !i_en) + o_d_ca_vld <= 1'b1; + + if (i_en) + dat <= {i_rs2,dat[31:1]}; + end +endmodule diff --git a/rtl/serv_params.vh b/rtl/serv_params.vh new file mode 100644 index 0000000..d911e2e --- /dev/null +++ b/rtl/serv_params.vh @@ -0,0 +1,14 @@ +localparam [1:0] + RD_SOURCE_CTRL = 2'd0, + RD_SOURCE_ALU = 2'd1, + RD_SOURCE_IMM = 2'd2, + RD_SOURCE_MEM = 2'd3; + +localparam [0:0] + OFFSET_SOURCE_IMM = 1'd0, + OFFSET_SOURCE_RD = 1'd1; + +localparam [0:0] + OP_B_SOURCE_IMM = 1'd0, + OP_B_SOURCE_RS2 = 1'd1; + diff --git a/rtl/serv_regfile.v b/rtl/serv_regfile.v index b1ac48f..af0cadd 100644 --- a/rtl/serv_regfile.v +++ b/rtl/serv_regfile.v @@ -1,34 +1,20 @@ `default_nettype none module serv_regfile ( - input clk, - input i_d, - input i_field_rs1, - input i_field_rs2, - input i_field_rd, - input i_rs_en, - output o_rs1, - output o_rs2, - input i_rd, - input i_rd_valid); + input i_clk, + input i_rd_en, + input [4:0] i_rd_addr, + input i_rd, + input [4:0] i_rs1_addr, + input [4:0] i_rs2_addr, + input i_rs_en, + output o_rs1, + output o_rs2); - reg [31:0] rf [0:31]; + //reg [31:0] rf [0:31]; - function automatic [31:0] xreg; - input [4:0] regnum; - begin - xreg = {rf[31][regnum],rf[30][regnum],rf[29][regnum],rf[28][regnum], - rf[27][regnum],rf[26][regnum],rf[25][regnum],rf[24][regnum], - rf[23][regnum],rf[22][regnum],rf[21][regnum],rf[20][regnum], - rf[19][regnum],rf[18][regnum],rf[17][regnum],rf[16][regnum], - rf[15][regnum],rf[14][regnum],rf[13][regnum],rf[12][regnum], - rf[11][regnum],rf[10][regnum],rf[9][regnum] ,rf[8][regnum], - rf[7][regnum] ,rf[6][regnum] ,rf[5][regnum] ,rf[4][regnum], - rf[3][regnum] ,rf[2][regnum] ,rf[1][regnum] ,rf[0][regnum]}; - end - endfunction // xreg - - always @(*) +`ifndef SYNTHESIS +/* always @(*) for (i=0;i<32;i=i+1) begin dbg_x1[i] = rf[i][1]; dbg_x2[i] = rf[i][2]; @@ -62,7 +48,7 @@ module serv_regfile dbg_x30[i] = rf[i][30]; dbg_x31[i] = rf[i][31]; end - + */ reg [31:0] dbg_x0 ; reg [31:0] dbg_x1 ; reg [31:0] dbg_x2 ; @@ -96,52 +82,62 @@ module serv_regfile reg [31:0] dbg_x30; reg [31:0] dbg_x31; - - - reg [4:0] raddr = 5'd0; - reg [4:0] waddr = 5'd0; - reg [31:0] rs = 32'd0; - integer i; - initial for (i=0; i<32; i=i+1) rf[i] = 0; +// initial for (i=0; i<32; i=i+1) rf[i] = 0; + `endif - always @(posedge clk) begin - if (i_rd_valid) begin + reg [4:0] raddr = 5'd1; + reg [4:0] waddr = 5'd0; +// reg [31:0] rs = 32'd0; + wire [31:0] rs; + + reg [31:0] mask; + + always @(i_rd_addr) + mask = ~(1 << i_rd_addr); + + SB_RAM40_4K rf0 + ( + .RDATA (rs[15:0]), + .RCLK (i_clk), + .RCLKE (1'b1), + .RE (1'b1), + .RADDR ({6'd0,raddr2}), + .WCLK (i_clk), + .WCLKE (1'b1), + .WE (i_rd_en), + .WADDR ({6'd0,waddr}), + .MASK (mask[15:0]), + .WDATA ({16{i_rd}}) + ); + + SB_RAM40_4K rf1 + ( + .RDATA (rs[31:16]), + .RCLK (i_clk), + .RCLKE (1'b1), + .RE (1'b1), + .RADDR ({6'd0,raddr2}), + .WCLK (i_clk), + .WCLKE (1'b1), + .WE (i_rd_en), + .WADDR ({6'd0,waddr}), + .MASK (mask[31:16]), + .WDATA ({16{i_rd}}) + ); + always @(posedge i_clk) begin + if (i_rd_en) begin waddr <= waddr + 1; - rf[waddr][rd_addr] <= i_rd; + //rf[waddr][i_rd_addr] <= i_rd; end if (i_rs_en) - rs <= rf[raddr]; - + raddr <= raddr + 1; + //rs <= rf[raddr2]; end - - wire [4:0] rs1_addr; - wire [4:0] rs2_addr; - wire [4:0] rd_addr; + wire [4:0] raddr2 = raddr & {5{i_rs_en}}; - shift_reg #(5) shift_reg_rs1_addr - (.clk (clk), - .i_en (i_field_rs1), - .i_d (i_d), - .o_q (rs1_addr[0]), - .o_par (rs1_addr[4:1])); - - shift_reg #(5) shift_reg_rs2_addr - (.clk (clk), - .i_en (i_field_rs2), - .i_d (i_d), - .o_q (rs2_addr[0]), - .o_par (rs2_addr[4:1])); - - shift_reg #(5) shift_reg_rd_addr - (.clk (clk), - .i_en (i_field_rd), - .i_d (i_d), - .o_q (rd_addr[0]), - .o_par (rd_addr[4:1])); - - assign o_rs1 = (|rs1_addr) ? rs[rs1_addr] : 1'b0; - assign o_rs2 = (|rs2_addr) ? rs[rs2_addr] : 1'b0; + assign o_rs1 = (|i_rs1_addr) ? rs[i_rs1_addr] : 1'b0; + assign o_rs2 = (|i_rs2_addr) ? rs[i_rs2_addr] : 1'b0; endmodule diff --git a/rtl/serv_top.v b/rtl/serv_top.v index fe8d826..4cfdadd 100644 --- a/rtl/serv_top.v +++ b/rtl/serv_top.v @@ -2,125 +2,154 @@ module serv_top ( input clk, - input [31:0] i_i_data, - input i_i_valid, - output reg o_i_ready = 1'b1, - output [31:0] o_pc_data, - output o_pc_valid, - input i_pc_ready); + output [31:0] o_i_ca_adr, + output o_i_ca_vld, + input i_i_ca_rdy, + input [31:0] i_i_rd_dat, + input i_i_rd_vld, + output o_i_rd_rdy, + output o_d_ca_cmd, + output [31:0] o_d_ca_adr, + output o_d_ca_vld, + input i_d_ca_rdy, + output [31:0] o_d_dm_dat, + output [3:0] o_d_dm_msk, + output o_d_dm_vld, + input i_d_dm_rdy, + input [31:0] i_d_rd_dat, + input i_d_rd_vld, + output o_d_rd_rdy); - reg [31:0] cur_instr = 32'd0; - reg instr; - wire imm_31_12; - wire imm_11_0; - wire field_rd; - wire field_rs1; - wire field_rs2; - wire funct3; - wire funct7; - reg decode_go = 1'b0; - wire ctrl_go; - wire alu_go; - wire rs_en; - wire rs1; - wire rs2; - wire rd; +`include "serv_params.vh" - wire ctrl_rd; - wire ctrl_rd_valid; + wire [4:0] rd_addr; + wire [4:0] rs1_addr; + wire [4:0] rs2_addr; - wire alu_rd; - wire alu_rd_valid; + wire [1:0] rd_source; + wire ctrl_rd; + wire alu_rd; + wire mem_rd; + wire rd; - wire funct3_valid; + wire ctrl_en; + wire jump; + wire offset; + wire offset_source; + wire imm; + + wire [2:0] funct3; - wire jal; - wire opimm; + wire rs1; + wire rs2; + wire rs_en; + wire rd_en; + + wire op_b_source; + wire op_b; + + wire mem_en; + + wire mem_cmd = 1'b0 /*FIXME*/; + wire mem_dat_valid; + + wire mem_init; + wire mem_busy; + + parameter RESET_PC = 32'd8; serv_decode decode - ( - .clk (clk), - .i_instr (cur_instr[0]), - .i_go (decode_go), - .o_funct7 (funct7), - .o_funct3 (funct3_valid), - .o_field_rs1 (field_rs1), - .o_field_rs2 (field_rs2), - .o_rd (field_rd), - .o_imm_11_0 (imm_11_0), - .o_imm_31_12 (imm_31_12), - .o_jal (jal), - .o_opimm (opimm), - .o_alu_go (alu_go), - .o_ctrl_go (ctrl_go)); - - wire reg_2012_en_decode; - wire reg_2012_en_ctrl; - wire reg_2012_data; - - wire reg_2012_en = reg_2012_en_decode | reg_2012_en_ctrl; - - shift_reg - #( - .LEN (9)) - reg_2012 ( .clk (clk), - .i_en (reg_2012_en), - .i_d (cur_instr[0]), - .o_q (reg_2012_data)); + .i_i_rd_dat (i_i_rd_dat), + .i_i_rd_vld (i_i_rd_vld), + .o_i_rd_rdy (o_i_rd_rdy), + .o_ctrl_en (ctrl_en), + .o_ctrl_jump (jump), + .o_funct3 (funct3), + .o_rf_rd_en (rd_en), + .o_rf_rd_addr (rd_addr), + .o_rf_rs_en (rs_en), + .o_rf_rs1_addr (rs1_addr), + .o_rf_rs2_addr (rs2_addr), + .o_mem_en (mem_en), + .o_mem_init (mem_init), + .o_mem_dat_valid (mem_dat_valid), + .i_mem_busy (mem_busy), + .o_imm (imm), + .o_offset_source (offset_source), + .o_op_b_source (op_b_source), + .o_rd_source (rd_source)); + serv_ctrl + #(.RESET_PC (RESET_PC)) + ctrl + ( + .clk (clk), + .i_en (ctrl_en), + .i_jump (jump), + .i_offset (offset), + .o_rd (ctrl_rd), + .o_i_ca_adr (o_i_ca_adr), + .o_i_ca_vld (o_i_ca_vld), + .i_i_ca_rdy (i_i_ca_rdy)); + + assign offset = (offset_source == OFFSET_SOURCE_IMM) ? imm : rs1; + + assign rd = (rd_source == RD_SOURCE_CTRL) ? ctrl_rd : + (rd_source == RD_SOURCE_ALU) ? alu_rd : + (rd_source == RD_SOURCE_IMM) ? imm : + (rd_source == RD_SOURCE_MEM) ? mem_rd : 1'b0; + + + assign op_b = (op_b_source == OP_B_SOURCE_IMM) ? imm : + 1'b0; + serv_alu alu ( .clk (clk), - .i_go (alu_go), - .i_d (cur_instr[0]), - .i_funct3_valid (funct3_valid), + .i_en (ctrl_en), /*FIXME: Is this true?*/ + .i_funct3 (funct3), .i_rs1 (rs1), - .o_rs_en (rs_en), - .o_rd (alu_rd), - .o_rd_valid (alu_rd_valid)); - - serv_ctrl ctrl - ( - .clk (clk), - .i_go (ctrl_go), - .i_instr (cur_instr[0]), - .i_jal (jal), - .i_reg11 (1'b0), //FIXME - .i_reg2012 (reg_2012_data), - .o_reg2012_en (reg_2012_en_ctrl), - .o_rd (ctrl_rd), - .o_rd_valid (ctrl_rd_valid), - .o_pc_data (o_pc_data), - .o_pc_valid (o_pc_valid), - .i_pc_ready (i_pc_ready)); + .i_op_b (op_b), + .o_rd (alu_rd)); serv_regfile regfile ( - .clk (clk), - .i_d (cur_instr[0]), - .i_field_rs1 (field_rs1), - .i_field_rs2 (field_rs2), - .i_field_rd (field_rd), - .i_rs_en (rs_en), - .o_rs1 (rs1), - .o_rs2 (rs2), - .i_rd ((ctrl_rd & ctrl_rd_valid) | (alu_rd & alu_rd_valid)), - .i_rd_valid (ctrl_rd_valid | alu_rd_valid)); + .i_clk (clk), + .i_rd_en (rd_en), + .i_rd_addr (rd_addr), + .i_rd (rd), + .i_rs1_addr (rs1_addr), + .i_rs2_addr (rs2_addr), + .i_rs_en (rs_en), + .o_rs1 (rs1), + .o_rs2 (rs2)); + + serv_mem_if mem_if + ( + .i_clk (clk), + .i_en (mem_en), + .i_init (mem_init), + .i_dat_valid (mem_dat_valid), + .i_cmd (mem_cmd), + .i_funct3 (funct3), + .i_rs1 (rs1), + .i_rs2 (rs2), + .i_imm (imm), + .o_rd (mem_rd), + .o_busy (mem_busy), + //External interface + .o_d_ca_cmd (o_d_ca_cmd), + .o_d_ca_adr (o_d_ca_adr), + .o_d_ca_vld (o_d_ca_vld), + .i_d_ca_rdy (i_d_ca_rdy), + .o_d_dm_dat (o_d_dm_dat), + .o_d_dm_msk (o_d_dm_msk), + .o_d_dm_vld (o_d_dm_vld), + .i_d_dm_rdy (i_d_dm_rdy), + .i_d_rd_dat (i_d_rd_dat), + .i_d_rd_vld (i_d_rd_vld), + .o_d_rd_rdy (o_d_rd_rdy)); - always @(posedge clk) begin - decode_go <= 1'b0; - cur_instr <= {1'b0, cur_instr[31:1]}; - - if (o_pc_valid) - o_i_ready <= 1'b1; - - if (i_i_valid & o_i_ready) begin - cur_instr <= i_i_data; - o_i_ready <= 1'b0; - decode_go <= 1'b1; - end - end // always @ (posedge clk) - endmodule diff --git a/serv.core b/serv.core index 2ce370e..a2524d7 100644 --- a/serv.core +++ b/serv.core @@ -5,14 +5,18 @@ name : ::serv:0 filesets: core: files: + - rtl/camd_ram.v + - rtl/serv_params.vh : {is_include_file : true} - rtl/shift_reg.v - rtl/ser_add.v - rtl/serv_alu.v - - rtl/serv_decode.v - rtl/serv_ctrl.v + - rtl/serv_decode.v + - rtl/serv_mem_if.v - rtl/serv_regfile.v - rtl/serv_top.v file_type : verilogSource + depend : [wb_ram] ser_add_tb: files: @@ -25,20 +29,35 @@ filesets: - bench/serv_ctrl_tb.v : {file_type : verilogSource} depend : [vlog_tb_utils] + serv_decode_tb: + files: [bench/serv_decode_tb.v : {file_type : verilogSource}] + depend : [vlog_tb_utils] serv_top_tb: files: - firmware.hex : {copyto : firmware.hex, file_type : user} - - decode.mem : {copyto : decode.mem, file_type : user} - - serv_top_tb.v + - bench/serv_top_tb.v file_type : verilogSource - depend : [vlog_tb_utils] + depend : [vlog_tb_utils, "yosys:techlibs:ice40"] + pcf: + files: [data/dummy.pcf : {file_type : PCF}] targets: default: default_tool : icarus filesets : [core, tb] toplevel : serv_top_tb + synth: + default_tool : icestorm + filesets : [core, pcf] + toplevel : serv_top + lint: + default_tool : verilator + filesets : [core] + tools: + verilator: + mode : lint-only + toplevel : serv_top ser_add_tb: default_tool : icarus filesets: [core, ser_add_tb] @@ -49,6 +68,11 @@ targets: filesets : [core, serv_ctrl_tb] toplevel : serv_ctrl_tb + serv_decode_tb: + default_tool: icarus + filesets : [core, serv_decode_tb] + toplevel : serv_decode_tb + serv_top_tb: default_tool: icarus filesets : [core, serv_top_tb]