From 82dec45fd786831f791b17b84aedb4d99b5ca25d Mon Sep 17 00:00:00 2001
From: Kimplul <kimi.h.kuparinen@gmail.com>
Date: Sun, 16 Feb 2025 20:55:24 +0200
Subject: add initial risc-v -> tta translation block

---
 .gitignore        |   4 ++
 src/common.svh    | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/rv2insn.sv    | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/sched.sv      |  12 +++---
 tb/Makefile       |  14 +++++++
 tb/data/rv2insn.S |   6 +++
 tb/rv2insn_tb.sv  |  42 ++++++++++++++++++++
 tb/sched_tb.sv    |  84 +++++++--------------------------------
 8 files changed, 306 insertions(+), 78 deletions(-)
 create mode 100644 .gitignore
 create mode 100644 src/rv2insn.sv
 create mode 100644 tb/Makefile
 create mode 100644 tb/data/rv2insn.S
 create mode 100644 tb/rv2insn_tb.sv

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;
-- 
cgit v1.2.3