diff options
author | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-02-16 20:55:24 +0200 |
---|---|---|
committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2025-02-16 20:55:24 +0200 |
commit | 82dec45fd786831f791b17b84aedb4d99b5ca25d (patch) | |
tree | 5b98b452edc749b938a67368c9020244ca40595e | |
parent | 0141d830f3326594f159c627dbbc284fdef27674 (diff) | |
download | ttarv32-82dec45fd786831f791b17b84aedb4d99b5ca25d.tar.gz ttarv32-82dec45fd786831f791b17b84aedb4d99b5ca25d.zip |
add initial risc-v -> tta translation block
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | src/common.svh | 115 | ||||
-rw-r--r-- | src/rv2insn.sv | 107 | ||||
-rw-r--r-- | src/sched.sv | 12 | ||||
-rw-r--r-- | tb/Makefile | 14 | ||||
-rw-r--r-- | tb/data/rv2insn.S | 6 | ||||
-rw-r--r-- | tb/rv2insn_tb.sv | 42 | ||||
-rw-r--r-- | tb/sched_tb.sv | 84 |
8 files changed, 306 insertions, 78 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..116542f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +tb/rv2insn +tb/rv2insn.hex +tb/*.vcd +tb/*objdir diff --git a/src/common.svh b/src/common.svh index 42fdb71..67a87d2 100644 --- a/src/common.svh +++ b/src/common.svh @@ -1,6 +1,119 @@ `ifndef __COMMON_SVH__ `define __COMMON_SVH__ -`define NOP 0 +`define RV_OP_FIELD 6:0 +typedef logic [31:0] rv_t; +typedef logic [31:0] xlen_t; + +typedef struct packed { + logic [6:0] funct7; + logic [4:0] rs2; + logic [4:0] rs1; + logic [2:0] funct3; + logic [4:0] rd; + logic [6:0] op; +} rtype_t; + +typedef struct packed { + logic [11:0] imm; + logic [4:0] rs1; + logic [2:0] funct3; + logic [4:0] rd; + logic [6:0] op; +} itype_t; + +typedef struct packed { + logic [6:0] imm1; + logic [4:0] rs2; + logic [4:0] rs1; + logic [2:0] funct3; + logic [4:0] imm0; + logic [6:0] op; +} stype_t; + +typedef struct packed { + logic [0:0] imm3; + logic [5:0] imm2; + logic [4:0] rs2; + logic [4:0] rs1; + logic [2:0] funct3; + logic [3:0] imm1; + logic [0:0] imm0; + logic [6:0] op; +} btype_t; + +typedef struct packed { + logic [19:0] imm; + logic [4:0] rd; + logic [6:0] op; +} utype_t; + +typedef struct packed { + logic [0:0] imm3; + logic [9:0] imm2; + logic [0:0] imm1; + logic [7:0] imm0; + logic [4:0] rd; + logic [6:0] op; +} jtype_t; + +typedef enum logic [6:0] { + LOAD = 7'b0000011, + LOAD_FP = 7'b0000111, + MISC_MEM = 7'b0001111, + OP_IMM = 7'b0010011, + AUIPC = 7'b0010111, + OP_IMM_32 = 7'b0011011, + + STORE = 7'b0100011, + STORE_FP = 7'b0100111, + AMO = 7'b0101111, + OP = 7'b0110011, + LUI = 7'b0110111, + OP_32 = 7'b0111011, + + MADD = 7'b1000011, + MSUB = 7'b1000111, + NMSUB = 7'b1001011, + NMADD = 7'b1001111, + OP_FP = 7'b1010011, + + BRANCH = 7'b1100011, + JALR = 7'b1100111, + JAL = 7'b1101111, + SYSTEM = 7'b1110011 +} opcode_t; + +typedef logic[7:0] port_t; + +typedef enum port_t { + NOP = 8'b00000000, + REG = 8'b00100000, + ALU = 8'b01000000 +} port_base_t; + +typedef struct packed { + port_t src; + port_t dst; +} mov_t; + +typedef logic[7:0] op_t; +typedef logic[19:0] imm_t; + +typedef struct packed { + mov_t[1:0] in; + mov_t out; + op_t op; + imm_t imm; +} insn_t; + +typedef enum op_t { + ALU_ADD, + ALU_SUB, + ALU_ADDI +} alu_op_t; + +`define rn(r) (REG + port_t'(r)) +`define alu(fu) (ALU + port_t'(fu)) `endif /* __COMMON_SVH__ */ diff --git a/src/rv2insn.sv b/src/rv2insn.sv new file mode 100644 index 0000000..1d9996c --- /dev/null +++ b/src/rv2insn.sv @@ -0,0 +1,107 @@ +`include "common.svh" + +module rv2insn #( + parameter QUE_DEPTH, + parameter ALU_COUNT +)( + input clk_i, + input rst_ni, + input xlen_t pc_i, + input rv_t[QUE_DEPTH-1:0] rv_i, + output insn_t[QUE_DEPTH-1:0] que_o +); + +typedef logic[$clog2(ALU_COUNT):0] alu_counter_t; + +alu_counter_t alu_counter_r; +alu_counter_t alu_counter; + +typedef struct packed { + insn_t insn; + alu_counter_t alu_counter; +} decode_out_t; + +function automatic insn_t halt(); + /* TODO come up with some proper instruction here */ + return -1; +endfunction + +function automatic alu_counter_t next_alu(alu_counter_t alu_counter); + return (alu_counter + 1) % ALU_COUNT; +endfunction + +function automatic decode_out_t op_imm(xlen_t pc, itype_t rv, alu_counter_t alu_counter); + alu_counter_t fu = next_alu(alu_counter); + unique case (rv.funct3) + 3'b000: return {{NOP, NOP}, + {`rn(rv.rs1), `alu(fu)}, + {`alu(fu), `rn(rv.rd)}, + ALU_ADDI, imm_t'(signed'(rv.imm)), fu}; + + default: return {halt(), fu}; + endcase + + return 0; +endfunction + +function automatic decode_out_t op(xlen_t pc, rtype_t rv, alu_counter_t alu_counter); + alu_counter_t fu = next_alu(alu_counter); + unique case (rv.funct3) + 3'b000: begin + unique case (rv.funct7) + 7'b0000000: + return {{`rn(rv.rs1), `alu(fu)}, + {`rn(rv.rs2), `alu(fu)}, + {`alu(fu), `rn(rv.rd)}, + ALU_ADD, imm_t'(0), fu}; + 7'b0100000: + return {{`rn(rv.rs1), `alu(fu)}, + {`rn(rv.rs2), `alu(fu)}, + {`alu(fu), `rn(rv.rd)}, + ALU_SUB, imm_t'(0), fu}; + + default: return {halt(), fu}; + endcase + end + default: return {halt(), fu}; + endcase +endfunction + +function automatic decode_out_t decode(xlen_t pc, rv_t rv, alu_counter_t alu_counter); + unique case (rv[`RV_OP_FIELD]) + OP_IMM: return op_imm (pc, rv, alu_counter); + OP: return op (pc, rv, alu_counter); + default: return {halt(), alu_counter}; + endcase +endfunction + +typedef struct packed { + insn_t[QUE_DEPTH-1:0] que; + alu_counter_t alu_counter; +} stages_out_t; + +function automatic stages_out_t stages(int i, xlen_t pc, + rv_t[QUE_DEPTH-1:0] rv, insn_t[QUE_DEPTH-1:0] que, alu_counter_t alu_counter); + if (i < QUE_DEPTH) begin + decode_out_t out = decode(pc + i, rv[i], alu_counter); + que[i] = out.insn; + return stages(i + 1, pc, rv, que, out.alu_counter); + end else begin + return {que, alu_counter}; + end +endfunction + +always_comb begin + stages_out_t out = stages(0, pc_i, rv_i, '0, alu_counter_r); + alu_counter = out.alu_counter; + que_o = out.que; +end + +always_ff @(posedge clk_i or negedge rst_ni) begin + if (!rst_ni) begin + alu_counter_r <= 0; + end else begin + alu_counter_r <= alu_counter; + end +end +endmodule diff --git a/src/sched.sv b/src/sched.sv index c538dc2..16a1e54 100644 --- a/src/sched.sv +++ b/src/sched.sv @@ -5,9 +5,6 @@ module sched parameter QUE_DEPTH, parameter SLOT_COUNT, parameter SLOT_DEPTH, - type port_t, - type mov_t, - type insn_t, type slot_t )( input insn_t[QUE_DEPTH-1:0] que_i, @@ -28,7 +25,7 @@ endfunction function automatic logic check_dst(mov_t d1, mov_t[SLOT_DEPTH-1:0] d2); logic[SLOT_DEPTH-1:0] dep = '0; for (int i = 0; i < SLOT_DEPTH; ++i) begin - dep[i] = d1.dst != `NOP & d1.dst == d2[i].dst; + dep[i] = d1.dst != NOP & d1.dst == d2[i].dst; end return dep != 0; endfunction @@ -37,7 +34,7 @@ endfunction function automatic logic check_overlap(mov_t d1, mov_t[SLOT_DEPTH-1:0] d2); logic[SLOT_DEPTH-1:0] dep = '0; for (int i = 0; i < SLOT_DEPTH; ++i) begin - dep[i] = d1.src != `NOP & d1.src == d2[i].dst; + dep[i] = d1.src != NOP & d1.src == d2[i].dst; end return dep != 0; endfunction @@ -50,7 +47,7 @@ function automatic logic depends(insn_t i, slot_t[SLOT_COUNT-1:0] slots); logic overlap1 = check_overlap(i.in[0], slots[ii].out); logic overlap2 = check_overlap(i.in[1], slots[ii].out); - logic same_src1 = i.in[0].dst != `NOP + logic same_src1 = i.in[0].dst != NOP & i.in[0].dst == slots[ii].in[0].dst; /* op must have trigger so don't need to check against NOP */ @@ -62,7 +59,7 @@ function automatic logic depends(insn_t i, slot_t[SLOT_COUNT-1:0] slots); endfunction function automatic logic is_noop(mov_t m); - return m.src == `NOP && m.dst == `NOP; + return m.src == NOP && m.dst == NOP; endfunction function automatic mov_t[SLOT_DEPTH-1:0] place_out(int i, logic placed, @@ -80,6 +77,7 @@ endfunction function automatic slot_t place(insn_t i, slot_t src); slot_t slot; slot.op = i.op; + slot.imm = i.imm; slot.in = i.in; slot.out = place_out(0, 0, i.out, src.out); return slot; diff --git a/tb/Makefile b/tb/Makefile new file mode 100644 index 0000000..a76747f --- /dev/null +++ b/tb/Makefile @@ -0,0 +1,14 @@ +all: rv2insn sched + +.PHONY: sched +sched: sched_tb.sv ../src/sched.sv ../src/common.svh + verilator --Mdir sched_objdir --assert --trace --binary -I../src sched_tb.sv + ./sched_objdir/Vsched_tb + +.PHONY: rv2insn +rv2insn: rv2insn_tb.sv ../src/rv2insn.sv ../src/common.svh + riscv32-unknown-elf-gcc -ffreestanding -nostdlib -march=rv32i -mabi=ilp32 \ + -Wl,-Ttext=0 data/rv2insn.S -o rv2insn + riscv32-unknown-elf-objcopy -O verilog rv2insn rv2insn.hex + verilator --Mdir rv2insn_objdir --assert --trace --binary -I../src rv2insn_tb.sv + ./rv2insn_objdir/Vrv2insn_tb diff --git a/tb/data/rv2insn.S b/tb/data/rv2insn.S new file mode 100644 index 0000000..a0ee610 --- /dev/null +++ b/tb/data/rv2insn.S @@ -0,0 +1,6 @@ +.global _start +_start: +add x1, x2, x3 +addi x4, x5, 123 +sub x6, x7, x8 +addi x9, x10, -456 diff --git a/tb/rv2insn_tb.sv b/tb/rv2insn_tb.sv new file mode 100644 index 0000000..14a0249 --- /dev/null +++ b/tb/rv2insn_tb.sv @@ -0,0 +1,42 @@ +`include "common.svh" + +module rv2insn_tb; + +logic clk; +logic rst_n; + +xlen_t pc; +logic[7:0] rv[4*4]; +insn_t[3:0] que; + +function automatic rv_t[3:0] unp2p(logic[7:0] in[4*4]); + logic [15:0][7:0] conversion; + for (int i = 0; i < 4 * 4; ++i) begin + conversion[i] = in[i]; + end + return conversion; +endfunction + +rv2insn #( + .QUE_DEPTH(4), + .ALU_COUNT(2) +) rv2insn ( + .clk_i(clk), + .rst_ni(rst_n), + .pc_i(pc), + .rv_i(unp2p(rv)), + .que_o(que) +); + +initial begin + $dumpfile("rv2insn_tb.vcd"); + $dumpvars(); + $readmemh("rv2insn.hex", rv); + + clk = 0; + rst_n = 0; + + #10 rst_n = 1; + #10 $finish; +end +endmodule diff --git a/tb/sched_tb.sv b/tb/sched_tb.sv index 8db66b3..036464e 100644 --- a/tb/sched_tb.sv +++ b/tb/sched_tb.sv @@ -2,62 +2,11 @@ module sched_tb; -typedef enum logic [7:0] { - NOP = `NOP, - R0, - R1, - R2, - R3, - R4, - R5, - R6, - R7, - R8, - R9, - R10, - R11, - R12, - R13, - R14, - R15, - R16, - R17, - R18, - R19, - R20, - R21, - R22, - R23, - R24, - R25, - R26, - R27, - R28, - R29, - R30, - R31, - - ALU0, - ALU1 -} port_t; - -typedef logic [19:0] op_t; - -typedef struct packed { - port_t src; - port_t dst; -} mov_t; - -typedef struct packed { - mov_t[1:0] in; - mov_t out; - op_t op; -} insn_t; - typedef struct packed { mov_t[1:0] in; mov_t[0:0] out; op_t op; + imm_t imm; } slot_t; slot_t[1:0] prev_slots; @@ -69,9 +18,6 @@ sched #( .QUE_DEPTH(3), .SLOT_COUNT(2), .SLOT_DEPTH(1), - .port_t(port_t), - .mov_t(mov_t), - .insn_t(insn_t), .slot_t(slot_t) ) sched ( .que_i(prev_que), @@ -80,16 +26,14 @@ sched #( .slots_o(next_slots) ); -`define assert(signal, value) \ - if (signal !== value) begin \ - $error("%m: signal != value"); \ - end +slot_t[1:0] first_check = {76'b0, + {{`rn(2), `alu(0)}, {`rn(3), `alu(0)}, {`alu(0), `rn(1)}, 8'h1, 20'h123} + }; -slot_t[1:0] first_check = {68'b0, {R2, ALU0}, {R3, ALU0}, {ALU0, R1}, 20'h123}; slot_t[1:0] second_check = { - {{R2, ALU0}, {R1, ALU0}, {ALU0, R5}, 20'h789}, - {{R2, ALU1}, {R1, ALU1}, {ALU1, R4}, 20'h456} - }; + {{`rn(2), `alu(0)}, {`rn(1), `alu(0)}, {`alu(0), `rn(5)}, 8'h3, 20'h789}, + {{`rn(2), `alu(1)}, {`rn(1), `alu(1)}, {`alu(1), `rn(4)}, 8'h2, 20'h456} + }; initial begin $dumpfile("sched_tb.vcd"); @@ -105,12 +49,12 @@ initial begin * add r4, r2, r1 add r5, r2, r1 */ prev_que = { - /* src2, src1, out, op, apparently. Have to get used to - * systemverilog's way of laying out bits, huh. */ - {{R2, ALU0}, {R1, ALU0}, {ALU0, R5}, 20'h789}, - {{R2, ALU1}, {R1, ALU1}, {ALU1, R4}, 20'h456}, - {{R2, ALU0}, {R3, ALU0}, {ALU0, R1}, 20'h123} - /* also, 'reverse' order, first instruction at bottom */ + /* src2, src1, out, op, apparently. Have to get used to + * systemverilog's way of laying out bits, huh. */ + {{`rn(2), `alu(0)}, {`rn(1), `alu(0)}, {`alu(0), `rn(5)}, 8'h3, 20'h789}, + {{`rn(2), `alu(1)}, {`rn(1), `alu(1)}, {`alu(1), `rn(4)}, 8'h2, 20'h456}, + {{`rn(2), `alu(0)}, {`rn(3), `alu(0)}, {`alu(0), `rn(1)}, 8'h1, 20'h123} + /* also, 'reverse' order, first instruction at bottom */ }; prev_slots = '0; @@ -118,7 +62,7 @@ initial begin #10 assert (next_slots == first_check) - else $error("\nwanted:\t%h", first_check, "\ngot:%h\t", next_slots); + else $error("\nwanted:\t%h", first_check, "\ngot:\t%h", next_slots); /* pretend all operations finished */ prev_slots = '0; |