summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-02-16 20:55:24 +0200
committerKimplul <kimi.h.kuparinen@gmail.com>2025-02-16 20:55:24 +0200
commit82dec45fd786831f791b17b84aedb4d99b5ca25d (patch)
tree5b98b452edc749b938a67368c9020244ca40595e
parent0141d830f3326594f159c627dbbc284fdef27674 (diff)
downloadttarv32-82dec45fd786831f791b17b84aedb4d99b5ca25d.tar.gz
ttarv32-82dec45fd786831f791b17b84aedb4d99b5ca25d.zip
add initial risc-v -> tta translation block
-rw-r--r--.gitignore4
-rw-r--r--src/common.svh115
-rw-r--r--src/rv2insn.sv107
-rw-r--r--src/sched.sv12
-rw-r--r--tb/Makefile14
-rw-r--r--tb/data/rv2insn.S6
-rw-r--r--tb/rv2insn_tb.sv42
-rw-r--r--tb/sched_tb.sv84
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;