diff --git a/.gitattributes b/.gitattributes
index 7613e20..31ce160 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,4 +1,5 @@
fw/project/lcmxo2/*.sty linguist-generated
+fw/rtl/serv/* -linguist-vendored
fw/rtl/vendor/** -linguist-vendored
fw/rtl/vendor/lcmxo2/generated/* linguist-generated
hw/pcb/*.html linguist-generated
diff --git a/build.sh b/build.sh
index 1fde564..fd52d0d 100755
--- a/build.sh
+++ b/build.sh
@@ -29,6 +29,7 @@ FILES=(
BUILT_BOOTLOADER=false
BUILT_CONTROLLER=false
+BUILT_CIC=false
BUILT_FPGA=false
BUILT_UPDATE=false
BUILT_RELEASE=false
@@ -66,6 +67,19 @@ build_controller () {
BUILT_CONTROLLER=true
}
+build_cic () {
+ if [ "$BUILT_CIC" = true ]; then return; fi
+
+ pushd sw/cic > /dev/null
+ if [ "$FORCE_CLEAN" = true ]; then
+ ./build.sh clean
+ fi
+ ./build.sh all
+ popd > /dev/null
+
+ BUILT_CIC=true
+}
+
build_fpga () {
if [ "$BUILT_FPGA" = true ]; then return; fi
@@ -84,6 +98,7 @@ build_update () {
build_bootloader
build_controller
+ build_cic
build_fpga
pushd sw/tools > /dev/null
@@ -126,10 +141,11 @@ build_release () {
print_usage () {
echo "builder script for SC64"
- echo "usage: ./build.sh [bootloader] [controller] [fpga] [update] [release] [-c] [--help]"
+ echo "usage: ./build.sh [bootloader] [controller] [cic] [fpga] [update] [release] [-c] [--help]"
echo "parameters:"
echo " bootloader - compile N64 bootloader software"
echo " controller - compile MCU controller software"
+ echo " cic - compile CIC emulation software"
echo " fpga - compile FPGA design"
echo " update - compile all software and designs"
echo " release - collect and zip files for release (triggers 'update' build)"
@@ -147,6 +163,7 @@ fi
TRIGGER_BOOTLOADER=false
TRIGGER_CONTROLLER=false
+TRIGGER_CIC=false
TRIGGER_FPGA=false
TRIGGER_UPDATE=false
TRIGGER_RELEASE=false
@@ -159,6 +176,9 @@ while test $# -gt 0; do
controller)
TRIGGER_CONTROLLER=true
;;
+ cic)
+ TRIGGER_CIC=true
+ ;;
fpga)
TRIGGER_FPGA=true
;;
@@ -187,6 +207,7 @@ done
if [ "$TRIGGER_BOOTLOADER" = true ]; then build_bootloader; fi
if [ "$TRIGGER_CONTROLLER" = true ]; then build_controller; fi
+if [ "$TRIGGER_CIC" = true ]; then build_cic; fi
if [ "$TRIGGER_FPGA" = true ]; then build_fpga; fi
if [ "$TRIGGER_UPDATE" = true ]; then build_update; fi
if [ "$TRIGGER_RELEASE" = true ]; then build_release; fi
diff --git a/docker_build.sh b/docker_build.sh
index 7f580b7..32ae7f9 100755
--- a/docker_build.sh
+++ b/docker_build.sh
@@ -1,6 +1,6 @@
#!/bin/bash
-BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.5"
+BUILDER_IMAGE="ghcr.io/polprzewodnikowy/sc64env:v1.6"
pushd $(dirname $0) > /dev/null
diff --git a/fw/project/lcmxo2/debug.sty b/fw/project/lcmxo2/debug.sty
index e2e20d6..821cca4 100644
--- a/fw/project/lcmxo2/debug.sty
+++ b/fw/project/lcmxo2/debug.sty
@@ -72,6 +72,7 @@
+
diff --git a/fw/project/lcmxo2/release.sty b/fw/project/lcmxo2/release.sty
index 3408612..c5ef791 100644
--- a/fw/project/lcmxo2/release.sty
+++ b/fw/project/lcmxo2/release.sty
@@ -72,6 +72,7 @@
+
@@ -93,7 +94,7 @@
-
+
@@ -119,12 +120,12 @@
-
+
-
+
@@ -179,8 +180,8 @@
-
-
+
+
diff --git a/fw/project/lcmxo2/sc64.ldf b/fw/project/lcmxo2/sc64.ldf
index 9b99571..f3198e8 100644
--- a/fw/project/lcmxo2/sc64.ldf
+++ b/fw/project/lcmxo2/sc64.ldf
@@ -6,6 +6,12 @@
+
+
@@ -33,9 +39,15 @@
+
+
@@ -48,15 +60,9 @@
-
-
@@ -78,9 +84,6 @@
-
@@ -108,6 +111,54 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/fw/rtl/mcu/mcu_top.sv b/fw/rtl/mcu/mcu_top.sv
index e55c36c..9996b23 100644
--- a/fw/rtl/mcu/mcu_top.sv
+++ b/fw/rtl/mcu/mcu_top.sv
@@ -358,7 +358,9 @@ module mcu_top (
REG_VENDOR_SCR,
REG_VENDOR_DATA,
REG_DEBUG_0,
- REG_DEBUG_1
+ REG_DEBUG_1,
+ REG_CIC_0,
+ REG_CIC_1
} reg_address_e;
logic bootloader_skip;
@@ -368,6 +370,8 @@ module mcu_top (
logic dd_bm_ack;
+ logic cic_invalid_region;
+
// Register read logic
@@ -649,6 +653,22 @@ module mcu_top (
n64_scb.pi_debug[35:32]
};
end
+
+ REG_CIC_0: begin
+ reg_rdata <= {
+ 4'd0,
+ cic_invalid_region,
+ n64_scb.cic_disabled,
+ n64_scb.cic_64dd_mode,
+ n64_scb.cic_region,
+ n64_scb.cic_seed,
+ n64_scb.cic_checksum[47:32]
+ };
+ end
+
+ REG_CIC_1: begin
+ reg_rdata <= n64_scb.cic_checksum[31:0];
+ end
endcase
end
end
@@ -705,6 +725,10 @@ module mcu_top (
dd_bm_ack <= 1'b1;
end
+ if (n64_scb.cic_invalid_region) begin
+ cic_invalid_region <= 1'b1;
+ end
+
if (reset) begin
mcu_int <= 1'b0;
sd_scb.clock_mode <= 2'd0;
@@ -723,6 +747,12 @@ module mcu_top (
flash_scb.erase_pending <= 1'b0;
dd_bm_ack <= 1'b0;
n64_scb.rtc_wdata_valid <= 1'b0;
+ cic_invalid_region <= 1'b0;
+ n64_scb.cic_disabled <= 1'b0;
+ n64_scb.cic_64dd_mode <= 1'b0;
+ n64_scb.cic_region <= 1'b0;
+ n64_scb.cic_seed <= 8'h3F;
+ n64_scb.cic_checksum <= 48'hA536C0F1D859;
end else if (reg_write) begin
case (address)
REG_MEM_ADDRESS: begin
@@ -900,6 +930,21 @@ module mcu_top (
REG_VENDOR_DATA: begin
vendor_scb.data_wdata <= reg_wdata;
end
+
+ REG_CIC_0: begin
+ if (reg_wdata[28]) begin
+ cic_invalid_region <= 1'b0;
+ end
+ n64_scb.cic_disabled <= reg_wdata[26];
+ n64_scb.cic_64dd_mode <= reg_wdata[25];
+ n64_scb.cic_region <= reg_wdata[24];
+ n64_scb.cic_seed <= reg_wdata[23:16];
+ n64_scb.cic_checksum[47:32] <= reg_wdata[15:0];
+ end
+
+ REG_CIC_1: begin
+ n64_scb.cic_checksum[31:0] <= reg_wdata;
+ end
endcase
end
end
diff --git a/fw/rtl/n64/n64_cic.sv b/fw/rtl/n64/n64_cic.sv
new file mode 100644
index 0000000..498f19c
--- /dev/null
+++ b/fw/rtl/n64/n64_cic.sv
@@ -0,0 +1,168 @@
+module n64_cic (
+ input clk,
+ input reset,
+
+ n64_scb.cic n64_scb,
+
+ input n64_reset,
+ input n64_cic_clk,
+ inout n64_cic_dq
+);
+
+ // Input/output synchronization
+
+ logic [1:0] n64_reset_ff;
+ logic [1:0] n64_cic_clk_ff;
+ logic [1:0] n64_cic_dq_ff;
+
+ always_ff @(posedge clk) begin
+ n64_reset_ff <= {n64_reset_ff[0], n64_reset};
+ n64_cic_clk_ff <= {n64_cic_clk_ff[0], n64_cic_clk};
+ n64_cic_dq_ff <= {n64_cic_dq_ff[0], n64_cic_dq};
+ end
+
+ logic cic_reset;
+ logic cic_clk;
+ logic cic_dq;
+
+ always_comb begin
+ cic_reset = n64_reset_ff[1];
+ cic_clk = n64_cic_clk_ff[1];
+ cic_dq = n64_cic_dq_ff[1];
+ end
+
+ logic cic_dq_out;
+
+ assign n64_cic_dq = cic_dq_out ? 1'bZ : 1'b0;
+
+
+ // SERV RISC-V CPU
+
+ logic [31:0] ibus_addr;
+ logic ibus_cycle;
+ logic [31:0] ibus_rdata;
+ logic ibus_ack;
+
+ logic [31:0] dbus_addr;
+ logic [31:0] dbus_wdata;
+ logic [3:0] dbus_wmask;
+ logic dbus_write;
+ logic dbus_cycle;
+ logic [31:0] dbus_rdata;
+ logic dbus_ack;
+
+ logic [31:0] ext_rs1;
+ logic [31:0] ext_rs2;
+ logic [2:0] ext_funct3;
+ logic mdu_valid;
+
+ serv_rf_top #(
+ .RESET_PC(32'h8000_0000),
+ .PRE_REGISTER(0),
+ .WITH_CSR(0)
+ ) serv_rf_top_inst (
+ .clk(clk),
+ .i_rst(reset),
+ .i_timer_irq(1'b0),
+
+ .o_ibus_adr(ibus_addr),
+ .o_ibus_cyc(ibus_cycle),
+ .i_ibus_rdt(ibus_rdata),
+ .i_ibus_ack(ibus_ack),
+
+ .o_dbus_adr(dbus_addr),
+ .o_dbus_dat(dbus_wdata),
+ .o_dbus_sel(dbus_wmask),
+ .o_dbus_we(dbus_write) ,
+ .o_dbus_cyc(dbus_cycle),
+ .i_dbus_rdt(dbus_rdata),
+ .i_dbus_ack(dbus_ack),
+
+ .o_ext_rs1(ext_rs1),
+ .o_ext_rs2(ext_rs2),
+ .o_ext_funct3(ext_funct3),
+ .i_ext_rd(32'd0),
+ .i_ext_ready(1'b0),
+ .o_mdu_valid(mdu_valid)
+ );
+
+
+ // CPU memory
+
+ logic [8:0] ram_addr;
+ logic [31:0] ram [0:511];
+ logic [31:0] ram_output;
+
+ assign ram_addr = ibus_cycle ? ibus_addr[10:2] : dbus_addr[10:2];
+ assign ibus_rdata = ram_output;
+
+ always_ff @(posedge clk) begin
+ ram_output <= ram[ram_addr];
+
+ ibus_ack <= ibus_cycle && !ibus_ack;
+ end
+
+ initial begin
+ $readmemh("../../../sw/cic/cic.mem", ram);
+ end
+
+
+ // Bus controller
+
+ always_ff @(posedge clk) begin
+ n64_scb.cic_invalid_region <= 1'b0;
+
+ dbus_ack <= dbus_cycle && !dbus_ack;
+
+ if (dbus_cycle && dbus_write) begin
+ case (dbus_addr[31:30])
+ 2'b10: begin
+ if (dbus_wmask[0]) ram[ram_addr][7:0] <= dbus_wdata[7:0];
+ if (dbus_wmask[1]) ram[ram_addr][15:8] <= dbus_wdata[15:8];
+ if (dbus_wmask[2]) ram[ram_addr][23:16] <= dbus_wdata[23:16];
+ if (dbus_wmask[3]) ram[ram_addr][31:24] <= dbus_wdata[31:24];
+ end
+
+ 2'b11: begin
+ case (dbus_addr[3:2])
+ 2'b10: begin
+ n64_scb.cic_invalid_region <= dbus_wdata[3];
+ cic_dq_out <= dbus_wdata[0];
+ end
+ endcase
+ end
+ endcase
+ end
+
+ if (reset || !cic_reset) begin
+ cic_dq_out <= 1'b1;
+ end
+ end
+
+ always_comb begin
+ dbus_rdata = 32'd0;
+
+ case (dbus_addr[31:30])
+ 2'b10: begin
+ dbus_rdata = ram_output;
+ end
+
+ 2'b11: begin
+ case (dbus_addr[3:2])
+ 2'b00: dbus_rdata = {
+ n64_scb.cic_disabled,
+ n64_scb.cic_64dd_mode,
+ n64_scb.cic_region,
+ n64_scb.cic_seed,
+ n64_scb.cic_checksum[47:32]
+ };
+
+ 2'b01: dbus_rdata = n64_scb.cic_checksum[31:0];
+
+ 2'b10: dbus_rdata = {29'd0, cic_reset, cic_clk, cic_dq};
+ endcase
+ end
+ endcase
+ end
+
+endmodule
diff --git a/fw/rtl/n64/n64_pi.sv b/fw/rtl/n64/n64_pi.sv
index 6eed2bf..4e49fa3 100644
--- a/fw/rtl/n64/n64_pi.sv
+++ b/fw/rtl/n64/n64_pi.sv
@@ -20,16 +20,16 @@ module n64_pi (
logic [1:0] n64_reset_ff;
logic [1:0] n64_nmi_ff;
- logic [3:0] n64_pi_alel_ff;
- logic [3:0] n64_pi_aleh_ff;
+ logic [2:0] n64_pi_alel_ff;
+ logic [2:0] n64_pi_aleh_ff;
logic [1:0] n64_pi_read_ff;
logic [2:0] n64_pi_write_ff;
always_ff @(posedge clk) begin
n64_reset_ff <= {n64_reset_ff[0], n64_reset};
n64_nmi_ff <= {n64_nmi_ff[0], n64_nmi};
- n64_pi_aleh_ff <= {n64_pi_aleh_ff[2:0], n64_pi_aleh};
- n64_pi_alel_ff <= {n64_pi_alel_ff[2:0], n64_pi_alel};
+ n64_pi_aleh_ff <= {n64_pi_aleh_ff[1:0], n64_pi_aleh};
+ n64_pi_alel_ff <= {n64_pi_alel_ff[1:0], n64_pi_alel};
n64_pi_read_ff <= {n64_pi_read_ff[0], n64_pi_read};
n64_pi_write_ff <= {n64_pi_write_ff[1:0], n64_pi_write};
end
@@ -44,8 +44,8 @@ module n64_pi (
always_comb begin
pi_reset = n64_reset_ff[1];
pi_nmi = n64_nmi_ff[1];
- pi_aleh = n64_pi_aleh_ff[3];
- pi_alel = n64_pi_alel_ff[3];
+ pi_aleh = n64_pi_aleh_ff[2];
+ pi_alel = n64_pi_alel_ff[2];
pi_read = n64_pi_read_ff[1];
pi_write = n64_pi_write_ff[2];
end
@@ -98,11 +98,14 @@ module n64_pi (
always_comb begin
n64_scb.n64_reset = !last_reset && pi_reset;
n64_scb.n64_nmi = !last_nmi && pi_nmi;
- aleh_op = pi_reset && (last_pi_mode != PI_MODE_HIGH) && (pi_mode == PI_MODE_HIGH);
- alel_op = pi_reset && (last_pi_mode == PI_MODE_HIGH) && (pi_mode == PI_MODE_LOW);
- read_op = pi_reset && (pi_mode == PI_MODE_VALID) && (read_port != PORT_NONE) && (last_read && !pi_read);
- write_op = pi_reset && (pi_mode == PI_MODE_VALID) && (write_port != PORT_NONE) && (last_write && !pi_write);
- end_op = pi_reset && (last_pi_mode == PI_MODE_VALID) && (pi_mode != PI_MODE_VALID);
+ end
+
+ always_ff @(posedge clk) begin
+ aleh_op <= pi_reset && (last_pi_mode != PI_MODE_HIGH) && (pi_mode == PI_MODE_HIGH);
+ alel_op <= pi_reset && (last_pi_mode == PI_MODE_HIGH) && (pi_mode == PI_MODE_LOW);
+ read_op <= pi_reset && (pi_mode == PI_MODE_VALID) && (read_port != PORT_NONE) && (last_read && !pi_read);
+ write_op <= pi_reset && (pi_mode == PI_MODE_VALID) && (write_port != PORT_NONE) && (last_write && !pi_write);
+ end_op <= pi_reset && (last_pi_mode == PI_MODE_VALID) && (pi_mode != PI_MODE_VALID);
end
diff --git a/fw/rtl/n64/n64_scb.sv b/fw/rtl/n64/n64_scb.sv
index 106b70a..b2ba869 100644
--- a/fw/rtl/n64/n64_scb.sv
+++ b/fw/rtl/n64/n64_scb.sv
@@ -55,6 +55,13 @@ interface n64_scb ();
logic [15:0] save_count;
+ logic cic_invalid_region;
+ logic cic_disabled;
+ logic cic_64dd_mode;
+ logic cic_region;
+ logic [7:0] cic_seed;
+ logic [47:0] cic_checksum;
+
logic pi_sdram_active;
logic pi_flash_active;
logic [35:0] pi_debug;
@@ -98,6 +105,13 @@ interface n64_scb ();
input save_count,
+ input cic_invalid_region,
+ output cic_disabled,
+ output cic_64dd_mode,
+ output cic_region,
+ output cic_seed,
+ output cic_checksum,
+
input pi_debug
);
@@ -205,6 +219,15 @@ interface n64_scb ();
output save_count
);
+ modport cic (
+ output cic_invalid_region,
+ input cic_disabled,
+ input cic_64dd_mode,
+ input cic_region,
+ input cic_seed,
+ input cic_checksum
+ );
+
modport arbiter (
input pi_sdram_active,
input pi_flash_active
diff --git a/fw/rtl/n64/n64_top.sv b/fw/rtl/n64/n64_top.sv
index 2dbc6af..42b4eae 100644
--- a/fw/rtl/n64/n64_top.sv
+++ b/fw/rtl/n64/n64_top.sv
@@ -18,7 +18,10 @@ module n64_top (
inout [15:0] n64_pi_ad,
input n64_si_clk,
- inout n64_si_dq
+ inout n64_si_dq,
+
+ input n64_cic_clk,
+ inout n64_cic_dq
);
logic n64_dd_irq;
@@ -101,4 +104,15 @@ module n64_top (
.n64_scb(n64_scb)
);
+ n64_cic n64_cic_inst (
+ .clk(clk),
+ .reset(reset),
+
+ .n64_scb(n64_scb),
+
+ .n64_reset(n64_reset),
+ .n64_cic_clk(n64_cic_clk),
+ .n64_cic_dq(n64_cic_dq)
+ );
+
endmodule
diff --git a/fw/rtl/serv/serv_aligner.v b/fw/rtl/serv/serv_aligner.v
new file mode 100644
index 0000000..87fceb6
--- /dev/null
+++ b/fw/rtl/serv/serv_aligner.v
@@ -0,0 +1,67 @@
+module serv_aligner
+ (
+ input wire clk,
+ input wire rst,
+ // serv_top
+ input wire [31:0] i_ibus_adr,
+ input wire i_ibus_cyc,
+ output wire [31:0] o_ibus_rdt,
+ output wire o_ibus_ack,
+ // serv_rf_top
+ output wire [31:0] o_wb_ibus_adr,
+ output wire o_wb_ibus_cyc,
+ input wire [31:0] i_wb_ibus_rdt,
+ input wire i_wb_ibus_ack);
+
+ wire [31:0] ibus_rdt_concat;
+ wire ack_en;
+
+ reg [15:0] lower_hw;
+ reg ctrl_misal ;
+
+ /* From SERV core to Memory
+
+ o_wb_ibus_adr: Carries address of instruction to memory. In case of misaligned access,
+ which is caused by pc+2 due to compressed instruction, next instruction is fetched
+ by pc+4 and concatenation is done to make the instruction aligned.
+
+ o_wb_ibus_cyc: Simply forwarded from SERV to Memory and is only altered by memory or SERV core.
+ */
+ assign o_wb_ibus_adr = ctrl_misal ? (i_ibus_adr+32'b100) : i_ibus_adr;
+ assign o_wb_ibus_cyc = i_ibus_cyc;
+
+ /* From Memory to SERV core
+
+ o_ibus_ack: Instruction bus acknowledge is send to SERV only when the aligned instruction,
+ either compressed or un-compressed, is ready to dispatch.
+
+ o_ibus_rdt: Carries the instruction from memory to SERV core. It can be either aligned
+ instruction coming from memory or made aligned by two bus transactions and concatenation.
+ */
+ assign o_ibus_ack = i_wb_ibus_ack & ack_en;
+ assign o_ibus_rdt = ctrl_misal ? ibus_rdt_concat : i_wb_ibus_rdt;
+
+ /* 16-bit register used to hold the upper half word of the current instruction in-case
+ concatenation will be required with the upper half word of upcoming instruction
+ */
+ always @(posedge clk) begin
+ if(i_wb_ibus_ack)begin
+ lower_hw <= i_wb_ibus_rdt[31:16];
+ end
+ end
+
+ assign ibus_rdt_concat = {i_wb_ibus_rdt[15:0],lower_hw};
+
+ /* Two control signals: ack_en, ctrl_misal are set to control the bus transactions between
+ SERV core and the memory
+ */
+ assign ack_en = !(i_ibus_adr[1] & !ctrl_misal);
+
+ always @(posedge clk ) begin
+ if(rst)
+ ctrl_misal <= 0;
+ else if(i_wb_ibus_ack & i_ibus_adr[1])
+ ctrl_misal <= !ctrl_misal;
+ end
+
+endmodule
diff --git a/fw/rtl/serv/serv_alu.v b/fw/rtl/serv/serv_alu.v
new file mode 100644
index 0000000..62755aa
--- /dev/null
+++ b/fw/rtl/serv/serv_alu.v
@@ -0,0 +1,81 @@
+`default_nettype none
+module serv_alu
+ #(
+ parameter W = 1,
+ parameter B = W-1
+ )
+ (
+ input wire clk,
+ //State
+ input wire i_en,
+ input wire i_cnt0,
+ output wire o_cmp,
+ //Control
+ input wire i_sub,
+ input wire [1:0] i_bool_op,
+ input wire i_cmp_eq,
+ input wire i_cmp_sig,
+ input wire [2:0] i_rd_sel,
+ //Data
+ input wire [B:0] i_rs1,
+ input wire [B:0] i_op_b,
+ input wire [B:0] i_buf,
+ output wire [B:0] o_rd);
+
+ wire [B:0] result_add;
+ wire [B:0] result_slt;
+
+ reg cmp_r;
+
+ wire add_cy;
+ reg [B:0] add_cy_r;
+
+ //Sign-extended operands
+ wire rs1_sx = i_rs1[B] & i_cmp_sig;
+ wire op_b_sx = i_op_b[B] & i_cmp_sig;
+
+ wire [B:0] add_b = i_op_b^{W{i_sub}};
+
+ assign {add_cy,result_add} = i_rs1+add_b+add_cy_r;
+
+ wire result_lt = rs1_sx + ~op_b_sx + add_cy;
+
+ wire result_eq = !(|result_add) & (cmp_r | i_cnt0);
+
+ assign o_cmp = i_cmp_eq ? result_eq : result_lt;
+
+ /*
+ The result_bool expression implements the following operations between
+ i_rs1 and i_op_b depending on the value of i_bool_op
+
+ 00 xor
+ 01 0
+ 10 or
+ 11 and
+
+ i_bool_op will be 01 during shift operations, so by outputting zero under
+ this condition we can safely or result_bool with i_buf
+ */
+ wire [B:0] result_bool = ((i_rs1 ^ i_op_b) & ~{W{i_bool_op[0]}}) | ({W{i_bool_op[1]}} & i_op_b & i_rs1);
+
+ assign result_slt[0] = cmp_r & i_cnt0;
+ generate
+ if (W>1) begin : gen_w_gt_1
+ assign result_slt[B:1] = {B{1'b0}};
+ end
+ endgenerate
+
+ assign o_rd = i_buf |
+ ({W{i_rd_sel[0]}} & result_add) |
+ ({W{i_rd_sel[1]}} & result_slt) |
+ ({W{i_rd_sel[2]}} & result_bool);
+
+ always @(posedge clk) begin
+ add_cy_r <= {W{1'b0}};
+ add_cy_r[0] <= i_en ? add_cy : i_sub;
+
+ if (i_en)
+ cmp_r <= o_cmp;
+ end
+
+endmodule
diff --git a/fw/rtl/serv/serv_bufreg.v b/fw/rtl/serv/serv_bufreg.v
new file mode 100644
index 0000000..15a194e
--- /dev/null
+++ b/fw/rtl/serv/serv_bufreg.v
@@ -0,0 +1,51 @@
+module serv_bufreg #(
+ parameter [0:0] MDU = 0
+)(
+ input wire i_clk,
+ //State
+ input wire i_cnt0,
+ input wire i_cnt1,
+ input wire i_en,
+ input wire i_init,
+ input wire i_mdu_op,
+ output wire [1:0] o_lsb,
+ //Control
+ input wire i_rs1_en,
+ input wire i_imm_en,
+ input wire i_clr_lsb,
+ input wire i_sh_signed,
+ //Data
+ input wire i_rs1,
+ input wire i_imm,
+ output wire o_q,
+ //External
+ output wire [31:0] o_dbus_adr,
+ //Extension
+ output wire [31:0] o_ext_rs1);
+
+ wire c, q;
+ reg c_r;
+ reg [31:2] data;
+ reg [1:0] lsb;
+
+ wire clr_lsb = i_cnt0 & i_clr_lsb;
+
+ assign {c,q} = {1'b0,(i_rs1 & i_rs1_en)} + {1'b0,(i_imm & i_imm_en & !clr_lsb)} + c_r;
+
+ always @(posedge i_clk) begin
+ //Make sure carry is cleared before loading new data
+ c_r <= c & i_en;
+
+ if (i_en)
+ data <= {i_init ? q : (data[31] & i_sh_signed), data[31:3]};
+
+ if (i_init ? (i_cnt0 | i_cnt1) : i_en)
+ lsb <= {i_init ? q : data[2],lsb[1]};
+ end
+
+ assign o_q = lsb[0] & i_en;
+ assign o_dbus_adr = {data, 2'b00};
+ assign o_ext_rs1 = {o_dbus_adr[31:2],lsb};
+ assign o_lsb = (MDU & i_mdu_op) ? 2'b00 : lsb;
+
+endmodule
diff --git a/fw/rtl/serv/serv_bufreg2.v b/fw/rtl/serv/serv_bufreg2.v
new file mode 100644
index 0000000..57cf753
--- /dev/null
+++ b/fw/rtl/serv/serv_bufreg2.v
@@ -0,0 +1,65 @@
+module serv_bufreg2
+ (
+ input wire i_clk,
+ //State
+ input wire i_en,
+ input wire i_init,
+ input wire i_cnt_done,
+ input wire [1:0] i_lsb,
+ input wire i_byte_valid,
+ output wire o_sh_done,
+ output wire o_sh_done_r,
+ //Control
+ input wire i_op_b_sel,
+ input wire i_shift_op,
+ //Data
+ input wire i_rs2,
+ input wire i_imm,
+ output wire o_op_b,
+ output wire o_q,
+ //External
+ output wire [31:0] o_dat,
+ input wire i_load,
+ input wire [31:0] i_dat);
+
+ reg [31:0] dat;
+
+ assign o_op_b = i_op_b_sel ? i_rs2 : i_imm;
+
+ wire dat_en = i_shift_op | (i_en & i_byte_valid);
+
+ /* The dat register has three different use cases for store, load and
+ shift operations.
+ store : Data to be written is shifted to the correct position in dat during
+ init by dat_en and is presented on the data bus as o_wb_dat
+ load : Data from the bus gets latched into dat during i_wb_ack and is then
+ shifted out at the appropriate time to end up in the correct
+ position in rd
+ shift : Data is shifted in during init. After that, the six LSB are used as
+ a downcounter (with bit 5 initially set to 0) that triggers
+ o_sh_done and o_sh_done_r when they wrap around to indicate that
+ the requested number of shifts have been performed
+ */
+ wire [5:0] dat_shamt = (i_shift_op & !i_init) ?
+ //Down counter mode
+ dat[5:0]-1 :
+ //Shift reg mode with optional clearing of bit 5
+ {dat[6] & !(i_shift_op & i_cnt_done),dat[5:1]};
+
+ assign o_sh_done = dat_shamt[5];
+ assign o_sh_done_r = dat[5];
+
+ assign o_q =
+ ((i_lsb == 2'd3) & dat[24]) |
+ ((i_lsb == 2'd2) & dat[16]) |
+ ((i_lsb == 2'd1) & dat[8]) |
+ ((i_lsb == 2'd0) & dat[0]);
+
+ assign o_dat = dat;
+
+ always @(posedge i_clk) begin
+ if (dat_en | i_load)
+ dat <= i_load ? i_dat : {o_op_b, dat[31:7], dat_shamt};
+ end
+
+endmodule
diff --git a/fw/rtl/serv/serv_compdec.v b/fw/rtl/serv/serv_compdec.v
new file mode 100644
index 0000000..8025249
--- /dev/null
+++ b/fw/rtl/serv/serv_compdec.v
@@ -0,0 +1,234 @@
+/* Copyright lowRISC contributors.
+Copyright 2018 ETH Zurich and University of Bologna, see also CREDITS.md.
+Licensed under the Apache License, Version 2.0, see LICENSE for details.
+SPDX-License-Identifier: Apache-2.0
+
+* Adapted to SERV by @Abdulwadoodd as part of the project under spring '22 LFX Mentorship program */
+
+/* Decodes RISC-V compressed instructions into their RV32i equivalent. */
+
+module serv_compdec
+ (
+ input wire i_clk,
+ input wire [31:0] i_instr,
+ input wire i_ack,
+ output wire [31:0] o_instr,
+ output reg o_iscomp);
+
+ localparam OPCODE_LOAD = 7'h03;
+ localparam OPCODE_OP_IMM = 7'h13;
+ localparam OPCODE_STORE = 7'h23;
+ localparam OPCODE_OP = 7'h33;
+ localparam OPCODE_LUI = 7'h37;
+ localparam OPCODE_BRANCH = 7'h63;
+ localparam OPCODE_JALR = 7'h67;
+ localparam OPCODE_JAL = 7'h6f;
+
+ reg [31:0] comp_instr;
+ reg illegal_instr;
+
+ assign o_instr = illegal_instr ? i_instr : comp_instr;
+
+ always @(posedge i_clk) begin
+ if(i_ack)
+ o_iscomp <= !illegal_instr;
+ end
+
+ always @ (*) begin
+ // By default, forward incoming instruction, mark it as legal.
+ comp_instr = i_instr;
+ illegal_instr = 1'b0;
+
+ // Check if incoming instruction is compressed.
+ case (i_instr[1:0])
+ // C0
+ 2'b00: begin
+ case (i_instr[15:14])
+ 2'b00: begin
+ // c.addi4spn -> addi rd', x2, imm
+ comp_instr = {2'b0, i_instr[10:7], i_instr[12:11], i_instr[5],
+ i_instr[6], 2'b00, 5'h02, 3'b000, 2'b01, i_instr[4:2], {OPCODE_OP_IMM}};
+ end
+
+ 2'b01: begin
+ // c.lw -> lw rd', imm(rs1')
+ comp_instr = {5'b0, i_instr[5], i_instr[12:10], i_instr[6],
+ 2'b00, 2'b01, i_instr[9:7], 3'b010, 2'b01, i_instr[4:2], {OPCODE_LOAD}};
+ end
+
+ 2'b11: begin
+ // c.sw -> sw rs2', imm(rs1')
+ comp_instr = {5'b0, i_instr[5], i_instr[12], 2'b01, i_instr[4:2],
+ 2'b01, i_instr[9:7], 3'b010, i_instr[11:10], i_instr[6],
+ 2'b00, {OPCODE_STORE}};
+ end
+
+ 2'b10: begin
+ illegal_instr = 1'b1;
+ end
+
+ endcase
+ end
+
+ // C1
+
+ // Register address checks for RV32E are performed in the regular instruction decoder.
+ // If this check fails, an illegal instruction exception is triggered and the controller
+ // writes the actual faulting instruction to mtval.
+ 2'b01: begin
+ case (i_instr[15:13])
+ 3'b000: begin
+ // c.addi -> addi rd, rd, nzimm
+ // c.nop
+ comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2],
+ i_instr[11:7], 3'b0, i_instr[11:7], {OPCODE_OP_IMM}};
+ end
+
+ 3'b001, 3'b101: begin
+ // 001: c.jal -> jal x1, imm
+ // 101: c.j -> jal x0, imm
+ comp_instr = {i_instr[12], i_instr[8], i_instr[10:9], i_instr[6],
+ i_instr[7], i_instr[2], i_instr[11], i_instr[5:3],
+ {9 {i_instr[12]}}, 4'b0, ~i_instr[15], {OPCODE_JAL}};
+ end
+
+ 3'b010: begin
+ // c.li -> addi rd, x0, nzimm
+ // (c.li hints are translated into an addi hint)
+ comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2], 5'b0,
+ 3'b0, i_instr[11:7], {OPCODE_OP_IMM}};
+ end
+
+ 3'b011: begin
+ // c.lui -> lui rd, imm
+ // (c.lui hints are translated into a lui hint)
+ comp_instr = {{15 {i_instr[12]}}, i_instr[6:2], i_instr[11:7], {OPCODE_LUI}};
+
+ if (i_instr[11:7] == 5'h02) begin
+ // c.addi16sp -> addi x2, x2, nzimm
+ comp_instr = {{3 {i_instr[12]}}, i_instr[4:3], i_instr[5], i_instr[2],
+ i_instr[6], 4'b0, 5'h02, 3'b000, 5'h02, {OPCODE_OP_IMM}};
+ end
+
+ end
+
+ 3'b100: begin
+ case (i_instr[11:10])
+ 2'b00,
+ 2'b01: begin
+ // 00: c.srli -> srli rd, rd, shamt
+ // 01: c.srai -> srai rd, rd, shamt
+ // (c.srli/c.srai hints are translated into a srli/srai hint)
+ comp_instr = {1'b0, i_instr[10], 5'b0, i_instr[6:2], 2'b01, i_instr[9:7],
+ 3'b101, 2'b01, i_instr[9:7], {OPCODE_OP_IMM}};
+ end
+
+ 2'b10: begin
+ // c.andi -> andi rd, rd, imm
+ comp_instr = {{6 {i_instr[12]}}, i_instr[12], i_instr[6:2], 2'b01, i_instr[9:7],
+ 3'b111, 2'b01, i_instr[9:7], {OPCODE_OP_IMM}};
+ end
+
+ 2'b11: begin
+ case (i_instr[6:5])
+ 2'b00: begin
+ // c.sub -> sub rd', rd', rs2'
+ comp_instr = {2'b01, 5'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7],
+ 3'b000, 2'b01, i_instr[9:7], {OPCODE_OP}};
+ end
+
+ 2'b01: begin
+ // c.xor -> xor rd', rd', rs2'
+ comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b100,
+ 2'b01, i_instr[9:7], {OPCODE_OP}};
+ end
+
+ 2'b10: begin
+ // c.or -> or rd', rd', rs2'
+ comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b110,
+ 2'b01, i_instr[9:7], {OPCODE_OP}};
+ end
+
+ 2'b11: begin
+ // c.and -> and rd', rd', rs2'
+ comp_instr = {7'b0, 2'b01, i_instr[4:2], 2'b01, i_instr[9:7], 3'b111,
+ 2'b01, i_instr[9:7], {OPCODE_OP}};
+ end
+ endcase
+ end
+ endcase
+ end
+
+ 3'b110, 3'b111: begin
+ // 0: c.beqz -> beq rs1', x0, imm
+ // 1: c.bnez -> bne rs1', x0, imm
+ comp_instr = {{4 {i_instr[12]}}, i_instr[6:5], i_instr[2], 5'b0, 2'b01,
+ i_instr[9:7], 2'b00, i_instr[13], i_instr[11:10], i_instr[4:3],
+ i_instr[12], {OPCODE_BRANCH}};
+ end
+ endcase
+ end
+
+ // C2
+
+ // Register address checks for RV32E are performed in the regular instruction decoder.
+ // If this check fails, an illegal instruction exception is triggered and the controller
+ // writes the actual faulting instruction to mtval.
+ 2'b10: begin
+ case (i_instr[15:14])
+ 2'b00: begin
+ // c.slli -> slli rd, rd, shamt
+ // (c.ssli hints are translated into a slli hint)
+ comp_instr = {7'b0, i_instr[6:2], i_instr[11:7], 3'b001, i_instr[11:7], {OPCODE_OP_IMM}};
+ end
+
+ 2'b01: begin
+ // c.lwsp -> lw rd, imm(x2)
+ comp_instr = {4'b0, i_instr[3:2], i_instr[12], i_instr[6:4], 2'b00, 5'h02,
+ 3'b010, i_instr[11:7], OPCODE_LOAD};
+ end
+
+ 2'b10: begin
+ if (i_instr[12] == 1'b0) begin
+ if (i_instr[6:2] != 5'b0) begin
+ // c.mv -> add rd/rs1, x0, rs2
+ // (c.mv hints are translated into an add hint)
+ comp_instr = {7'b0, i_instr[6:2], 5'b0, 3'b0, i_instr[11:7], {OPCODE_OP}};
+ end else begin
+ // c.jr -> jalr x0, rd/rs1, 0
+ comp_instr = {12'b0, i_instr[11:7], 3'b0, 5'b0, {OPCODE_JALR}};
+ end
+ end else begin
+ if (i_instr[6:2] != 5'b0) begin
+ // c.add -> add rd, rd, rs2
+ // (c.add hints are translated into an add hint)
+ comp_instr = {7'b0, i_instr[6:2], i_instr[11:7], 3'b0, i_instr[11:7], {OPCODE_OP}};
+ end else begin
+ if (i_instr[11:7] == 5'b0) begin
+ // c.ebreak -> ebreak
+ comp_instr = {32'h00_10_00_73};
+ end else begin
+ // c.jalr -> jalr x1, rs1, 0
+ comp_instr = {12'b0, i_instr[11:7], 3'b000, 5'b00001, {OPCODE_JALR}};
+ end
+ end
+ end
+ end
+
+ 2'b11: begin
+ // c.swsp -> sw rs2, imm(x2)
+ comp_instr = {4'b0, i_instr[8:7], i_instr[12], i_instr[6:2], 5'h02, 3'b010,
+ i_instr[11:9], 2'b00, {OPCODE_STORE}};
+ end
+ endcase
+ end
+
+ // Incoming instruction is not compressed.
+ 2'b11: illegal_instr = 1'b1;
+
+ endcase
+ end
+
+ endmodule
+
+
diff --git a/fw/rtl/serv/serv_csr.v b/fw/rtl/serv/serv_csr.v
new file mode 100644
index 0000000..1bcfc06
--- /dev/null
+++ b/fw/rtl/serv/serv_csr.v
@@ -0,0 +1,142 @@
+`default_nettype none
+module serv_csr
+ #(parameter RESET_STRATEGY = "MINI")
+ (
+ input wire i_clk,
+ input wire i_rst,
+ //State
+ input wire i_trig_irq,
+ input wire i_en,
+ input wire i_cnt0to3,
+ input wire i_cnt3,
+ input wire i_cnt7,
+ input wire i_cnt_done,
+ input wire i_mem_op,
+ input wire i_mtip,
+ input wire i_trap,
+ output reg o_new_irq,
+ //Control
+ input wire i_e_op,
+ input wire i_ebreak,
+ input wire i_mem_cmd,
+ input wire i_mstatus_en,
+ input wire i_mie_en,
+ input wire i_mcause_en,
+ input wire [1:0] i_csr_source,
+ input wire i_mret,
+ input wire i_csr_d_sel,
+ //Data
+ input wire i_rf_csr_out,
+ output wire o_csr_in,
+ input wire i_csr_imm,
+ input wire i_rs1,
+ output wire o_q);
+
+ localparam [1:0]
+ CSR_SOURCE_CSR = 2'b00,
+ CSR_SOURCE_EXT = 2'b01,
+ CSR_SOURCE_SET = 2'b10,
+ CSR_SOURCE_CLR = 2'b11;
+
+ reg mstatus_mie;
+ reg mstatus_mpie;
+ reg mie_mtie;
+
+ reg mcause31;
+ reg [3:0] mcause3_0;
+ wire mcause;
+
+ wire csr_in;
+ wire csr_out;
+
+ reg timer_irq_r;
+
+ wire d = i_csr_d_sel ? i_csr_imm : i_rs1;
+
+ assign csr_in = (i_csr_source == CSR_SOURCE_EXT) ? d :
+ (i_csr_source == CSR_SOURCE_SET) ? csr_out | d :
+ (i_csr_source == CSR_SOURCE_CLR) ? csr_out & ~d :
+ (i_csr_source == CSR_SOURCE_CSR) ? csr_out :
+ 1'bx;
+
+ assign csr_out = (i_mstatus_en & mstatus_mie & i_cnt3) |
+ i_rf_csr_out |
+ (i_mcause_en & i_en & mcause);
+
+ assign o_q = csr_out;
+
+ wire timer_irq = i_mtip & mstatus_mie & mie_mtie;
+
+ assign mcause = i_cnt0to3 ? mcause3_0[0] : //[3:0]
+ i_cnt_done ? mcause31 //[31]
+ : 1'b0;
+
+ assign o_csr_in = csr_in;
+
+ always @(posedge i_clk) begin
+ if (i_trig_irq) begin
+ timer_irq_r <= timer_irq;
+ o_new_irq <= timer_irq & !timer_irq_r;
+ end
+
+ if (i_mie_en & i_cnt7)
+ mie_mtie <= csr_in;
+
+ /*
+ The mie bit in mstatus gets updated under three conditions
+
+ When a trap is taken, the bit is cleared
+ During an mret instruction, the bit is restored from mpie
+ During a mstatus CSR access instruction it's assigned when
+ bit 3 gets updated
+
+ These conditions are all mutually exclusibe
+ */
+ if ((i_trap & i_cnt_done) | i_mstatus_en & i_cnt3 | i_mret)
+ mstatus_mie <= !i_trap & (i_mret ? mstatus_mpie : csr_in);
+
+ /*
+ Note: To save resources mstatus_mpie (mstatus bit 7) is not
+ readable or writable from sw
+ */
+ if (i_trap & i_cnt_done)
+ mstatus_mpie <= mstatus_mie;
+
+ /*
+ The four lowest bits in mcause hold the exception code
+
+ These bits get updated under three conditions
+
+ During an mcause CSR access function, they are assigned when
+ bits 0 to 3 gets updated
+
+ During an external interrupt the exception code is set to
+ 7, since SERV only support timer interrupts
+
+ During an exception, the exception code is assigned to indicate
+ if it was caused by an ebreak instruction (3),
+ ecall instruction (11), misaligned load (4), misaligned store (6)
+ or misaligned jump (0)
+
+ The expressions below are derived from the following truth table
+ irq => 0111 (timer=7)
+ e_op => x011 (ebreak=3, ecall=11)
+ mem => 01x0 (store=6, load=4)
+ ctrl => 0000 (jump=0)
+ */
+ if (i_mcause_en & i_en & i_cnt0to3 | (i_trap & i_cnt_done)) begin
+ mcause3_0[3] <= (i_e_op & !i_ebreak) | (!i_trap & csr_in);
+ mcause3_0[2] <= o_new_irq | i_mem_op | (!i_trap & mcause3_0[3]);
+ mcause3_0[1] <= o_new_irq | i_e_op | (i_mem_op & i_mem_cmd) | (!i_trap & mcause3_0[2]);
+ mcause3_0[0] <= o_new_irq | i_e_op | (!i_trap & mcause3_0[1]);
+ end
+ if (i_mcause_en & i_cnt_done | i_trap)
+ mcause31 <= i_trap ? o_new_irq : csr_in;
+ if (i_rst)
+ if (RESET_STRATEGY != "NONE") begin
+ o_new_irq <= 1'b0;
+ mie_mtie <= 1'b0;
+ end
+ end
+
+endmodule
diff --git a/fw/rtl/serv/serv_ctrl.v b/fw/rtl/serv/serv_ctrl.v
new file mode 100644
index 0000000..ee3e154
--- /dev/null
+++ b/fw/rtl/serv/serv_ctrl.v
@@ -0,0 +1,84 @@
+`default_nettype none
+module serv_ctrl
+ #(parameter RESET_STRATEGY = "MINI",
+ parameter RESET_PC = 32'd0,
+ parameter WITH_CSR = 1)
+ (
+ input wire clk,
+ input wire i_rst,
+ //State
+ input wire i_pc_en,
+ input wire i_cnt12to31,
+ input wire i_cnt0,
+ input wire i_cnt1,
+ input wire i_cnt2,
+ //Control
+ input wire i_jump,
+ input wire i_jal_or_jalr,
+ input wire i_utype,
+ input wire i_pc_rel,
+ input wire i_trap,
+ input wire i_iscomp,
+ //Data
+ input wire i_imm,
+ input wire i_buf,
+ input wire i_csr_pc,
+ output wire o_rd,
+ output wire o_bad_pc,
+ //External
+ output reg [31:0] o_ibus_adr);
+
+ wire pc_plus_4;
+ wire pc_plus_4_cy;
+ reg pc_plus_4_cy_r;
+ wire pc_plus_offset;
+ wire pc_plus_offset_cy;
+ reg pc_plus_offset_cy_r;
+ wire pc_plus_offset_aligned;
+ wire plus_4;
+
+ wire pc = o_ibus_adr[0];
+
+ wire new_pc;
+
+ wire offset_a;
+ wire offset_b;
+
+ /* If i_iscomp=1: increment pc by 2 else increment pc by 4 */
+
+ assign plus_4 = i_iscomp ? i_cnt1 : i_cnt2;
+
+ assign o_bad_pc = pc_plus_offset_aligned;
+
+ assign {pc_plus_4_cy,pc_plus_4} = pc+plus_4+pc_plus_4_cy_r;
+
+ generate
+ if (|WITH_CSR) begin : gen_csr
+ assign new_pc = i_trap ? (i_csr_pc & !i_cnt0) : i_jump ? pc_plus_offset_aligned : pc_plus_4;
+ end else begin : gen_no_csr
+ assign new_pc = i_jump ? pc_plus_offset_aligned : pc_plus_4;
+ end
+ endgenerate
+ assign o_rd = (i_utype & pc_plus_offset_aligned) | (pc_plus_4 & i_jal_or_jalr);
+
+ assign offset_a = i_pc_rel & pc;
+ assign offset_b = i_utype ? (i_imm & i_cnt12to31): i_buf;
+ assign {pc_plus_offset_cy,pc_plus_offset} = offset_a+offset_b+pc_plus_offset_cy_r;
+
+ assign pc_plus_offset_aligned = pc_plus_offset & !i_cnt0;
+
+ initial if (RESET_STRATEGY == "NONE") o_ibus_adr = RESET_PC;
+
+ always @(posedge clk) begin
+ pc_plus_4_cy_r <= i_pc_en & pc_plus_4_cy;
+ pc_plus_offset_cy_r <= i_pc_en & pc_plus_offset_cy;
+
+ if (RESET_STRATEGY == "NONE") begin
+ if (i_pc_en)
+ o_ibus_adr <= {new_pc, o_ibus_adr[31:1]};
+ end else begin
+ if (i_pc_en | i_rst)
+ o_ibus_adr <= i_rst ? RESET_PC : {new_pc, o_ibus_adr[31:1]};
+ end
+ end
+endmodule
diff --git a/fw/rtl/serv/serv_decode.v b/fw/rtl/serv/serv_decode.v
new file mode 100644
index 0000000..3719819
--- /dev/null
+++ b/fw/rtl/serv/serv_decode.v
@@ -0,0 +1,365 @@
+`default_nettype none
+module serv_decode
+ #(parameter [0:0] PRE_REGISTER = 1,
+ parameter [0:0] MDU = 0)
+ (
+ input wire clk,
+ //Input
+ input wire [31:2] i_wb_rdt,
+ input wire i_wb_en,
+ //To state
+ output reg o_sh_right,
+ output reg o_bne_or_bge,
+ output reg o_cond_branch,
+ output reg o_e_op,
+ output reg o_ebreak,
+ output reg o_branch_op,
+ output reg o_shift_op,
+ output reg o_slt_or_branch,
+ output reg o_rd_op,
+ output reg o_two_stage_op,
+ output reg o_dbus_en,
+ //MDU
+ output reg o_mdu_op,
+ //Extension
+ output reg [2:0] o_ext_funct3,
+ //To bufreg
+ output reg o_bufreg_rs1_en,
+ output reg o_bufreg_imm_en,
+ output reg o_bufreg_clr_lsb,
+ output reg o_bufreg_sh_signed,
+ //To ctrl
+ output reg o_ctrl_jal_or_jalr,
+ output reg o_ctrl_utype,
+ output reg o_ctrl_pc_rel,
+ output reg o_ctrl_mret,
+ //To alu
+ output reg o_alu_sub,
+ output reg [1:0] o_alu_bool_op,
+ output reg o_alu_cmp_eq,
+ output reg o_alu_cmp_sig,
+ output reg [2:0] o_alu_rd_sel,
+ //To mem IF
+ output reg o_mem_signed,
+ output reg o_mem_word,
+ output reg o_mem_half,
+ output reg o_mem_cmd,
+ //To CSR
+ output reg o_csr_en,
+ output reg [1:0] o_csr_addr,
+ output reg o_csr_mstatus_en,
+ output reg o_csr_mie_en,
+ output reg o_csr_mcause_en,
+ output reg [1:0] o_csr_source,
+ output reg o_csr_d_sel,
+ output reg o_csr_imm_en,
+ output reg o_mtval_pc,
+ //To top
+ output reg [3:0] o_immdec_ctrl,
+ output reg [3:0] o_immdec_en,
+ output reg o_op_b_source,
+ //To RF IF
+ output reg o_rd_mem_en,
+ output reg o_rd_csr_en,
+ output reg o_rd_alu_en);
+
+ reg [4:0] opcode;
+ reg [2:0] funct3;
+ reg op20;
+ reg op21;
+ reg op22;
+ reg op26;
+
+ reg imm25;
+ reg imm30;
+
+ wire co_mdu_op = MDU & (opcode == 5'b01100) & imm25;
+
+ wire co_two_stage_op =
+ ~opcode[2] | (funct3[0] & ~funct3[1] & ~opcode[0] & ~opcode[4]) |
+ (funct3[1] & ~funct3[2] & ~opcode[0] & ~opcode[4]) | co_mdu_op;
+ wire co_shift_op = (opcode[2] & ~funct3[1]) & !co_mdu_op;
+ wire co_slt_or_branch = (opcode[4] | (funct3[1] & opcode[2]) | (imm30 & opcode[2] & opcode[3] & ~funct3[2])) & !co_mdu_op;
+ wire co_branch_op = opcode[4];
+ wire co_dbus_en = ~opcode[2] & ~opcode[4];
+ wire co_mtval_pc = opcode[4];
+ wire co_mem_word = funct3[1];
+ wire co_rd_alu_en = !opcode[0] & opcode[2] & !opcode[4] & !co_mdu_op;
+ wire co_rd_mem_en = (!opcode[2] & !opcode[0]) | co_mdu_op;
+ wire [2:0] co_ext_funct3 = funct3;
+
+ //jal,branch = imm
+ //jalr = rs1+imm
+ //mem = rs1+imm
+ //shift = rs1
+ wire co_bufreg_rs1_en = !opcode[4] | (!opcode[1] & opcode[0]);
+ wire co_bufreg_imm_en = !opcode[2];
+
+ //Clear LSB of immediate for BRANCH and JAL ops
+ //True for BRANCH and JAL
+ //False for JALR/LOAD/STORE/OP/OPIMM?
+ wire co_bufreg_clr_lsb = opcode[4] & ((opcode[1:0] == 2'b00) | (opcode[1:0] == 2'b11));
+
+ //Conditional branch
+ //True for BRANCH
+ //False for JAL/JALR
+ wire co_cond_branch = !opcode[0];
+
+ wire co_ctrl_utype = !opcode[4] & opcode[2] & opcode[0];
+ wire co_ctrl_jal_or_jalr = opcode[4] & opcode[0];
+
+ //PC-relative operations
+ //True for jal, b* auipc, ebreak
+ //False for jalr, lui
+ wire co_ctrl_pc_rel = (opcode[2:0] == 3'b000) |
+ (opcode[1:0] == 2'b11) |
+ (opcode[4] & opcode[2]) & op20|
+ (opcode[4:3] == 2'b00);
+ //Write to RD
+ //True for OP-IMM, AUIPC, OP, LUI, SYSTEM, JALR, JAL, LOAD
+ //False for STORE, BRANCH, MISC-MEM
+ wire co_rd_op = (opcode[2] |
+ (!opcode[2] & opcode[4] & opcode[0]) |
+ (!opcode[2] & !opcode[3] & !opcode[0]));
+
+ //
+ //funct3
+ //
+
+ wire co_sh_right = funct3[2];
+ wire co_bne_or_bge = funct3[0];
+
+ //Matches system ops except eceall/ebreak/mret
+ wire csr_op = opcode[4] & opcode[2] & (|funct3);
+
+
+ //op20
+ wire co_ebreak = op20;
+
+
+ //opcode & funct3 & op21
+
+ wire co_ctrl_mret = opcode[4] & opcode[2] & op21 & !(|funct3);
+ //Matches system opcodes except CSR accesses (funct3 == 0)
+ //and mret (!op21)
+ wire co_e_op = opcode[4] & opcode[2] & !op21 & !(|funct3);
+
+ //opcode & funct3 & imm30
+
+ wire co_bufreg_sh_signed = imm30;
+
+ /*
+ True for sub, b*, slt*
+ False for add*
+ op opcode f3 i30
+ b* 11000 xxx x t
+ addi 00100 000 x f
+ slt* 0x100 01x x t
+ add 01100 000 0 f
+ sub 01100 000 1 t
+ */
+ wire co_alu_sub = funct3[1] | funct3[0] | (opcode[3] & imm30) | opcode[4];
+
+ /*
+ Bits 26, 22, 21 and 20 are enough to uniquely identify the eight supported CSR regs
+ mtvec, mscratch, mepc and mtval are stored externally (normally in the RF) and are
+ treated differently from mstatus, mie and mcause which are stored in serv_csr.
+
+ The former get a 2-bit address as seen below while the latter get a
+ one-hot enable signal each.
+
+ Hex|2 222|Reg |csr
+ adr|6 210|name |addr
+ ---|-----|--------|----
+ 300|0_000|mstatus | xx
+ 304|0_100|mie | xx
+ 305|0_101|mtvec | 01
+ 340|1_000|mscratch| 00
+ 341|1_001|mepc | 10
+ 342|1_010|mcause | xx
+ 343|1_011|mtval | 11
+
+ */
+
+ //true for mtvec,mscratch,mepc and mtval
+ //false for mstatus, mie, mcause
+ wire csr_valid = op20 | (op26 & !op21);
+
+ wire co_rd_csr_en = csr_op;
+
+ wire co_csr_en = csr_op & csr_valid;
+ wire co_csr_mstatus_en = csr_op & !op26 & !op22;
+ wire co_csr_mie_en = csr_op & !op26 & op22 & !op20;
+ wire co_csr_mcause_en = csr_op & op21 & !op20;
+
+ wire [1:0] co_csr_source = funct3[1:0];
+ wire co_csr_d_sel = funct3[2];
+ wire co_csr_imm_en = opcode[4] & opcode[2] & funct3[2];
+ wire [1:0] co_csr_addr = {op26 & op20, !op26 | op21};
+
+ wire co_alu_cmp_eq = funct3[2:1] == 2'b00;
+
+ wire co_alu_cmp_sig = ~((funct3[0] & funct3[1]) | (funct3[1] & funct3[2]));
+
+ wire co_mem_cmd = opcode[3];
+ wire co_mem_signed = ~funct3[2];
+ wire co_mem_half = funct3[0];
+
+ wire [1:0] co_alu_bool_op = funct3[1:0];
+
+ wire [3:0] co_immdec_ctrl;
+ //True for S (STORE) or B (BRANCH) type instructions
+ //False for J type instructions
+ assign co_immdec_ctrl[0] = opcode[3:0] == 4'b1000;
+ //True for OP-IMM, LOAD, STORE, JALR (I S)
+ //False for LUI, AUIPC, JAL (U J)
+ assign co_immdec_ctrl[1] = (opcode[1:0] == 2'b00) | (opcode[2:1] == 2'b00);
+ assign co_immdec_ctrl[2] = opcode[4] & !opcode[0];
+ assign co_immdec_ctrl[3] = opcode[4];
+
+ wire [3:0] co_immdec_en;
+ assign co_immdec_en[3] = opcode[4] | opcode[3] | opcode[2] | !opcode[0]; //B I J S U
+ assign co_immdec_en[2] = (opcode[4] & opcode[2]) | !opcode[3] | opcode[0]; // I J U
+ assign co_immdec_en[1] = (opcode[2:1] == 2'b01) | (opcode[2] & opcode[0]) | co_csr_imm_en;// J U
+ assign co_immdec_en[0] = ~co_rd_op; //B S
+
+ wire [2:0] co_alu_rd_sel;
+ assign co_alu_rd_sel[0] = (funct3 == 3'b000); // Add/sub
+ assign co_alu_rd_sel[1] = (funct3[2:1] == 2'b01); //SLT*
+ assign co_alu_rd_sel[2] = funct3[2]; //Bool
+
+ //0 (OP_B_SOURCE_IMM) when OPIMM
+ //1 (OP_B_SOURCE_RS2) when BRANCH or OP
+ wire co_op_b_source = opcode[3];
+
+ generate
+ if (PRE_REGISTER) begin : gen_pre_register
+
+ always @(posedge clk) begin
+ if (i_wb_en) begin
+ funct3 <= i_wb_rdt[14:12];
+ imm30 <= i_wb_rdt[30];
+ imm25 <= i_wb_rdt[25];
+ opcode <= i_wb_rdt[6:2];
+ op20 <= i_wb_rdt[20];
+ op21 <= i_wb_rdt[21];
+ op22 <= i_wb_rdt[22];
+ op26 <= i_wb_rdt[26];
+ end
+ end
+
+ always @(*) begin
+ o_sh_right = co_sh_right;
+ o_bne_or_bge = co_bne_or_bge;
+ o_cond_branch = co_cond_branch;
+ o_dbus_en = co_dbus_en;
+ o_mtval_pc = co_mtval_pc;
+ o_two_stage_op = co_two_stage_op;
+ o_e_op = co_e_op;
+ o_ebreak = co_ebreak;
+ o_branch_op = co_branch_op;
+ o_shift_op = co_shift_op;
+ o_slt_or_branch = co_slt_or_branch;
+ o_rd_op = co_rd_op;
+ o_mdu_op = co_mdu_op;
+ o_ext_funct3 = co_ext_funct3;
+ o_bufreg_rs1_en = co_bufreg_rs1_en;
+ o_bufreg_imm_en = co_bufreg_imm_en;
+ o_bufreg_clr_lsb = co_bufreg_clr_lsb;
+ o_bufreg_sh_signed = co_bufreg_sh_signed;
+ o_ctrl_jal_or_jalr = co_ctrl_jal_or_jalr;
+ o_ctrl_utype = co_ctrl_utype;
+ o_ctrl_pc_rel = co_ctrl_pc_rel;
+ o_ctrl_mret = co_ctrl_mret;
+ o_alu_sub = co_alu_sub;
+ o_alu_bool_op = co_alu_bool_op;
+ o_alu_cmp_eq = co_alu_cmp_eq;
+ o_alu_cmp_sig = co_alu_cmp_sig;
+ o_alu_rd_sel = co_alu_rd_sel;
+ o_mem_signed = co_mem_signed;
+ o_mem_word = co_mem_word;
+ o_mem_half = co_mem_half;
+ o_mem_cmd = co_mem_cmd;
+ o_csr_en = co_csr_en;
+ o_csr_addr = co_csr_addr;
+ o_csr_mstatus_en = co_csr_mstatus_en;
+ o_csr_mie_en = co_csr_mie_en;
+ o_csr_mcause_en = co_csr_mcause_en;
+ o_csr_source = co_csr_source;
+ o_csr_d_sel = co_csr_d_sel;
+ o_csr_imm_en = co_csr_imm_en;
+ o_immdec_ctrl = co_immdec_ctrl;
+ o_immdec_en = co_immdec_en;
+ o_op_b_source = co_op_b_source;
+ o_rd_csr_en = co_rd_csr_en;
+ o_rd_alu_en = co_rd_alu_en;
+ o_rd_mem_en = co_rd_mem_en;
+ end
+
+ end else begin : gen_post_register
+
+ always @(*) begin
+ funct3 = i_wb_rdt[14:12];
+ imm30 = i_wb_rdt[30];
+ imm25 = i_wb_rdt[25];
+ opcode = i_wb_rdt[6:2];
+ op20 = i_wb_rdt[20];
+ op21 = i_wb_rdt[21];
+ op22 = i_wb_rdt[22];
+ op26 = i_wb_rdt[26];
+ end
+
+ always @(posedge clk) begin
+ if (i_wb_en) begin
+ o_sh_right <= co_sh_right;
+ o_bne_or_bge <= co_bne_or_bge;
+ o_cond_branch <= co_cond_branch;
+ o_e_op <= co_e_op;
+ o_ebreak <= co_ebreak;
+ o_two_stage_op <= co_two_stage_op;
+ o_dbus_en <= co_dbus_en;
+ o_mtval_pc <= co_mtval_pc;
+ o_branch_op <= co_branch_op;
+ o_shift_op <= co_shift_op;
+ o_slt_or_branch <= co_slt_or_branch;
+ o_rd_op <= co_rd_op;
+ o_mdu_op <= co_mdu_op;
+ o_ext_funct3 <= co_ext_funct3;
+ o_bufreg_rs1_en <= co_bufreg_rs1_en;
+ o_bufreg_imm_en <= co_bufreg_imm_en;
+ o_bufreg_clr_lsb <= co_bufreg_clr_lsb;
+ o_bufreg_sh_signed <= co_bufreg_sh_signed;
+ o_ctrl_jal_or_jalr <= co_ctrl_jal_or_jalr;
+ o_ctrl_utype <= co_ctrl_utype;
+ o_ctrl_pc_rel <= co_ctrl_pc_rel;
+ o_ctrl_mret <= co_ctrl_mret;
+ o_alu_sub <= co_alu_sub;
+ o_alu_bool_op <= co_alu_bool_op;
+ o_alu_cmp_eq <= co_alu_cmp_eq;
+ o_alu_cmp_sig <= co_alu_cmp_sig;
+ o_alu_rd_sel <= co_alu_rd_sel;
+ o_mem_signed <= co_mem_signed;
+ o_mem_word <= co_mem_word;
+ o_mem_half <= co_mem_half;
+ o_mem_cmd <= co_mem_cmd;
+ o_csr_en <= co_csr_en;
+ o_csr_addr <= co_csr_addr;
+ o_csr_mstatus_en <= co_csr_mstatus_en;
+ o_csr_mie_en <= co_csr_mie_en;
+ o_csr_mcause_en <= co_csr_mcause_en;
+ o_csr_source <= co_csr_source;
+ o_csr_d_sel <= co_csr_d_sel;
+ o_csr_imm_en <= co_csr_imm_en;
+ o_immdec_ctrl <= co_immdec_ctrl;
+ o_immdec_en <= co_immdec_en;
+ o_op_b_source <= co_op_b_source;
+ o_rd_csr_en <= co_rd_csr_en;
+ o_rd_alu_en <= co_rd_alu_en;
+ o_rd_mem_en <= co_rd_mem_en;
+ end
+ end
+
+ end
+ endgenerate
+
+endmodule
diff --git a/fw/rtl/serv/serv_immdec.v b/fw/rtl/serv/serv_immdec.v
new file mode 100644
index 0000000..1a6e129
--- /dev/null
+++ b/fw/rtl/serv/serv_immdec.v
@@ -0,0 +1,95 @@
+`default_nettype none
+module serv_immdec
+ #(parameter SHARED_RFADDR_IMM_REGS = 1)
+ (
+ input wire i_clk,
+ //State
+ input wire i_cnt_en,
+ input wire i_cnt_done,
+ //Control
+ input wire [3:0] i_immdec_en,
+ input wire i_csr_imm_en,
+ input wire [3:0] i_ctrl,
+ output wire [4:0] o_rd_addr,
+ output wire [4:0] o_rs1_addr,
+ output wire [4:0] o_rs2_addr,
+ //Data
+ output wire o_csr_imm,
+ output wire o_imm,
+ //External
+ input wire i_wb_en,
+ input wire [31:7] i_wb_rdt);
+
+ reg imm31;
+
+ reg [8:0] imm19_12_20;
+ reg imm7;
+ reg [5:0] imm30_25;
+ reg [4:0] imm24_20;
+ reg [4:0] imm11_7;
+
+ assign o_csr_imm = imm19_12_20[4];
+
+ wire signbit = imm31 & !i_csr_imm_en;
+
+ generate
+ if (SHARED_RFADDR_IMM_REGS) begin : gen_shared_imm_regs
+ assign o_rs1_addr = imm19_12_20[8:4];
+ assign o_rs2_addr = imm24_20;
+ assign o_rd_addr = imm11_7;
+
+ always @(posedge i_clk) begin
+ if (i_wb_en) begin
+ /* CSR immediates are always zero-extended, hence clear the signbit */
+ imm31 <= i_wb_rdt[31];
+ end
+ if (i_wb_en | (i_cnt_en & i_immdec_en[1]))
+ imm19_12_20 <= i_wb_en ? {i_wb_rdt[19:12],i_wb_rdt[20]} : {i_ctrl[3] ? signbit : imm24_20[0], imm19_12_20[8:1]};
+ if (i_wb_en | (i_cnt_en))
+ imm7 <= i_wb_en ? i_wb_rdt[7] : signbit;
+
+ if (i_wb_en | (i_cnt_en & i_immdec_en[3]))
+ imm30_25 <= i_wb_en ? i_wb_rdt[30:25] : {i_ctrl[2] ? imm7 : i_ctrl[1] ? signbit : imm19_12_20[0], imm30_25[5:1]};
+
+ if (i_wb_en | (i_cnt_en & i_immdec_en[2]))
+ imm24_20 <= i_wb_en ? i_wb_rdt[24:20] : {imm30_25[0], imm24_20[4:1]};
+
+ if (i_wb_en | (i_cnt_en & i_immdec_en[0]))
+ imm11_7 <= i_wb_en ? i_wb_rdt[11:7] : {imm30_25[0], imm11_7[4:1]};
+ end
+ end else begin : gen_separate_imm_regs
+ reg [4:0] rd_addr;
+ reg [4:0] rs1_addr;
+ reg [4:0] rs2_addr;
+
+ assign o_rd_addr = rd_addr;
+ assign o_rs1_addr = rs1_addr;
+ assign o_rs2_addr = rs2_addr;
+ always @(posedge i_clk) begin
+ if (i_wb_en) begin
+ /* CSR immediates are always zero-extended, hence clear the signbit */
+ imm31 <= i_wb_rdt[31];
+ imm19_12_20 <= {i_wb_rdt[19:12],i_wb_rdt[20]};
+ imm7 <= i_wb_rdt[7];
+ imm30_25 <= i_wb_rdt[30:25];
+ imm24_20 <= i_wb_rdt[24:20];
+ imm11_7 <= i_wb_rdt[11:7];
+
+ rd_addr <= i_wb_rdt[11:7];
+ rs1_addr <= i_wb_rdt[19:15];
+ rs2_addr <= i_wb_rdt[24:20];
+ end
+ if (i_cnt_en) begin
+ imm19_12_20 <= {i_ctrl[3] ? signbit : imm24_20[0], imm19_12_20[8:1]};
+ imm7 <= signbit;
+ imm30_25 <= {i_ctrl[2] ? imm7 : i_ctrl[1] ? signbit : imm19_12_20[0], imm30_25[5:1]};
+ imm24_20 <= {imm30_25[0], imm24_20[4:1]};
+ imm11_7 <= {imm30_25[0], imm11_7[4:1]};
+ end
+ end
+ end
+ endgenerate
+
+ assign o_imm = i_cnt_done ? signbit : i_ctrl[0] ? imm11_7[0] : imm24_20[0];
+
+endmodule
diff --git a/fw/rtl/serv/serv_mem_if.v b/fw/rtl/serv/serv_mem_if.v
new file mode 100644
index 0000000..7cdb39f
--- /dev/null
+++ b/fw/rtl/serv/serv_mem_if.v
@@ -0,0 +1,69 @@
+`default_nettype none
+module serv_mem_if
+ #(
+ parameter [0:0] WITH_CSR = 1,
+ parameter W = 1,
+ parameter B = W-1
+ )
+ (
+ input wire i_clk,
+ //State
+ input wire [1:0] i_bytecnt,
+ input wire [1:0] i_lsb,
+ output wire o_byte_valid,
+ output wire o_misalign,
+ //Control
+ input wire i_signed,
+ input wire i_word,
+ input wire i_half,
+ //MDU
+ input wire i_mdu_op,
+ //Data
+ input wire [B:0] i_bufreg2_q,
+ output wire [B:0] o_rd,
+ //External interface
+ output wire [3:0] o_wb_sel);
+
+ reg signbit;
+
+ /*
+ Before a store operation, the data to be written needs to be shifted into
+ place. Depending on the address alignment, we need to shift different
+ amounts. One formula for calculating this is to say that we shift when
+ i_lsb + i_bytecnt < 4. Unfortunately, the synthesis tools don't seem to be
+ clever enough so the hideous expression below is used to achieve the same
+ thing in a more optimal way.
+ */
+ assign o_byte_valid
+ = (!i_lsb[0] & !i_lsb[1]) |
+ (!i_bytecnt[0] & !i_bytecnt[1]) |
+ (!i_bytecnt[1] & !i_lsb[1]) |
+ (!i_bytecnt[1] & !i_lsb[0]) |
+ (!i_bytecnt[0] & !i_lsb[1]);
+
+ wire dat_valid =
+ i_mdu_op |
+ i_word |
+ (i_bytecnt == 2'b00) |
+ (i_half & !i_bytecnt[1]);
+
+ assign o_rd = dat_valid ? i_bufreg2_q : {W{i_signed & signbit}};
+
+ assign o_wb_sel[3] = (i_lsb == 2'b11) | i_word | (i_half & i_lsb[1]);
+ assign o_wb_sel[2] = (i_lsb == 2'b10) | i_word;
+ assign o_wb_sel[1] = (i_lsb == 2'b01) | i_word | (i_half & !i_lsb[1]);
+ assign o_wb_sel[0] = (i_lsb == 2'b00);
+
+ always @(posedge i_clk) begin
+ if (dat_valid)
+ signbit <= i_bufreg2_q[B];
+ end
+
+ /*
+ mem_misalign is checked after the init stage to decide whether to do a data
+ bus transaction or go to the trap state. It is only guaranteed to be correct
+ at this time
+ */
+ assign o_misalign = WITH_CSR & ((i_lsb[0] & (i_word | i_half)) | (i_lsb[1] & i_word));
+
+endmodule
diff --git a/fw/rtl/serv/serv_rf_if.v b/fw/rtl/serv/serv_rf_if.v
new file mode 100644
index 0000000..81d4c85
--- /dev/null
+++ b/fw/rtl/serv/serv_rf_if.v
@@ -0,0 +1,149 @@
+`default_nettype none
+module serv_rf_if
+ #(parameter WITH_CSR = 1)
+ (//RF Interface
+ input wire i_cnt_en,
+ output wire [4+WITH_CSR:0] o_wreg0,
+ output wire [4+WITH_CSR:0] o_wreg1,
+ output wire o_wen0,
+ output wire o_wen1,
+ output wire o_wdata0,
+ output wire o_wdata1,
+ output wire [4+WITH_CSR:0] o_rreg0,
+ output wire [4+WITH_CSR:0] o_rreg1,
+ input wire i_rdata0,
+ input wire i_rdata1,
+
+ //Trap interface
+ input wire i_trap,
+ input wire i_mret,
+ input wire i_mepc,
+ input wire i_mtval_pc,
+ input wire i_bufreg_q,
+ input wire i_bad_pc,
+ output wire o_csr_pc,
+ //CSR interface
+ input wire i_csr_en,
+ input wire [1:0] i_csr_addr,
+ input wire i_csr,
+ output wire o_csr,
+ //RD write port
+ input wire i_rd_wen,
+ input wire [4:0] i_rd_waddr,
+ input wire i_ctrl_rd,
+ input wire i_alu_rd,
+ input wire i_rd_alu_en,
+ input wire i_csr_rd,
+ input wire i_rd_csr_en,
+ input wire i_mem_rd,
+ input wire i_rd_mem_en,
+
+ //RS1 read port
+ input wire [4:0] i_rs1_raddr,
+ output wire o_rs1,
+ //RS2 read port
+ input wire [4:0] i_rs2_raddr,
+ output wire o_rs2);
+
+
+ /*
+ ********** Write side ***********
+ */
+
+ wire rd_wen = i_rd_wen & (|i_rd_waddr);
+
+ generate
+ if (|WITH_CSR) begin : gen_csr
+ wire rd = (i_ctrl_rd ) |
+ (i_alu_rd & i_rd_alu_en) |
+ (i_csr_rd & i_rd_csr_en) |
+ (i_mem_rd & i_rd_mem_en);
+
+ wire mtval = i_mtval_pc ? i_bad_pc : i_bufreg_q;
+
+ assign o_wdata0 = i_trap ? mtval : rd;
+ assign o_wdata1 = i_trap ? i_mepc : i_csr;
+
+ /* Port 0 handles writes to mtval during traps and rd otherwise
+ * Port 1 handles writes to mepc during traps and csr accesses otherwise
+ *
+ * GPR registers are mapped to address 0-31 (bits 0xxxxx).
+ * Following that are four CSR registers
+ * mscratch 100000
+ * mtvec 100001
+ * mepc 100010
+ * mtval 100011
+ */
+
+ assign o_wreg0 = i_trap ? {6'b100011} : {1'b0,i_rd_waddr};
+ assign o_wreg1 = i_trap ? {6'b100010} : {4'b1000,i_csr_addr};
+
+ assign o_wen0 = i_cnt_en & (i_trap | rd_wen);
+ assign o_wen1 = i_cnt_en & (i_trap | i_csr_en);
+
+ /*
+ ********** Read side ***********
+ */
+
+ //0 : RS1
+ //1 : RS2 / CSR
+
+ assign o_rreg0 = {1'b0, i_rs1_raddr};
+
+ /*
+ The address of the second read port (o_rreg1) can get assigned from four
+ different sources
+
+ Normal operations : i_rs2_raddr
+ CSR access : i_csr_addr
+ trap : MTVEC
+ mret : MEPC
+
+ Address 0-31 in the RF are assigned to the GPRs. After that follows the four
+ CSRs on addresses 32-35
+
+ 32 MSCRATCH
+ 33 MTVEC
+ 34 MEPC
+ 35 MTVAL
+
+ The expression below is an optimized version of this logic
+ */
+ wire sel_rs2 = !(i_trap | i_mret | i_csr_en);
+ assign o_rreg1 = {~sel_rs2,
+ i_rs2_raddr[4:2] & {3{sel_rs2}},
+ {1'b0,i_trap} | {i_mret,1'b0} | ({2{i_csr_en}} & i_csr_addr) | ({2{sel_rs2}} & i_rs2_raddr[1:0])};
+
+ assign o_rs1 = i_rdata0;
+ assign o_rs2 = i_rdata1;
+ assign o_csr = i_rdata1 & i_csr_en;
+ assign o_csr_pc = i_rdata1;
+
+ end else begin : gen_no_csr
+ wire rd = (i_ctrl_rd ) |
+ (i_alu_rd & i_rd_alu_en) |
+ (i_mem_rd & i_rd_mem_en);
+
+ assign o_wdata0 = rd;
+ assign o_wdata1 = 1'b0;
+
+ assign o_wreg0 = i_rd_waddr;
+ assign o_wreg1 = 5'd0;
+
+ assign o_wen0 = i_cnt_en & rd_wen;
+ assign o_wen1 = 1'b0;
+
+ /*
+ ********** Read side ***********
+ */
+
+ assign o_rreg0 = i_rs1_raddr;
+ assign o_rreg1 = i_rs2_raddr;
+
+ assign o_rs1 = i_rdata0;
+ assign o_rs2 = i_rdata1;
+ assign o_csr = 1'b0;
+ assign o_csr_pc = 1'b0;
+ end // else: !if(WITH_CSR)
+ endgenerate
+endmodule
diff --git a/fw/rtl/serv/serv_rf_ram.v b/fw/rtl/serv/serv_rf_ram.v
new file mode 100644
index 0000000..6c96fa6
--- /dev/null
+++ b/fw/rtl/serv/serv_rf_ram.v
@@ -0,0 +1,45 @@
+module serv_rf_ram
+ #(parameter width=0,
+ parameter csr_regs=4,
+ parameter depth=32*(32+csr_regs)/width)
+ (input wire i_clk,
+ input wire [$clog2(depth)-1:0] i_waddr,
+ input wire [width-1:0] i_wdata,
+ input wire i_wen,
+ input wire [$clog2(depth)-1:0] i_raddr,
+ input wire i_ren,
+ output wire [width-1:0] o_rdata);
+
+ reg [width-1:0] memory [0:depth-1];
+ reg [width-1:0] rdata ;
+
+ always @(posedge i_clk) begin
+ if (i_wen)
+ memory[i_waddr] <= i_wdata;
+ rdata <= i_ren ? memory[i_raddr] : {width{1'bx}};
+ end
+
+ /* Reads from reg x0 needs to return 0
+ Check that the part of the read address corresponding to the register
+ is zero and gate the output
+ width LSB of reg index $clog2(width)
+ 2 4 1
+ 4 3 2
+ 8 2 3
+ 16 1 4
+ 32 0 5
+ */
+ reg regzero;
+
+ always @(posedge i_clk)
+ regzero <= !(|i_raddr[$clog2(depth)-1:5-$clog2(width)]);
+
+ assign o_rdata = rdata & ~{width{regzero}};
+
+`ifdef SERV_CLEAR_RAM
+ integer i;
+ initial
+ for (i=0;i2) begin : gen_rdata1_w_neq_2
+ always @(posedge i_clk) begin
+ rdata1 <= {1'b0,rdata1[width-2:1]}; //Optimize?
+ if (rtrig1)
+ rdata1[width-2:0] <= i_rdata[width-1:1];
+ end
+ end else begin : gen_rdata1_w_eq_2
+ always @(posedge i_clk) if (rtrig1) rdata1 <= i_rdata[1];
+ end
+ endgenerate
+
+ always @(posedge i_clk) begin
+ if (&rcnt | i_rreq)
+ rgate <= i_rreq;
+
+ rtrig1 <= rtrig0;
+ rcnt <= rcnt+5'd1;
+ if (i_rreq | i_wreq)
+ rcnt <= {3'd0,i_wreq,1'b0};
+
+ rreq_r <= i_rreq;
+ rgnt <= rreq_r;
+
+ rdata0 <= {1'b0,rdata0[width-1:1]};
+ if (rtrig0)
+ rdata0 <= i_rdata;
+
+ if (i_rst) begin
+ if (reset_strategy != "NONE") begin
+ rgate <= 1'b0;
+ rgnt <= 1'b0;
+ rreq_r <= 1'b0;
+ rcnt <= 5'd0;
+ end
+ end
+ end
+
+
+
+endmodule
diff --git a/fw/rtl/serv/serv_rf_top.v b/fw/rtl/serv/serv_rf_top.v
new file mode 100644
index 0000000..35b7662
--- /dev/null
+++ b/fw/rtl/serv/serv_rf_top.v
@@ -0,0 +1,216 @@
+`default_nettype none
+
+module serv_rf_top
+ #(parameter RESET_PC = 32'd0,
+ /* COMPRESSED=1: Enable the compressed decoder and allowed misaligned jump of pc
+ COMPRESSED=0: Disable the compressed decoder and does not allow the misaligned jump of pc
+ */
+ parameter [0:0] COMPRESSED = 0,
+ /*
+ ALIGN = 1: Fetch the aligned instruction by making two bus transactions if the misaligned address
+ is given to the instruction bus.
+ */
+ parameter [0:0] ALIGN = COMPRESSED,
+ /* Multiplication and Division Unit
+ This parameter enables the interface for connecting SERV and MDU
+ */
+ parameter [0:0] MDU = 0,
+ /* Register signals before or after the decoder
+ 0 : Register after the decoder. Faster but uses more resources
+ 1 : (default) Register before the decoder. Slower but uses less resources
+ */
+ parameter PRE_REGISTER = 1,
+ /* Amount of reset applied to design
+ "NONE" : No reset at all. Relies on a POR to set correct initialization
+ values and that core isn't reset during runtime
+ "MINI" : Standard setting. Resets the minimal amount of FFs needed to
+ restart execution from the instruction at RESET_PC
+ */
+ parameter RESET_STRATEGY = "MINI",
+ parameter WITH_CSR = 1,
+ parameter RF_WIDTH = 2,
+ parameter RF_L2D = $clog2((32+(WITH_CSR*4))*32/RF_WIDTH))
+ (
+ input wire clk,
+ input wire i_rst,
+ input wire i_timer_irq,
+`ifdef RISCV_FORMAL
+ output wire rvfi_valid,
+ output wire [63:0] rvfi_order,
+ output wire [31:0] rvfi_insn,
+ output wire rvfi_trap,
+ output wire rvfi_halt,
+ output wire rvfi_intr,
+ output wire [1:0] rvfi_mode,
+ output wire [1:0] rvfi_ixl,
+ output wire [4:0] rvfi_rs1_addr,
+ output wire [4:0] rvfi_rs2_addr,
+ output wire [31:0] rvfi_rs1_rdata,
+ output wire [31:0] rvfi_rs2_rdata,
+ output wire [4:0] rvfi_rd_addr,
+ output wire [31:0] rvfi_rd_wdata,
+ output wire [31:0] rvfi_pc_rdata,
+ output wire [31:0] rvfi_pc_wdata,
+ output wire [31:0] rvfi_mem_addr,
+ output wire [3:0] rvfi_mem_rmask,
+ output wire [3:0] rvfi_mem_wmask,
+ output wire [31:0] rvfi_mem_rdata,
+ output wire [31:0] rvfi_mem_wdata,
+`endif
+ output wire [31:0] o_ibus_adr,
+ output wire o_ibus_cyc,
+ input wire [31:0] i_ibus_rdt,
+ input wire i_ibus_ack,
+ output wire [31:0] o_dbus_adr,
+ output wire [31:0] o_dbus_dat,
+ output wire [3:0] o_dbus_sel,
+ output wire o_dbus_we ,
+ output wire o_dbus_cyc,
+ input wire [31:0] i_dbus_rdt,
+ input wire i_dbus_ack,
+
+ // Extension
+ output wire [31:0] o_ext_rs1,
+ output wire [31:0] o_ext_rs2,
+ output wire [ 2:0] o_ext_funct3,
+ input wire [31:0] i_ext_rd,
+ input wire i_ext_ready,
+ // MDU
+ output wire o_mdu_valid);
+
+ localparam CSR_REGS = WITH_CSR*4;
+
+ wire rf_wreq;
+ wire rf_rreq;
+ wire [4+WITH_CSR:0] wreg0;
+ wire [4+WITH_CSR:0] wreg1;
+ wire wen0;
+ wire wen1;
+ wire wdata0;
+ wire wdata1;
+ wire [4+WITH_CSR:0] rreg0;
+ wire [4+WITH_CSR:0] rreg1;
+ wire rf_ready;
+ wire rdata0;
+ wire rdata1;
+
+ wire [RF_L2D-1:0] waddr;
+ wire [RF_WIDTH-1:0] wdata;
+ wire wen;
+ wire [RF_L2D-1:0] raddr;
+ wire ren;
+ wire [RF_WIDTH-1:0] rdata;
+
+ serv_rf_ram_if
+ #(.width (RF_WIDTH),
+ .reset_strategy (RESET_STRATEGY),
+ .csr_regs (CSR_REGS))
+ rf_ram_if
+ (.i_clk (clk),
+ .i_rst (i_rst),
+ .i_wreq (rf_wreq),
+ .i_rreq (rf_rreq),
+ .o_ready (rf_ready),
+ .i_wreg0 (wreg0),
+ .i_wreg1 (wreg1),
+ .i_wen0 (wen0),
+ .i_wen1 (wen1),
+ .i_wdata0 (wdata0),
+ .i_wdata1 (wdata1),
+ .i_rreg0 (rreg0),
+ .i_rreg1 (rreg1),
+ .o_rdata0 (rdata0),
+ .o_rdata1 (rdata1),
+ .o_waddr (waddr),
+ .o_wdata (wdata),
+ .o_wen (wen),
+ .o_raddr (raddr),
+ .o_ren (ren),
+ .i_rdata (rdata));
+
+ serv_rf_ram
+ #(.width (RF_WIDTH),
+ .csr_regs (CSR_REGS))
+ rf_ram
+ (.i_clk (clk),
+ .i_waddr (waddr),
+ .i_wdata (wdata),
+ .i_wen (wen),
+ .i_raddr (raddr),
+ .i_ren (ren),
+ .o_rdata (rdata));
+
+ serv_top
+ #(.RESET_PC (RESET_PC),
+ .PRE_REGISTER (PRE_REGISTER),
+ .RESET_STRATEGY (RESET_STRATEGY),
+ .WITH_CSR (WITH_CSR),
+ .MDU(MDU),
+ .COMPRESSED(COMPRESSED),
+ .ALIGN(ALIGN))
+ cpu
+ (
+ .clk (clk),
+ .i_rst (i_rst),
+ .i_timer_irq (i_timer_irq),
+`ifdef RISCV_FORMAL
+ .rvfi_valid (rvfi_valid ),
+ .rvfi_order (rvfi_order ),
+ .rvfi_insn (rvfi_insn ),
+ .rvfi_trap (rvfi_trap ),
+ .rvfi_halt (rvfi_halt ),
+ .rvfi_intr (rvfi_intr ),
+ .rvfi_mode (rvfi_mode ),
+ .rvfi_ixl (rvfi_ixl ),
+ .rvfi_rs1_addr (rvfi_rs1_addr ),
+ .rvfi_rs2_addr (rvfi_rs2_addr ),
+ .rvfi_rs1_rdata (rvfi_rs1_rdata),
+ .rvfi_rs2_rdata (rvfi_rs2_rdata),
+ .rvfi_rd_addr (rvfi_rd_addr ),
+ .rvfi_rd_wdata (rvfi_rd_wdata ),
+ .rvfi_pc_rdata (rvfi_pc_rdata ),
+ .rvfi_pc_wdata (rvfi_pc_wdata ),
+ .rvfi_mem_addr (rvfi_mem_addr ),
+ .rvfi_mem_rmask (rvfi_mem_rmask),
+ .rvfi_mem_wmask (rvfi_mem_wmask),
+ .rvfi_mem_rdata (rvfi_mem_rdata),
+ .rvfi_mem_wdata (rvfi_mem_wdata),
+`endif
+ .o_rf_rreq (rf_rreq),
+ .o_rf_wreq (rf_wreq),
+ .i_rf_ready (rf_ready),
+ .o_wreg0 (wreg0),
+ .o_wreg1 (wreg1),
+ .o_wen0 (wen0),
+ .o_wen1 (wen1),
+ .o_wdata0 (wdata0),
+ .o_wdata1 (wdata1),
+ .o_rreg0 (rreg0),
+ .o_rreg1 (rreg1),
+ .i_rdata0 (rdata0),
+ .i_rdata1 (rdata1),
+
+ .o_ibus_adr (o_ibus_adr),
+ .o_ibus_cyc (o_ibus_cyc),
+ .i_ibus_rdt (i_ibus_rdt),
+ .i_ibus_ack (i_ibus_ack),
+
+ .o_dbus_adr (o_dbus_adr),
+ .o_dbus_dat (o_dbus_dat),
+ .o_dbus_sel (o_dbus_sel),
+ .o_dbus_we (o_dbus_we),
+ .o_dbus_cyc (o_dbus_cyc),
+ .i_dbus_rdt (i_dbus_rdt),
+ .i_dbus_ack (i_dbus_ack),
+
+ //Extension
+ .o_ext_funct3 (o_ext_funct3),
+ .i_ext_ready (i_ext_ready),
+ .i_ext_rd (i_ext_rd),
+ .o_ext_rs1 (o_ext_rs1),
+ .o_ext_rs2 (o_ext_rs2),
+ //MDU
+ .o_mdu_valid (o_mdu_valid));
+
+endmodule
+`default_nettype wire
diff --git a/fw/rtl/serv/serv_state.v b/fw/rtl/serv/serv_state.v
new file mode 100644
index 0000000..012a85e
--- /dev/null
+++ b/fw/rtl/serv/serv_state.v
@@ -0,0 +1,224 @@
+module serv_state
+ #(parameter RESET_STRATEGY = "MINI",
+ parameter [0:0] WITH_CSR = 1,
+ parameter [0:0] ALIGN =0,
+ parameter [0:0] MDU = 0,
+ parameter W = 1
+ )
+ (
+ input wire i_clk,
+ input wire i_rst,
+ //State
+ input wire i_new_irq,
+ input wire i_alu_cmp,
+ output wire o_init,
+ output reg o_cnt_en,
+ output wire o_cnt0to3,
+ output wire o_cnt12to31,
+ output wire o_cnt0,
+ output wire o_cnt1,
+ output wire o_cnt2,
+ output wire o_cnt3,
+ output wire o_cnt7,
+ output wire o_cnt_done,
+ output wire o_bufreg_en,
+ output wire o_ctrl_pc_en,
+ output reg o_ctrl_jump,
+ output wire o_ctrl_trap,
+ input wire i_ctrl_misalign,
+ input wire i_sh_done,
+ input wire i_sh_done_r,
+ output wire [1:0] o_mem_bytecnt,
+ input wire i_mem_misalign,
+ //Control
+ input wire i_bne_or_bge,
+ input wire i_cond_branch,
+ input wire i_dbus_en,
+ input wire i_two_stage_op,
+ input wire i_branch_op,
+ input wire i_shift_op,
+ input wire i_sh_right,
+ input wire i_slt_or_branch,
+ input wire i_e_op,
+ input wire i_rd_op,
+ //MDU
+ input wire i_mdu_op,
+ output wire o_mdu_valid,
+ //Extension
+ input wire i_mdu_ready,
+ //External
+ output wire o_dbus_cyc,
+ input wire i_dbus_ack,
+ output wire o_ibus_cyc,
+ input wire i_ibus_ack,
+ //RF Interface
+ output wire o_rf_rreq,
+ output wire o_rf_wreq,
+ input wire i_rf_ready,
+ output wire o_rf_rd_en);
+
+ reg stage_two_req;
+ reg init_done;
+ wire misalign_trap_sync;
+
+ reg [4:2] o_cnt;
+ reg [3:0] cnt_r;
+
+ reg ibus_cyc;
+ //Update PC in RUN or TRAP states
+ assign o_ctrl_pc_en = o_cnt_en & !o_init;
+
+ assign o_mem_bytecnt = o_cnt[4:3];
+
+ assign o_cnt0to3 = (o_cnt[4:2] == 3'd0);
+ assign o_cnt12to31 = (o_cnt[4] | (o_cnt[3:2] == 2'b11));
+ assign o_cnt0 = (o_cnt[4:2] == 3'd0) & cnt_r[0];
+ assign o_cnt1 = (o_cnt[4:2] == 3'd0) & cnt_r[1];
+ assign o_cnt2 = (o_cnt[4:2] == 3'd0) & cnt_r[2];
+ assign o_cnt3 = (o_cnt[4:2] == 3'd0) & cnt_r[3];
+ assign o_cnt7 = (o_cnt[4:2] == 3'd1) & cnt_r[3];
+
+ //Take branch for jump or branch instructions (opcode == 1x0xx) if
+ //a) It's an unconditional branch (opcode[0] == 1)
+ //b) It's a conditional branch (opcode[0] == 0) of type beq,blt,bltu (funct3[0] == 0) and ALU compare is true
+ //c) It's a conditional branch (opcode[0] == 0) of type bne,bge,bgeu (funct3[0] == 1) and ALU compare is false
+ //Only valid during the last cycle of INIT, when the branch condition has
+ //been calculated.
+ wire take_branch = i_branch_op & (!i_cond_branch | (i_alu_cmp^i_bne_or_bge));
+
+ //valid signal for mdu
+ assign o_mdu_valid = MDU & !o_cnt_en & init_done & i_mdu_op;
+
+ //Prepare RF for writes when everything is ready to enter stage two
+ // and the first stage didn't cause a misalign exception
+ assign o_rf_wreq = !misalign_trap_sync & !o_cnt_en & init_done &
+ ((i_shift_op & (i_sh_done | !i_sh_right)) |
+ i_dbus_ack | (MDU & i_mdu_ready) |
+ i_slt_or_branch);
+
+ assign o_dbus_cyc = !o_cnt_en & init_done & i_dbus_en & !i_mem_misalign;
+
+ //Prepare RF for reads when a new instruction is fetched
+ // or when stage one caused an exception (rreq implies a write request too)
+ assign o_rf_rreq = i_ibus_ack | (stage_two_req & misalign_trap_sync);
+
+ assign o_rf_rd_en = i_rd_op & !o_init;
+
+ /*
+ bufreg is used during mem. branch and shift operations
+
+ mem : bufreg is used for dbus address. Shift in data during phase 1.
+ Shift out during phase 2 if there was an misalignment exception.
+
+ branch : Shift in during phase 1. Shift out during phase 2
+
+ shift : Shift in during phase 1. Continue shifting between phases (except
+ for the first cycle after init). Shift out during phase 2
+ */
+ assign o_bufreg_en = (o_cnt_en & (o_init | ((o_ctrl_trap | i_branch_op) & i_two_stage_op))) | (i_shift_op & !stage_two_req & (i_sh_right | i_sh_done_r) & init_done);
+
+ assign o_ibus_cyc = ibus_cyc & !i_rst;
+
+ assign o_init = i_two_stage_op & !i_new_irq & !init_done;
+
+ assign o_cnt_done = (o_cnt[4:2] == 3'b111) & cnt_r[3];
+
+ always @(posedge i_clk) begin
+ //ibus_cyc changes on three conditions.
+ //1. i_rst is asserted. Together with the async gating above, o_ibus_cyc
+ // will be asserted as soon as the reset is released. This is how the
+ // first instruction is fetced
+ //2. o_cnt_done and o_ctrl_pc_en are asserted. This means that SERV just
+ // finished updating the PC, is done with the current instruction and
+ // o_ibus_cyc gets asserted to fetch a new instruction
+ //3. When i_ibus_ack, a new instruction is fetched and o_ibus_cyc gets
+ // deasserted to finish the transaction
+ if (i_ibus_ack | o_cnt_done | i_rst)
+ ibus_cyc <= o_ctrl_pc_en | i_rst;
+
+ if (o_cnt_done) begin
+ init_done <= o_init & !init_done;
+ o_ctrl_jump <= o_init & take_branch;
+ end
+
+ //Need a strobe for the first cycle in the IDLE state after INIT
+ stage_two_req <= o_cnt_done & o_init;
+
+ if (i_rst) begin
+ if (RESET_STRATEGY != "NONE") begin
+ init_done <= 1'b0;
+ o_ctrl_jump <= 1'b0;
+ stage_two_req <= 1'b0;
+ end
+ end
+ end
+
+ always @(posedge i_clk) begin
+ /*
+ Because SERV is 32-bit bit-serial we need a counter than can count 0-31
+ to keep track of which bit we are currently processing. o_cnt and cnt_r
+ are used together to create such a counter.
+ The top three bits (o_cnt) are implemented as a normal counter, but
+ instead of the two LSB, cnt_r is a 4-bit shift register which loops 0-3
+ When cnt_r[3] is 1, o_cnt will be increased.
+
+ The counting starts when the core is idle and the i_rf_ready signal
+ comes in from the RF module by shifting in the i_rf_ready bit as LSB of
+ the shift register. Counting is stopped by using o_cnt_done to block the
+ bit that was supposed to be shifted into bit 0 of cnt_r.
+
+ There are two benefit of doing the counter this way
+ 1. We only need to check four bits instead of five when we want to check
+ if the counter is at a certain value. For 4-LUT architectures this means
+ we only need one LUT instead of two for each comparison.
+ 2. We don't need a separate enable signal to turn on and off the counter
+ between stages, which saves an extra FF and a unique control signal. We
+ just need to check if cnt_r is not zero to see if the counter is
+ currently running
+ */
+ if (W == 4) begin
+ if (i_rf_ready) o_cnt_en <= 1; else
+ if (o_cnt_done) o_cnt_en <= 0;
+ o_cnt <= o_cnt + { 2'b0, o_cnt_en };
+ end else if (W == 1) begin
+ o_cnt <= o_cnt + {2'd0,cnt_r[3]};
+ cnt_r <= {cnt_r[2:0],(cnt_r[3] & !o_cnt_done) | (i_rf_ready & !o_cnt_en)};
+ end
+ if (i_rst) begin
+ if (RESET_STRATEGY != "NONE") begin
+ o_cnt <= 3'd0;
+ if (W == 1)
+ cnt_r <= 4'b0000;
+ else if (W == 4)
+ o_cnt_en <= 1'b0;
+ end
+ end
+ end
+
+ always @(*)
+ if (W == 1)
+ o_cnt_en = |cnt_r;
+ else if (W == 4)
+ cnt_r = 4'b1111;
+
+ assign o_ctrl_trap = WITH_CSR & (i_e_op | i_new_irq | misalign_trap_sync);
+
+ generate
+ if (WITH_CSR) begin : gen_csr
+ reg misalign_trap_sync_r;
+
+ //trap_pending is only guaranteed to have correct value during the
+ // last cycle of the init stage
+ wire trap_pending = WITH_CSR & ((take_branch & i_ctrl_misalign & !ALIGN) |
+ (i_dbus_en & i_mem_misalign));
+
+ always @(posedge i_clk) begin
+ if (i_ibus_ack | o_cnt_done | i_rst)
+ misalign_trap_sync_r <= !(i_ibus_ack | i_rst) & ((trap_pending & o_init) | misalign_trap_sync_r);
+ end
+ assign misalign_trap_sync = misalign_trap_sync_r;
+ end else begin : gen_no_csr
+ assign misalign_trap_sync = 1'b0;
+ end
+ endgenerate
+endmodule
diff --git a/fw/rtl/serv/serv_top.v b/fw/rtl/serv/serv_top.v
new file mode 100644
index 0000000..a4e9a90
--- /dev/null
+++ b/fw/rtl/serv/serv_top.v
@@ -0,0 +1,659 @@
+`default_nettype none
+
+module serv_top
+ #(parameter WITH_CSR = 1,
+ parameter PRE_REGISTER = 1,
+ parameter RESET_STRATEGY = "MINI",
+ parameter RESET_PC = 32'd0,
+ parameter [0:0] MDU = 1'b0,
+ parameter [0:0] COMPRESSED=0,
+ parameter [0:0] ALIGN = COMPRESSED)
+ (
+ input wire clk,
+ input wire i_rst,
+ input wire i_timer_irq,
+`ifdef RISCV_FORMAL
+ output reg rvfi_valid = 1'b0,
+ output reg [63:0] rvfi_order = 64'd0,
+ output reg [31:0] rvfi_insn = 32'd0,
+ output reg rvfi_trap = 1'b0,
+ output reg rvfi_halt = 1'b0,
+ output reg rvfi_intr = 1'b0,
+ output reg [1:0] rvfi_mode = 2'b11,
+ output reg [1:0] rvfi_ixl = 2'b01,
+ output reg [4:0] rvfi_rs1_addr,
+ output reg [4:0] rvfi_rs2_addr,
+ output reg [31:0] rvfi_rs1_rdata,
+ output reg [31:0] rvfi_rs2_rdata,
+ output reg [4:0] rvfi_rd_addr,
+ output reg [31:0] rvfi_rd_wdata,
+ output reg [31:0] rvfi_pc_rdata,
+ output reg [31:0] rvfi_pc_wdata,
+ output reg [31:0] rvfi_mem_addr,
+ output reg [3:0] rvfi_mem_rmask,
+ output reg [3:0] rvfi_mem_wmask,
+ output reg [31:0] rvfi_mem_rdata,
+ output reg [31:0] rvfi_mem_wdata,
+`endif
+ //RF Interface
+ output wire o_rf_rreq,
+ output wire o_rf_wreq,
+ input wire i_rf_ready,
+ output wire [4+WITH_CSR:0] o_wreg0,
+ output wire [4+WITH_CSR:0] o_wreg1,
+ output wire o_wen0,
+ output wire o_wen1,
+ output wire o_wdata0,
+ output wire o_wdata1,
+ output wire [4+WITH_CSR:0] o_rreg0,
+ output wire [4+WITH_CSR:0] o_rreg1,
+ input wire i_rdata0,
+ input wire i_rdata1,
+
+ output wire [31:0] o_ibus_adr,
+ output wire o_ibus_cyc,
+ input wire [31:0] i_ibus_rdt,
+ input wire i_ibus_ack,
+ output wire [31:0] o_dbus_adr,
+ output wire [31:0] o_dbus_dat,
+ output wire [3:0] o_dbus_sel,
+ output wire o_dbus_we ,
+ output wire o_dbus_cyc,
+ input wire [31:0] i_dbus_rdt,
+ input wire i_dbus_ack,
+ //Extension
+ output wire [ 2:0] o_ext_funct3,
+ input wire i_ext_ready,
+ input wire [31:0] i_ext_rd,
+ output wire [31:0] o_ext_rs1,
+ output wire [31:0] o_ext_rs2,
+ //MDU
+ output wire o_mdu_valid);
+
+ wire [4:0] rd_addr;
+ wire [4:0] rs1_addr;
+ wire [4:0] rs2_addr;
+
+ wire [3:0] immdec_ctrl;
+ wire [3:0] immdec_en;
+
+ wire sh_right;
+ wire bne_or_bge;
+ wire cond_branch;
+ wire two_stage_op;
+ wire e_op;
+ wire ebreak;
+ wire branch_op;
+ wire shift_op;
+ wire slt_or_branch;
+ wire rd_op;
+ wire mdu_op;
+
+ wire rd_alu_en;
+ wire rd_csr_en;
+ wire rd_mem_en;
+ wire ctrl_rd;
+ wire alu_rd;
+ wire mem_rd;
+ wire csr_rd;
+ wire mtval_pc;
+
+ wire ctrl_pc_en;
+ wire jump;
+ wire jal_or_jalr;
+ wire utype;
+ wire mret;
+ wire imm;
+ wire trap;
+ wire pc_rel;
+ wire iscomp;
+
+ wire init;
+ wire cnt_en;
+ wire cnt0to3;
+ wire cnt12to31;
+ wire cnt0;
+ wire cnt1;
+ wire cnt2;
+ wire cnt3;
+ wire cnt7;
+
+ wire cnt_done;
+
+ wire bufreg_en;
+ wire bufreg_sh_signed;
+ wire bufreg_rs1_en;
+ wire bufreg_imm_en;
+ wire bufreg_clr_lsb;
+ wire bufreg_q;
+ wire bufreg2_q;
+ wire [31:0] dbus_rdt;
+ wire dbus_ack;
+
+ wire alu_sub;
+ wire [1:0] alu_bool_op;
+ wire alu_cmp_eq;
+ wire alu_cmp_sig;
+ wire alu_cmp;
+ wire [2:0] alu_rd_sel;
+
+ wire rs1;
+ wire rs2;
+ wire rd_en;
+
+ wire op_b;
+ wire op_b_sel;
+
+ wire mem_signed;
+ wire mem_word;
+ wire mem_half;
+ wire [1:0] mem_bytecnt;
+ wire sh_done;
+ wire sh_done_r;
+ wire byte_valid;
+
+ wire mem_misalign;
+
+ wire bad_pc;
+
+ wire csr_mstatus_en;
+ wire csr_mie_en;
+ wire csr_mcause_en;
+ wire [1:0] csr_source;
+ wire csr_imm;
+ wire csr_d_sel;
+ wire csr_en;
+ wire [1:0] csr_addr;
+ wire csr_pc;
+ wire csr_imm_en;
+ wire csr_in;
+ wire rf_csr_out;
+ wire dbus_en;
+
+ wire new_irq;
+
+ wire [1:0] lsb;
+
+ wire [31:0] i_wb_rdt;
+
+ wire [31:0] wb_ibus_adr;
+ wire wb_ibus_cyc;
+ wire [31:0] wb_ibus_rdt;
+ wire wb_ibus_ack;
+
+ generate
+ if (ALIGN) begin : gen_align
+ serv_aligner align
+ (
+ .clk(clk),
+ .rst(i_rst),
+ // serv_rf_top
+ .i_ibus_adr(wb_ibus_adr),
+ .i_ibus_cyc(wb_ibus_cyc),
+ .o_ibus_rdt(wb_ibus_rdt),
+ .o_ibus_ack(wb_ibus_ack),
+ // servant_arbiter
+ .o_wb_ibus_adr(o_ibus_adr),
+ .o_wb_ibus_cyc(o_ibus_cyc),
+ .i_wb_ibus_rdt(i_ibus_rdt),
+ .i_wb_ibus_ack(i_ibus_ack));
+ end else begin : gen_no_align
+ assign o_ibus_adr = wb_ibus_adr;
+ assign o_ibus_cyc = wb_ibus_cyc;
+ assign wb_ibus_rdt = i_ibus_rdt;
+ assign wb_ibus_ack = i_ibus_ack;
+ end
+ endgenerate
+
+ generate
+ if (COMPRESSED) begin : gen_compressed
+ serv_compdec compdec
+ (
+ .i_clk(clk),
+ .i_instr(wb_ibus_rdt),
+ .i_ack(wb_ibus_ack),
+ .o_instr(i_wb_rdt),
+ .o_iscomp(iscomp));
+ end else begin : gen_no_compressed
+ assign i_wb_rdt = wb_ibus_rdt;
+ assign iscomp = 1'b0;
+ end
+ endgenerate
+
+ serv_state
+ #(.RESET_STRATEGY (RESET_STRATEGY),
+ .WITH_CSR (WITH_CSR[0:0]),
+ .MDU(MDU),
+ .ALIGN(ALIGN))
+ state
+ (
+ .i_clk (clk),
+ .i_rst (i_rst),
+ //State
+ .i_new_irq (new_irq),
+ .i_alu_cmp (alu_cmp),
+ .o_init (init),
+ .o_cnt_en (cnt_en),
+ .o_cnt0to3 (cnt0to3),
+ .o_cnt12to31 (cnt12to31),
+ .o_cnt0 (cnt0),
+ .o_cnt1 (cnt1),
+ .o_cnt2 (cnt2),
+ .o_cnt3 (cnt3),
+ .o_cnt7 (cnt7),
+ .o_cnt_done (cnt_done),
+ .o_bufreg_en (bufreg_en),
+ .o_ctrl_pc_en (ctrl_pc_en),
+ .o_ctrl_jump (jump),
+ .o_ctrl_trap (trap),
+ .i_ctrl_misalign(lsb[1]),
+ .i_sh_done (sh_done),
+ .i_sh_done_r (sh_done_r),
+ .o_mem_bytecnt (mem_bytecnt),
+ .i_mem_misalign (mem_misalign),
+ //Control
+ .i_bne_or_bge (bne_or_bge),
+ .i_cond_branch (cond_branch),
+ .i_dbus_en (dbus_en),
+ .i_two_stage_op (two_stage_op),
+ .i_branch_op (branch_op),
+ .i_shift_op (shift_op),
+ .i_sh_right (sh_right),
+ .i_slt_or_branch (slt_or_branch),
+ .i_e_op (e_op),
+ .i_rd_op (rd_op),
+ //MDU
+ .i_mdu_op (mdu_op),
+ .o_mdu_valid (o_mdu_valid),
+ //Extension
+ .i_mdu_ready (i_ext_ready),
+ //External
+ .o_dbus_cyc (o_dbus_cyc),
+ .i_dbus_ack (i_dbus_ack),
+ .o_ibus_cyc (wb_ibus_cyc),
+ .i_ibus_ack (wb_ibus_ack),
+ //RF Interface
+ .o_rf_rreq (o_rf_rreq),
+ .o_rf_wreq (o_rf_wreq),
+ .i_rf_ready (i_rf_ready),
+ .o_rf_rd_en (rd_en));
+
+ serv_decode
+ #(.PRE_REGISTER (PRE_REGISTER),
+ .MDU(MDU))
+ decode
+ (
+ .clk (clk),
+ //Input
+ .i_wb_rdt (i_wb_rdt[31:2]),
+ .i_wb_en (wb_ibus_ack),
+ //To state
+ .o_bne_or_bge (bne_or_bge),
+ .o_cond_branch (cond_branch),
+ .o_dbus_en (dbus_en),
+ .o_e_op (e_op),
+ .o_ebreak (ebreak),
+ .o_branch_op (branch_op),
+ .o_shift_op (shift_op),
+ .o_slt_or_branch (slt_or_branch),
+ .o_rd_op (rd_op),
+ .o_sh_right (sh_right),
+ .o_mdu_op (mdu_op),
+ .o_two_stage_op (two_stage_op),
+ //Extension
+ .o_ext_funct3 (o_ext_funct3),
+
+ //To bufreg
+ .o_bufreg_rs1_en (bufreg_rs1_en),
+ .o_bufreg_imm_en (bufreg_imm_en),
+ .o_bufreg_clr_lsb (bufreg_clr_lsb),
+ .o_bufreg_sh_signed (bufreg_sh_signed),
+ //To bufreg2
+ .o_op_b_source (op_b_sel),
+ //To ctrl
+ .o_ctrl_jal_or_jalr (jal_or_jalr),
+ .o_ctrl_utype (utype),
+ .o_ctrl_pc_rel (pc_rel),
+ .o_ctrl_mret (mret),
+ //To alu
+ .o_alu_sub (alu_sub),
+ .o_alu_bool_op (alu_bool_op),
+ .o_alu_cmp_eq (alu_cmp_eq),
+ .o_alu_cmp_sig (alu_cmp_sig),
+ .o_alu_rd_sel (alu_rd_sel),
+ //To mem IF
+ .o_mem_cmd (o_dbus_we),
+ .o_mem_signed (mem_signed),
+ .o_mem_word (mem_word),
+ .o_mem_half (mem_half),
+ //To CSR
+ .o_csr_en (csr_en),
+ .o_csr_addr (csr_addr),
+ .o_csr_mstatus_en (csr_mstatus_en),
+ .o_csr_mie_en (csr_mie_en),
+ .o_csr_mcause_en (csr_mcause_en),
+ .o_csr_source (csr_source),
+ .o_csr_d_sel (csr_d_sel),
+ .o_csr_imm_en (csr_imm_en),
+ .o_mtval_pc (mtval_pc ),
+ //To top
+ .o_immdec_ctrl (immdec_ctrl),
+ .o_immdec_en (immdec_en),
+ //To RF IF
+ .o_rd_mem_en (rd_mem_en),
+ .o_rd_csr_en (rd_csr_en),
+ .o_rd_alu_en (rd_alu_en));
+
+ serv_immdec immdec
+ (
+ .i_clk (clk),
+ //State
+ .i_cnt_en (cnt_en),
+ .i_cnt_done (cnt_done),
+ //Control
+ .i_immdec_en (immdec_en),
+ .i_csr_imm_en (csr_imm_en),
+ .i_ctrl (immdec_ctrl),
+ .o_rd_addr (rd_addr),
+ .o_rs1_addr (rs1_addr),
+ .o_rs2_addr (rs2_addr),
+ //Data
+ .o_csr_imm (csr_imm),
+ .o_imm (imm),
+ //External
+ .i_wb_en (wb_ibus_ack),
+ .i_wb_rdt (i_wb_rdt[31:7]));
+
+ serv_bufreg
+ #(.MDU(MDU))
+ bufreg
+ (
+ .i_clk (clk),
+ //State
+ .i_cnt0 (cnt0),
+ .i_cnt1 (cnt1),
+ .i_en (bufreg_en),
+ .i_init (init),
+ .i_mdu_op (mdu_op),
+ .o_lsb (lsb),
+ //Control
+ .i_sh_signed (bufreg_sh_signed),
+ .i_rs1_en (bufreg_rs1_en),
+ .i_imm_en (bufreg_imm_en),
+ .i_clr_lsb (bufreg_clr_lsb),
+ //Data
+ .i_rs1 (rs1),
+ .i_imm (imm),
+ .o_q (bufreg_q),
+ //External
+ .o_dbus_adr (o_dbus_adr),
+ .o_ext_rs1 (o_ext_rs1));
+
+ serv_bufreg2 bufreg2
+ (
+ .i_clk (clk),
+ //State
+ .i_en (cnt_en),
+ .i_init (init),
+ .i_cnt_done (cnt_done),
+ .i_lsb (lsb),
+ .i_byte_valid (byte_valid),
+ .o_sh_done (sh_done),
+ .o_sh_done_r (sh_done_r),
+ //Control
+ .i_op_b_sel (op_b_sel),
+ .i_shift_op (shift_op),
+ //Data
+ .i_rs2 (rs2),
+ .i_imm (imm),
+ .o_op_b (op_b),
+ .o_q (bufreg2_q),
+ //External
+ .o_dat (o_dbus_dat),
+ .i_load (dbus_ack),
+ .i_dat (dbus_rdt));
+
+ serv_ctrl
+ #(.RESET_PC (RESET_PC),
+ .RESET_STRATEGY (RESET_STRATEGY),
+ .WITH_CSR (WITH_CSR))
+ ctrl
+ (
+ .clk (clk),
+ .i_rst (i_rst),
+ //State
+ .i_pc_en (ctrl_pc_en),
+ .i_cnt12to31 (cnt12to31),
+ .i_cnt0 (cnt0),
+ .i_cnt1 (cnt1),
+ .i_cnt2 (cnt2),
+ //Control
+ .i_jump (jump),
+ .i_jal_or_jalr (jal_or_jalr),
+ .i_utype (utype),
+ .i_pc_rel (pc_rel),
+ .i_trap (trap | mret),
+ .i_iscomp (iscomp),
+ //Data
+ .i_imm (imm),
+ .i_buf (bufreg_q),
+ .i_csr_pc (csr_pc),
+ .o_rd (ctrl_rd),
+ .o_bad_pc (bad_pc),
+ //External
+ .o_ibus_adr (wb_ibus_adr));
+
+ serv_alu alu
+ (
+ .clk (clk),
+ //State
+ .i_en (cnt_en),
+ .i_cnt0 (cnt0),
+ .o_cmp (alu_cmp),
+ //Control
+ .i_sub (alu_sub),
+ .i_bool_op (alu_bool_op),
+ .i_cmp_eq (alu_cmp_eq),
+ .i_cmp_sig (alu_cmp_sig),
+ .i_rd_sel (alu_rd_sel),
+ //Data
+ .i_rs1 (rs1),
+ .i_op_b (op_b),
+ .i_buf (bufreg_q),
+ .o_rd (alu_rd));
+
+ serv_rf_if
+ #(.WITH_CSR (WITH_CSR))
+ rf_if
+ (//RF interface
+ .i_cnt_en (cnt_en),
+ .o_wreg0 (o_wreg0),
+ .o_wreg1 (o_wreg1),
+ .o_wen0 (o_wen0),
+ .o_wen1 (o_wen1),
+ .o_wdata0 (o_wdata0),
+ .o_wdata1 (o_wdata1),
+ .o_rreg0 (o_rreg0),
+ .o_rreg1 (o_rreg1),
+ .i_rdata0 (i_rdata0),
+ .i_rdata1 (i_rdata1),
+
+ //Trap interface
+ .i_trap (trap),
+ .i_mret (mret),
+ .i_mepc (wb_ibus_adr[0]),
+ .i_mtval_pc (mtval_pc),
+ .i_bufreg_q (bufreg_q),
+ .i_bad_pc (bad_pc),
+ .o_csr_pc (csr_pc),
+ //CSR write port
+ .i_csr_en (csr_en),
+ .i_csr_addr (csr_addr),
+ .i_csr (csr_in),
+ //RD write port
+ .i_rd_wen (rd_en),
+ .i_rd_waddr (rd_addr),
+ .i_ctrl_rd (ctrl_rd),
+ .i_alu_rd (alu_rd),
+ .i_rd_alu_en (rd_alu_en),
+ .i_csr_rd (csr_rd),
+ .i_rd_csr_en (rd_csr_en),
+ .i_mem_rd (mem_rd),
+ .i_rd_mem_en (rd_mem_en),
+
+ //RS1 read port
+ .i_rs1_raddr (rs1_addr),
+ .o_rs1 (rs1),
+ //RS2 read port
+ .i_rs2_raddr (rs2_addr),
+ .o_rs2 (rs2),
+
+ //CSR read port
+ .o_csr (rf_csr_out));
+
+ serv_mem_if
+ #(.WITH_CSR (WITH_CSR[0:0]))
+ mem_if
+ (
+ .i_clk (clk),
+ //State
+ .i_bytecnt (mem_bytecnt),
+ .i_lsb (lsb),
+ .o_byte_valid (byte_valid),
+ .o_misalign (mem_misalign),
+ //Control
+ .i_mdu_op (mdu_op),
+ .i_signed (mem_signed),
+ .i_word (mem_word),
+ .i_half (mem_half),
+ //Data
+ .i_bufreg2_q (bufreg2_q),
+ .o_rd (mem_rd),
+ //External interface
+ .o_wb_sel (o_dbus_sel));
+
+ generate
+ if (|WITH_CSR) begin : gen_csr
+ serv_csr
+ #(.RESET_STRATEGY (RESET_STRATEGY))
+ csr
+ (
+ .i_clk (clk),
+ .i_rst (i_rst),
+ //State
+ .i_trig_irq (wb_ibus_ack),
+ .i_en (cnt_en),
+ .i_cnt0to3 (cnt0to3),
+ .i_cnt3 (cnt3),
+ .i_cnt7 (cnt7),
+ .i_cnt_done (cnt_done),
+ .i_mem_op (!mtval_pc),
+ .i_mtip (i_timer_irq),
+ .i_trap (trap),
+ .o_new_irq (new_irq),
+ //Control
+ .i_e_op (e_op),
+ .i_ebreak (ebreak),
+ .i_mem_cmd (o_dbus_we),
+ .i_mstatus_en (csr_mstatus_en),
+ .i_mie_en (csr_mie_en ),
+ .i_mcause_en (csr_mcause_en ),
+ .i_csr_source (csr_source),
+ .i_mret (mret),
+ .i_csr_d_sel (csr_d_sel),
+ //Data
+ .i_rf_csr_out (rf_csr_out),
+ .o_csr_in (csr_in),
+ .i_csr_imm (csr_imm),
+ .i_rs1 (rs1),
+ .o_q (csr_rd));
+ end else begin : gen_no_csr
+ assign csr_in = 1'b0;
+ assign csr_rd = 1'b0;
+ assign new_irq = 1'b0;
+ end
+ endgenerate
+
+
+`ifdef RISCV_FORMAL
+ reg [31:0] pc = RESET_PC;
+
+ wire rs_en = two_stage_op ? init : ctrl_pc_en;
+
+ always @(posedge clk) begin
+ /* End of instruction */
+ rvfi_valid <= cnt_done & ctrl_pc_en & !i_rst;
+ rvfi_order <= rvfi_order + {63'd0,rvfi_valid};
+
+ /* Get instruction word when it's fetched from ibus */
+ if (wb_ibus_cyc & wb_ibus_ack)
+ rvfi_insn <= i_wb_rdt;
+
+ /* Store data written to rd */
+ if (o_wen0)
+ rvfi_rd_wdata <= {o_wdata0,rvfi_rd_wdata[31:1]};
+
+ if (cnt_done & ctrl_pc_en) begin
+ rvfi_pc_rdata <= pc;
+ if (!(rd_en & (|rd_addr))) begin
+ rvfi_rd_addr <= 5'd0;
+ rvfi_rd_wdata <= 32'd0;
+ end
+ end
+ rvfi_trap <= trap;
+ if (rvfi_valid) begin
+ rvfi_trap <= 1'b0;
+ pc <= rvfi_pc_wdata;
+ end
+
+ /* Not used */
+ rvfi_halt <= 1'b0;
+ rvfi_intr <= 1'b0;
+ rvfi_mode <= 2'd3;
+ rvfi_ixl = 2'd1;
+
+ /* RS1 not valid during J, U instructions (immdec_en[1]) */
+ /* RS2 not valid during I, J, U instructions (immdec_en[2]) */
+ if (i_rf_ready) begin
+ rvfi_rs1_addr <= !immdec_en[1] ? rs1_addr : 5'd0;
+ rvfi_rs2_addr <= !immdec_en[2] /*rs2_valid*/ ? rs2_addr : 5'd0;
+ rvfi_rd_addr <= rd_addr;
+ end
+ if (rs_en) begin
+ rvfi_rs1_rdata <= {!immdec_en[1] & rs1,rvfi_rs1_rdata[31:1]};
+ rvfi_rs2_rdata <= {!immdec_en[2] & rs2,rvfi_rs2_rdata[31:1]};
+ end
+
+ if (i_dbus_ack) begin
+ rvfi_mem_addr <= o_dbus_adr;
+ rvfi_mem_rmask <= o_dbus_we ? 4'b0000 : o_dbus_sel;
+ rvfi_mem_wmask <= o_dbus_we ? o_dbus_sel : 4'b0000;
+ rvfi_mem_rdata <= i_dbus_rdt;
+ rvfi_mem_wdata <= o_dbus_dat;
+ end
+ if (wb_ibus_ack) begin
+ rvfi_mem_rmask <= 4'b0000;
+ rvfi_mem_wmask <= 4'b0000;
+ end
+ end
+ /* verilator lint_off COMBDLY */
+ always @(wb_ibus_adr)
+ rvfi_pc_wdata <= wb_ibus_adr;
+ /* verilator lint_on COMBDLY */
+
+
+`endif
+
+generate
+ if (MDU) begin: gen_mdu
+ assign dbus_rdt = i_ext_ready ? i_ext_rd:i_dbus_rdt;
+ assign dbus_ack = i_dbus_ack | i_ext_ready;
+ end else begin : gen_no_mdu
+ assign dbus_rdt = i_dbus_rdt;
+ assign dbus_ack = i_dbus_ack;
+ end
+ assign o_ext_rs2 = o_dbus_dat;
+endgenerate
+
+endmodule
+`default_nettype wire
diff --git a/fw/rtl/top.sv b/fw/rtl/top.sv
index 7cad9ad..d00ac60 100644
--- a/fw/rtl/top.sv
+++ b/fw/rtl/top.sv
@@ -14,6 +14,9 @@ module top (
input n64_si_clk,
inout n64_si_dq,
+ input n64_cic_clk,
+ inout n64_cic_dq,
+
input usb_pwrsav,
output usb_clk,
output usb_cs,
@@ -48,8 +51,6 @@ module top (
output mcu_miso,
// Unused I/O
- output n64_cic_clk,
- output n64_cic_dq,
output n64_video_sync
);
@@ -137,7 +138,10 @@ module top (
.n64_pi_ad(n64_pi_ad),
.n64_si_clk(n64_si_clk),
- .n64_si_dq(n64_si_dq)
+ .n64_si_dq(n64_si_dq),
+
+ .n64_cic_clk(n64_cic_clk),
+ .n64_cic_dq(n64_cic_dq)
);
@@ -272,8 +276,6 @@ module top (
// Unused I/O
- assign n64_cic_clk = 1'bZ;
- assign n64_cic_dq = 1'bZ;
assign n64_video_sync = 1'bZ;
endmodule
diff --git a/sw/bootloader/Makefile b/sw/bootloader/Makefile
index aa0a74b..2f97b5a 100644
--- a/sw/bootloader/Makefile
+++ b/sw/bootloader/Makefile
@@ -1,4 +1,4 @@
-TOOLCHAIN = mips64-elf-
+TOOLCHAIN = $(N64_INST)/bin/mips64-elf-
CC = $(TOOLCHAIN)gcc
CXX = $(TOOLCHAIN)g++
OBJCOPY = $(TOOLCHAIN)objcopy
diff --git a/sw/cic/.gitignore b/sw/cic/.gitignore
new file mode 100644
index 0000000..58e68f7
--- /dev/null
+++ b/sw/cic/.gitignore
@@ -0,0 +1,4 @@
+*.bin
+*.elf
+*.lst
+*.mem
diff --git a/sw/cic/build.sh b/sw/cic/build.sh
new file mode 100755
index 0000000..5e370a8
--- /dev/null
+++ b/sw/cic/build.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+set -e
+
+TOOLCHAIN="riscv32-unknown-elf-"
+CFLAGS=" \
+ -march=rv32i \
+ -mabi=ilp32 \
+ -Os \
+ -Wl,--gc-sections \
+ -ffunction-sections \
+ -fdata-sections \
+ -ffreestanding \
+ -nostartfiles \
+ -nostdlib \
+ -nodefaultlibs \
+ -fno-builtin \
+ -mcmodel=medany \
+"
+
+case "$1" in
+ all)
+ ${TOOLCHAIN}gcc $CFLAGS -T cic.ld -o cic.elf startup.S cic.c
+ echo "Size of cic:"
+ ${TOOLCHAIN}size -B -d cic.elf
+ ${TOOLCHAIN}objdump -S -D cic.elf > cic.lst
+ ${TOOLCHAIN}objcopy -O binary cic.elf cic.bin
+ python3 ./convert.py cic.bin cic.mem
+ ;;
+ clean)
+ rm -f cic.elf cic.lst cic.bin cic.mem
+ ;;
+esac
diff --git a/sw/cic/cic.c b/sw/cic/cic.c
new file mode 100644
index 0000000..0da7fc8
--- /dev/null
+++ b/sw/cic/cic.c
@@ -0,0 +1,361 @@
+// Original code sourced from https://github.com/jago85/UltraCIC_C
+
+// MIT License
+
+// Copyright (c) 2019 Jan Goldacker
+// Copyright (c) 2022-2023 Mateusz Faderewski
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+#include
+#include
+#include
+
+
+typedef struct {
+ volatile uint32_t CIC_CONFIG[2];
+ volatile uint32_t GPIO;
+} ext_regs_t;
+
+#define EXT ((ext_regs_t *) (0xC0000000UL))
+
+#define CIC_DQ (1 << 0)
+#define CIC_CLK (1 << 1)
+#define CIC_RESET (1 << 2)
+#define CIC_INVALID_REGION (1 << 3)
+
+#define CIC_IS_RUNNING() (EXT->GPIO & CIC_RESET)
+#define CIC_CLK_WAIT_LOW() { while ((EXT->GPIO & (CIC_RESET | CIC_CLK)) == (CIC_RESET | CIC_CLK)); }
+#define CIC_CLK_WAIT_HIGH() { while ((EXT->GPIO & (CIC_RESET | CIC_CLK)) == CIC_RESET); }
+#define CIC_DQ_GET() (EXT->GPIO & CIC_DQ)
+#define CIC_DQ_SET(v) { EXT->GPIO = ((v) ? CIC_DQ : 0); }
+#define CIC_CLK_GET() (EXT->GPIO & (CIC_RESET | CIC_CLK))
+#define CIC_NOTIFY_INVALID_REGION() { EXT->GPIO = (CIC_INVALID_REGION | CIC_DQ); }
+
+
+typedef struct {
+ bool cic_disabled;
+ bool cic_64dd_mode;
+ bool cic_region;
+ uint8_t cic_seed;
+ uint8_t cic_checksum[6];
+} cic_config_t;
+
+static cic_config_t config;
+
+static uint8_t cic_ram[32];
+static uint8_t cic_x105_ram[30];
+
+static const uint8_t cic_ram_init[2][32] = {{
+ 0xE, 0x0, 0x9, 0xA, 0x1, 0x8, 0x5, 0xA, 0x1, 0x3, 0xE, 0x1, 0x0, 0xD, 0xE, 0xC,
+ 0x0, 0xB, 0x1, 0x4, 0xF, 0x8, 0xB, 0x5, 0x7, 0xC, 0xD, 0x6, 0x1, 0xE, 0x9, 0x8
+}, {
+ 0xE, 0x0, 0x4, 0xF, 0x5, 0x1, 0x2, 0x1, 0x7, 0x1, 0x9, 0x8, 0x5, 0x7, 0x5, 0xA,
+ 0x0, 0xB, 0x1, 0x2, 0x3, 0xF, 0x8, 0x2, 0x7, 0x1, 0x9, 0x8, 0x1, 0x1, 0x5, 0xC
+}};
+
+
+static void cic_die (void) {
+ while (CIC_IS_RUNNING());
+}
+
+static void cic_init (void) {
+ CIC_DQ_SET(1);
+
+ while (!CIC_IS_RUNNING());
+
+ uint32_t cic_config[2];
+
+ cic_config[0] = EXT->CIC_CONFIG[0];
+ cic_config[1] = EXT->CIC_CONFIG[1];
+
+ config.cic_disabled = (cic_config[0] & (1 << 26));
+ config.cic_64dd_mode = (cic_config[0] & (1 << 25));
+ config.cic_region = (cic_config[0] & (1 << 24));
+ config.cic_seed = ((cic_config[0] >> 16) & 0xFF);
+ config.cic_checksum[0] = ((cic_config[0] >> 8) & 0xFF);
+ config.cic_checksum[1] = (cic_config[0] & 0xFF);
+ config.cic_checksum[2] = ((cic_config[1] >> 24) & 0xFF);
+ config.cic_checksum[3] = ((cic_config[1] >> 16) & 0xFF);
+ config.cic_checksum[4] = ((cic_config[1] >> 8) & 0xFF);
+ config.cic_checksum[5] = (cic_config[1] & 0xFF);
+
+ if (config.cic_disabled) {
+ cic_die();
+ }
+}
+
+static uint8_t cic_read (void) {
+ uint8_t value;
+ CIC_CLK_WAIT_LOW();
+ value = CIC_DQ_GET() ? 1 : 0;
+ CIC_CLK_WAIT_HIGH();
+ return value;
+}
+
+static void cic_write (uint8_t value) {
+ CIC_CLK_WAIT_LOW();
+ CIC_DQ_SET(value);
+ CIC_CLK_WAIT_HIGH();
+ CIC_DQ_SET(1);
+}
+
+static uint8_t cic_read_nibble (void) {
+ uint8_t data = 0;
+ for (int i = 0; i < 4; i++) {
+ data = ((data << 1) | cic_read());
+ }
+ return data;
+}
+
+static void cic_write_nibble (uint8_t data) {
+ cic_write(data & 0x08);
+ cic_write(data & 0x04);
+ cic_write(data & 0x02);
+ cic_write(data & 0x01);
+}
+
+static void cic_write_ram_nibbles (uint8_t index) {
+ do {
+ cic_write_nibble(cic_ram[index++]);
+ } while ((index & 0x0F) != 0);
+}
+
+static void cic_encode_round (uint8_t index) {
+ uint8_t data = cic_ram[index++];
+ do {
+ data = ((((data + 1) & 0x0F) + cic_ram[index]) & 0x0F);
+ cic_ram[index++] = data;
+ } while ((index & 0x0F) != 0);
+}
+
+static void cic_write_id (void) {
+ if (config.cic_64dd_mode) {
+ CIC_CLK_WAIT_LOW();
+ while (CIC_CLK_GET() == CIC_RESET) {
+ if (!CIC_DQ_GET()) {
+ cic_die();
+ }
+ }
+ } else {
+ cic_write(0);
+ }
+ cic_write(config.cic_region ? 1 : 0);
+ cic_write(0);
+ cic_write(1);
+}
+
+static void cic_write_seed (void) {
+ cic_ram[0x0A] = 0x0B;
+ cic_ram[0x0B] = 0x05;
+ cic_ram[0x0C] = (config.cic_seed >> 4);
+ cic_ram[0x0D] = config.cic_seed;
+ cic_ram[0x0E] = (config.cic_seed >> 4);
+ cic_ram[0x0F] = config.cic_seed;
+ cic_encode_round(0x0A);
+ cic_encode_round(0x0A);
+
+ uint32_t timeout = 100000;
+ do {
+ if (timeout == 0) {
+ CIC_NOTIFY_INVALID_REGION();
+ cic_die();
+ }
+ } while (timeout-- && (CIC_CLK_GET() == (CIC_RESET | CIC_CLK)));
+
+ cic_write_ram_nibbles(0x0A);
+}
+
+static void cic_write_checksum (void) {
+ for (int i = 0; i < 4; i++) {
+ cic_ram[i] = 0x00;
+ }
+ for (int i = 0; i < 6; i++) {
+ cic_ram[(i * 2) + 4] = ((config.cic_checksum[i] >> 4) & 0x0F);
+ cic_ram[(i * 2) + 5] = (config.cic_checksum[i] & 0x0F);
+ }
+ cic_encode_round(0x00);
+ cic_encode_round(0x00);
+ cic_encode_round(0x00);
+ cic_encode_round(0x00);
+ cic_write(0);
+ cic_write_ram_nibbles(0x00);
+}
+
+static void cic_init_ram (void) {
+ for (int i = 0; i < 32; i++) {
+ cic_ram[i] = cic_ram_init[config.cic_region ? 1 : 0][i];
+ }
+ cic_ram[0x01] = cic_read_nibble();
+ cic_ram[0x11] = cic_read_nibble();
+}
+
+static void cic_exchange_bytes (uint8_t *a, uint8_t *b) {
+ uint8_t tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+static void cic_round (uint8_t *m) {
+ uint8_t a, b, x;
+
+ x = m[15];
+ a = x;
+
+ do {
+ b = 1;
+ a += (m[b] + 1);
+ m[b] = a;
+ b++;
+ a += (m[b] + 1);
+ cic_exchange_bytes(&a, &m[b]);
+ m[b] = ~(m[b]);
+ b++;
+ a &= 0x0F;
+ a += ((m[b] & 0x0F) + 1);
+ if (a < 16) {
+ cic_exchange_bytes(&a, &m[b]);
+ b++;
+ }
+ a += m[b];
+ m[b] = a;
+ b++;
+ a += m[b];
+ cic_exchange_bytes(&a, &m[b]);
+ b++;
+ a &= 0x0F;
+ a += 8;
+ if (a < 16) {
+ a += m[b];
+ }
+ cic_exchange_bytes(&a, &m[b]);
+ b++;
+ do {
+ a += (m[b] + 1);
+ m[b] = a;
+ b++;
+ b &= 0x0F;
+ } while (b != 0);
+ a = (x + 0x0F);
+ x = (a & 0x0F);
+ } while (x != 0x0F);
+}
+
+static void cic_compare_mode (void) {
+ cic_round(&cic_ram[0x10]);
+ cic_round(&cic_ram[0x10]);
+ cic_round(&cic_ram[0x10]);
+
+ uint8_t index = (cic_ram[0x17] & 0x0F);
+ if (index == 0) {
+ index = 1;
+ }
+ index |= 0x10;
+
+ do {
+ cic_read();
+ cic_write(cic_ram[index] & 0x01);
+ if (config.cic_region) {
+ index--;
+ } else {
+ index++;
+ }
+ } while (index & 0x0F);
+}
+
+static void cic_x105_algorithm (void) {
+ uint8_t a = 5;
+ uint8_t carry = 1;
+
+ for (int i = 0; i < 30; ++i) {
+ if (!(cic_x105_ram[i] & 0x01)) {
+ a += 8;
+ }
+ if (!(a & 0x02)) {
+ a += 4;
+ }
+ a = ((a + cic_x105_ram[i]) & 0x0F);
+ cic_x105_ram[i] = a;
+ if (!carry) {
+ a += 7;
+ }
+ a = ((a + cic_x105_ram[i]) & 0x0F);
+ a = (a + cic_x105_ram[i] + carry);
+ if (a >= 0x10) {
+ carry = 1;
+ a -= 0x10;
+ } else {
+ carry = 0;
+ }
+ a = (~(a) & 0x0F);
+ cic_x105_ram[i] = a;
+ }
+}
+
+static void cic_x105_mode (void) {
+ cic_write_nibble(0x0A);
+ cic_write_nibble(0x0A);
+
+ for (int i = 0; i < 30; i++) {
+ cic_x105_ram[i] = cic_read_nibble();
+ }
+
+ cic_x105_algorithm();
+
+ cic_write(0);
+
+ for (int i = 0; i < 30; i++) {
+ cic_write_nibble(cic_x105_ram[i]);
+ }
+}
+
+static void cic_soft_reset (void) {
+ volatile uint32_t timeout = 100000;
+ CIC_CLK_WAIT_LOW();
+ while ((timeout--) && CIC_IS_RUNNING());
+ cic_write(0);
+}
+
+
+__attribute__((naked)) void cic_main (void) {
+ while (true) {
+ cic_init();
+
+ cic_write_id();
+ cic_write_seed();
+ cic_write_checksum();
+ cic_init_ram();
+
+ while (CIC_IS_RUNNING()) {
+ uint8_t cmd = 0;
+ cmd |= (cic_read() << 1);
+ cmd |= cic_read();
+
+ if (cmd == 0) {
+ cic_compare_mode();
+ } else if (cmd == 2) {
+ cic_x105_mode();
+ } else if (cmd == 3) {
+ cic_soft_reset();
+ } else {
+ cic_die();
+ }
+ }
+ }
+}
diff --git a/sw/cic/cic.ld b/sw/cic/cic.ld
new file mode 100644
index 0000000..466bfb6
--- /dev/null
+++ b/sw/cic/cic.ld
@@ -0,0 +1,51 @@
+OUTPUT_ARCH("riscv")
+OUTPUT_FORMAT("elf32-littleriscv")
+
+MEMORY {
+ ram (rwx) : org = 0x80000000, len = 2k
+}
+
+ENTRY(entry_handler)
+
+SECTIONS {
+ .text : {
+ *(.text.entry_handler)
+ *(.text .text.* .gnu.linkonce.t.*)
+ . = ALIGN(4);
+ *(.rodata .rodata.* .gnu.linkonce.r.*)
+ *(.rodata1)
+ . = ALIGN(4);
+ } > ram : text
+
+ .data : {
+ . = ALIGN(4);
+ *(.sdata2 .sdata2.* .gnu.linkonce.s2.*)
+ *(.data1)
+ *(.data .data.* .gnu.linkonce.d.*)
+ . = ALIGN(4);
+ } > ram : data
+
+ .bss : {
+ . = ALIGN(4);
+ _sbss = .;
+ *(.dynsbss)
+ *(.sbss .sbss.* .gnu.linkonce.sb.*)
+ *(.sbss2 .sbss2.* .gnu.linkonce.sb2.*)
+ *(.tbss .tbss.* .gnu.linkonce.tb.*)
+ *(.tcommon)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ . = ALIGN(4);
+ _ebss = .;
+ } > ram : bss
+
+ _sp = ORIGIN(ram) + LENGTH(ram);
+}
+
+PHDRS {
+ text PT_LOAD FLAGS(5);
+ data PT_LOAD FLAGS(6);
+ bss PT_LOAD FLAGS(6);
+}
diff --git a/sw/cic/convert.py b/sw/cic/convert.py
new file mode 100644
index 0000000..ae55057
--- /dev/null
+++ b/sw/cic/convert.py
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+
+import sys
+
+
+
+if __name__ == '__main__':
+ if (len(sys.argv) != 3):
+ print(f'Usage: python {sys.argv[0]} in_file out_file')
+ sys.exit(1)
+
+ with open(sys.argv[1], 'rb') as f:
+ output = ''
+ while True:
+ file_bytes = f.read(4)
+ if len(file_bytes) != 4:
+ break
+ output += f"{int.from_bytes(file_bytes, 'little'):08X}\n"
+
+ with open(sys.argv[2], 'w') as f:
+ f.write(output)
diff --git a/sw/cic/startup.S b/sw/cic/startup.S
new file mode 100644
index 0000000..ffc9a79
--- /dev/null
+++ b/sw/cic/startup.S
@@ -0,0 +1,23 @@
+.option norvc
+.section .text.entry_handler
+entry_handler:
+ .global entry_handler
+
+init_stack_pointer:
+ .option push
+ .option norelax
+ la sp, _sp
+ .option pop
+
+init_bss:
+ la t5, _sbss
+ la t6, _ebss
+ beq a0, a1, 2f
+1:
+ sw zero, 0(t5)
+ addi t5, t5, 4
+ bltu t5, t6, 1b
+2:
+
+run_main:
+ tail cic_main
diff --git a/sw/controller/common.mk b/sw/controller/common.mk
index 8dbbcf1..7fee96b 100644
--- a/sw/controller/common.mk
+++ b/sw/controller/common.mk
@@ -6,7 +6,7 @@ OBJDUMP = $(TOOLCHAIN)objdump
SIZE = $(TOOLCHAIN)size
FLAGS = -mcpu=cortex-m0plus -mthumb -DSTM32G030xx $(USER_FLAGS) -g -ggdb3
-CFLAGS = -Os -Wall -ffunction-sections -fdata-sections -ffreestanding -MMD -MP -I./inc
+CFLAGS = -Os -Wall -ffunction-sections -fdata-sections -ffreestanding -MMD -MP -I. -isystem ./inc
LDFLAGS = -nostartfiles -Wl,--gc-sections
SRC_DIR = src
diff --git a/sw/controller/src/app.S b/sw/controller/src/app.S
index 5150fde..01b6ea0 100644
--- a/sw/controller/src/app.S
+++ b/sw/controller/src/app.S
@@ -7,7 +7,7 @@
.section .loader, "a", %progbits
.type loader, %object
loader:
- .incbin "../build/loader/loader.bin"
+ .incbin "build/loader/loader.bin"
.section .text.Reset_Handler
diff --git a/sw/controller/src/app.c b/sw/controller/src/app.c
index 1988a88..16be2f7 100644
--- a/sw/controller/src/app.c
+++ b/sw/controller/src/app.c
@@ -1,5 +1,4 @@
#include "app.h"
-#include "cic.h"
#include "gvr.h"
#include "hw.h"
#include "led.h"
@@ -7,20 +6,18 @@
#include "task.h"
-#define CIC_STACK_SIZE (256)
#define RTC_STACK_SIZE (256)
#define LED_STACK_SIZE (256)
#define GVR_STACK_SIZE (2048)
-uint8_t cic_stack[CIC_STACK_SIZE] __attribute__((aligned(8)));
uint8_t rtc_stack[RTC_STACK_SIZE] __attribute__((aligned(8)));
uint8_t led_stack[LED_STACK_SIZE] __attribute__((aligned(8)));
uint8_t gvr_stack[GVR_STACK_SIZE] __attribute__((aligned(8)));
void app_get_stack_usage (uint32_t *usage) {
- *usage++ = task_get_stack_usage(cic_stack, CIC_STACK_SIZE);
+ *usage++ = 0;
*usage++ = task_get_stack_usage(rtc_stack, RTC_STACK_SIZE);
*usage++ = task_get_stack_usage(led_stack, LED_STACK_SIZE);
*usage++ = task_get_stack_usage(gvr_stack, GVR_STACK_SIZE);
@@ -28,9 +25,7 @@ void app_get_stack_usage (uint32_t *usage) {
void app (void) {
hw_init();
- cic_hw_init();
- task_create(TASK_ID_CIC, cic_task, cic_stack, CIC_STACK_SIZE);
task_create(TASK_ID_RTC, rtc_task, rtc_stack, RTC_STACK_SIZE);
task_create(TASK_ID_LED, led_task, led_stack, LED_STACK_SIZE);
task_create(TASK_ID_GVR, gvr_task, gvr_stack, GVR_STACK_SIZE);
diff --git a/sw/controller/src/cic.c b/sw/controller/src/cic.c
index 5961946..a676232 100644
--- a/sw/controller/src/cic.c
+++ b/sw/controller/src/cic.c
@@ -1,34 +1,8 @@
-// Original code sourced from https://github.com/jago85/UltraCIC_C
-
-// MIT License
-
-// Copyright (c) 2019 Jan Goldacker
-// Copyright (c) 2022 Mateusz Faderewski
-
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-
-// The above copyright notice and this permission notice shall be included in all
-// copies or substantial portions of the Software.
-
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-// SOFTWARE.
-
-
#include "cic.h"
+#include "fpga.h"
#include "hw.h"
#include "led.h"
#include "rtc.h"
-#include "task.h"
typedef enum {
@@ -38,372 +12,78 @@ typedef enum {
} cic_region_t;
-static volatile bool cic_enabled = false;
-static volatile bool cic_detect_enabled;
-
-static volatile uint8_t cic_next_rd;
-static volatile uint8_t cic_next_wr;
-
-static volatile bool cic_disabled = false;
-static volatile bool cic_dd_mode = false;
-static volatile uint8_t cic_seed = 0x3F;
-static volatile uint8_t cic_checksum[6] = { 0xA5, 0x36, 0xC0, 0xF1, 0xD8, 0x59 };
-
-static uint8_t cic_ram[32];
-static uint8_t cic_x105_ram[30];
-
-static const uint8_t cic_ram_init[2][32] = {{
- 0x0E, 0x00, 0x09, 0x0A, 0x01, 0x08, 0x05, 0x0A, 0x01, 0x03, 0x0E, 0x01, 0x00, 0x0D, 0x0E, 0x0C,
- 0x00, 0x0B, 0x01, 0x04, 0x0F, 0x08, 0x0B, 0x05, 0x07, 0x0C, 0x0D, 0x06, 0x01, 0x0E, 0x09, 0x08
-}, {
- 0x0E, 0x00, 0x04, 0x0F, 0x05, 0x01, 0x02, 0x01, 0x07, 0x01, 0x09, 0x08, 0x05, 0x07, 0x05, 0x0A,
- 0x00, 0x0B, 0x01, 0x02, 0x03, 0x0F, 0x08, 0x02, 0x07, 0x01, 0x09, 0x08, 0x01, 0x01, 0x05, 0x0C
-}};
-
-
static void cic_irq_reset_falling (void) {
- cic_enabled = false;
- hw_gpio_set(GPIO_ID_N64_CIC_DQ);
led_clear_error(LED_ERROR_CIC);
}
-static void cic_irq_reset_rising (void) {
- if (!cic_disabled) {
- cic_enabled = true;
- task_set_ready_and_reset(TASK_ID_CIC);
- }
-}
-
-static void cic_irq_clk_falling (void) {
- if (cic_enabled) {
- if (!cic_next_wr) {
- hw_gpio_reset(GPIO_ID_N64_CIC_DQ);
- }
- cic_next_rd = hw_gpio_get(GPIO_ID_N64_CIC_DQ) ? 1 : 0;
- task_set_ready(TASK_ID_CIC);
- }
-}
-
-static void cic_irq_clk_rising (void) {
- hw_gpio_set(GPIO_ID_N64_CIC_DQ);
- if (cic_detect_enabled) {
- cic_detect_enabled = false;
- if (!hw_gpio_get(GPIO_ID_N64_CIC_DQ)) {
- cic_enabled = false;
- }
- }
-}
-
-static uint8_t cic_read (void) {
- cic_next_wr = 1;
- task_yield();
- return cic_next_rd;
-}
-
-static void cic_write (uint8_t bit) {
- cic_next_wr = bit;
- task_yield();
-}
-
-static void cic_start_detect (void) {
- cic_detect_enabled = cic_dd_mode;
-}
-
-static uint8_t cic_read_nibble (void) {
- uint8_t data = 0;
- for (int i = 0; i < 4; i++) {
- data = ((data << 1) | cic_read());
- }
- return data;
-}
-
-static void cic_write_nibble (uint8_t data) {
- cic_write(data & 0x08);
- cic_write(data & 0x04);
- cic_write(data & 0x02);
- cic_write(data & 0x01);
-}
-
-static void cic_write_ram_nibbles (uint8_t index) {
- do {
- cic_write_nibble(cic_ram[index++]);
- } while ((index & 0x0F) != 0);
-}
-
-static void cic_encode_round (uint8_t index) {
- uint8_t data = cic_ram[index++];
- do {
- data = ((((data + 1) & 0x0F) + cic_ram[index]) & 0x0F);
- cic_ram[index++] = data;
- } while ((index & 0x0F) != 0);
-}
-
-static void cic_write_id (cic_region_t region) {
- cic_start_detect();
- cic_write(cic_dd_mode ? 1 : 0);
- cic_write(region == REGION_PAL ? 1 : 0);
- cic_write(0);
- cic_write(1);
-}
-
-static void cic_write_id_failed (void) {
- uint8_t current_region = rtc_get_region();
- uint8_t next_region = (current_region == REGION_NTSC) ? REGION_PAL : REGION_NTSC;
- rtc_set_region(next_region);
- led_blink_error(LED_ERROR_CIC);
-}
-
-static void cic_write_seed (void) {
- cic_ram[0x0A] = 0x0B;
- cic_ram[0x0B] = 0x05;
- cic_ram[0x0C] = (cic_seed >> 4);
- cic_ram[0x0D] = cic_seed;
- cic_ram[0x0E] = (cic_seed >> 4);
- cic_ram[0x0F] = cic_seed;
- cic_encode_round(0x0A);
- cic_encode_round(0x0A);
- cic_write_ram_nibbles(0x0A);
-}
-
-static void cic_write_checksum (void) {
- for (int i = 0; i < 4; i++) {
- cic_ram[i] = 0x00;
- }
- for (int i = 0; i < 6; i++) {
- cic_ram[(i * 2) + 4] = ((cic_checksum[i] >> 4) & 0x0F);
- cic_ram[(i * 2) + 5] = (cic_checksum[i] & 0x0F);
- }
- cic_encode_round(0x00);
- cic_encode_round(0x00);
- cic_encode_round(0x00);
- cic_encode_round(0x00);
- cic_write(0);
- cic_write_ram_nibbles(0x00);
-}
-
-static void cic_init_ram (cic_region_t region) {
- if (region < __REGION_MAX) {
- for (int i = 0; i < 32; i++) {
- cic_ram[i] = cic_ram_init[region][i];
- }
- }
- cic_ram[0x01] = cic_read_nibble();
- cic_ram[0x11] = cic_read_nibble();
-}
-
-static void cic_exchange_bytes (uint8_t *a, uint8_t *b) {
- uint8_t tmp = *a;
- *a = *b;
- *b = tmp;
-}
-
-static void cic_round (uint8_t *m) {
- uint8_t a, b, x;
-
- x = m[15];
- a = x;
-
- do {
- b = 1;
- a += (m[b] + 1);
- m[b] = a;
- b++;
- a += (m[b] + 1);
- cic_exchange_bytes(&a, &m[b]);
- m[b] = ~(m[b]);
- b++;
- a &= 0x0F;
- a += ((m[b] & 0x0F) + 1);
- if (a < 16) {
- cic_exchange_bytes(&a, &m[b]);
- b++;
- }
- a += m[b];
- m[b] = a;
- b++;
- a += m[b];
- cic_exchange_bytes(&a, &m[b]);
- b++;
- a &= 0x0F;
- a += 8;
- if (a < 16) {
- a += m[b];
- }
- cic_exchange_bytes(&a, &m[b]);
- b++;
- do {
- a += (m[b] + 1);
- m[b] = a;
- b++;
- b &= 0x0F;
- } while (b != 0);
- a = (x + 0x0F);
- x = (a & 0x0F);
- } while (x != 0x0F);
-}
-
-static void cic_compare_mode (cic_region_t region) {
- cic_round(&cic_ram[0x10]);
- cic_round(&cic_ram[0x10]);
- cic_round(&cic_ram[0x10]);
-
- uint8_t index = (cic_ram[0x17] & 0x0F);
- if (index == 0) {
- index = 1;
- }
- index |= 0x10;
-
- do {
- cic_read();
- cic_write(cic_ram[index] & 0x01);
- if (region == REGION_PAL) {
- index--;
- } else {
- index++;
- }
- } while (index & 0x0F);
-}
-
-static void cic_x105_algorithm (void) {
- uint8_t a = 5;
- uint8_t carry = 1;
-
- for (int i = 0; i < 30; ++i) {
- if (!(cic_x105_ram[i] & 0x01)) {
- a += 8;
- }
- if (!(a & 0x02)) {
- a += 4;
- }
- a = ((a + cic_x105_ram[i]) & 0x0F);
- cic_x105_ram[i] = a;
- if (!carry) {
- a += 7;
- }
- a = ((a + cic_x105_ram[i]) & 0x0F);
- a = (a + cic_x105_ram[i] + carry);
- if (a >= 0x10) {
- carry = 1;
- a -= 0x10;
- } else {
- carry = 0;
- }
- a = (~(a) & 0x0F);
- cic_x105_ram[i] = a;
- }
-}
-
-static void cic_x105_mode (void) {
- cic_write_nibble(0x0A);
- cic_write_nibble(0x0A);
-
- for (int i = 0; i < 30; i++) {
- cic_x105_ram[i] = cic_read_nibble();
- }
-
- cic_x105_algorithm();
-
- cic_write(0);
-
- for (int i = 0; i < 30; i++) {
- cic_write_nibble(cic_x105_ram[i]);
- }
-}
-
-static void cic_soft_reset_timeout (void) {
- hw_gpio_reset(GPIO_ID_N64_CIC_DQ);
- task_set_ready(TASK_ID_CIC);
-}
-
-static void cic_soft_reset (void) {
- cic_read();
- hw_tim_setup(TIM_ID_CIC, 500, cic_soft_reset_timeout);
- task_yield();
-}
-
void cic_reset_parameters (void) {
- cic_disabled = false;
- cic_dd_mode = false;
- cic_seed = 0x3F;
- cic_checksum[0] = 0xA5;
- cic_checksum[1] = 0x36;
- cic_checksum[2] = 0xC0;
- cic_checksum[3] = 0xF1;
- cic_checksum[4] = 0xD8;
- cic_checksum[5] = 0x59;
+ cic_region_t region = rtc_get_region();
+
+ const uint8_t default_seed = 0x3F;
+ const uint64_t default_checksum = 0xA536C0F1D859ULL;
+
+ uint32_t cic_config_0 = (default_seed << CIC_SEED_BIT) | ((default_checksum >> 32) & 0xFFFF);
+ uint32_t cic_config_1 = (default_checksum & 0xFFFFFFFFUL);
+
+ if (region == REGION_PAL) {
+ cic_config_0 |= CIC_REGION;
+ }
+
+ fpga_reg_set(REG_CIC_0, cic_config_0);
+ fpga_reg_set(REG_CIC_1, cic_config_1);
}
void cic_set_parameters (uint32_t *args) {
- cic_disabled = (args[0] >> 24) & (1 << 0);
- cic_seed = (args[0] >> 16) & 0xFF;
- cic_checksum[0] = (args[0] >> 8) & 0xFF;
- cic_checksum[1] = args[0] & 0xFF;
- cic_checksum[2] = (args[1] >> 24) & 0xFF;
- cic_checksum[3] = (args[1] >> 16) & 0xFF;
- cic_checksum[4] = (args[1] >> 8) & 0xFF;
- cic_checksum[5] = args[1] & 0xFF;
+ cic_region_t region = rtc_get_region();
+
+ uint32_t cic_config_0 = args[0] & (0x00FFFFFF);
+ uint32_t cic_config_1 = args[1];
+
+ if (region == REGION_PAL) {
+ cic_config_0 |= CIC_REGION;
+ }
+ if (args[0] & (1 << 24)) {
+ cic_config_0 |= CIC_DISABLED;
+ }
+
+ fpga_reg_set(REG_CIC_0, cic_config_0);
+ fpga_reg_set(REG_CIC_1, cic_config_1);
}
void cic_set_dd_mode (bool enabled) {
- cic_dd_mode = enabled;
+ uint32_t cic_config_0 = fpga_reg_get(REG_CIC_0);
+
+ if (enabled) {
+ cic_config_0 |= CIC_64DD_MODE;
+ } else {
+ cic_config_0 &= ~(CIC_64DD_MODE);
+ }
+
+ fpga_reg_set(REG_CIC_0, cic_config_0);
}
-void cic_hw_init (void) {
+
+void cic_init (void) {
+ while (!rtc_is_initialized());
+ cic_reset_parameters();
hw_gpio_irq_setup(GPIO_ID_N64_RESET, GPIO_IRQ_FALLING, cic_irq_reset_falling);
- hw_gpio_irq_setup(GPIO_ID_N64_RESET, GPIO_IRQ_RISING, cic_irq_reset_rising);
- hw_gpio_irq_setup(GPIO_ID_N64_CIC_CLK, GPIO_IRQ_FALLING, cic_irq_clk_falling);
- hw_gpio_irq_setup(GPIO_ID_N64_CIC_CLK, GPIO_IRQ_RISING, cic_irq_clk_rising);
}
-void cic_task (void) {
- while (!hw_gpio_get(GPIO_ID_N64_RESET)) {
- task_yield();
- }
- cic_region_t region = rtc_get_region();
- if (region >= __REGION_MAX) {
- region = REGION_NTSC;
- rtc_set_region(region);
- }
+void cic_process (void) {
+ uint32_t cic_config_0 = fpga_reg_get(REG_CIC_0);
- cic_write_id(region);
+ if (cic_config_0 & CIC_INVALID_REGION_DETECTED) {
+ cic_config_0 ^= CIC_REGION;
+ fpga_reg_set(REG_CIC_0, (cic_config_0 | CIC_INVALID_REGION_RESET));
- hw_tim_setup(TIM_ID_CIC, 500, cic_write_id_failed);
- cic_write_seed();
- hw_tim_stop(TIM_ID_CIC);
-
- cic_write_checksum();
- cic_init_ram(region);
-
- while (1) {
- uint8_t cmd = 0;
- cmd |= (cic_read() << 1);
- cmd |= cic_read();
-
- switch (cmd) {
- case 0: {
- cic_compare_mode(region);
- break;
- }
-
- case 2: {
- cic_x105_mode();
- break;
- }
-
- case 3: {
- cic_soft_reset();
- break;
- }
-
- case 1:
- default: {
- while (1) {
- task_yield();
- }
- break;
- }
+ if (cic_config_0 & CIC_REGION) {
+ rtc_set_region(REGION_PAL);
+ } else {
+ rtc_set_region(REGION_NTSC);
}
+
+ led_blink_error(LED_ERROR_CIC);
}
}
diff --git a/sw/controller/src/cic.h b/sw/controller/src/cic.h
index 98fe6ae..56f006e 100644
--- a/sw/controller/src/cic.h
+++ b/sw/controller/src/cic.h
@@ -9,8 +9,8 @@
void cic_reset_parameters (void);
void cic_set_parameters (uint32_t *args);
void cic_set_dd_mode (bool enabled);
-void cic_hw_init (void);
-void cic_task (void);
+void cic_init (void);
+void cic_process (void);
#endif
diff --git a/sw/controller/src/fpga.h b/sw/controller/src/fpga.h
index f14fe76..5fafded 100644
--- a/sw/controller/src/fpga.h
+++ b/sw/controller/src/fpga.h
@@ -55,6 +55,8 @@ typedef enum {
REG_VENDOR_DATA,
REG_DEBUG_0,
REG_DEBUG_1,
+ REG_CIC_0,
+ REG_CIC_1,
} fpga_reg_t;
@@ -186,6 +188,13 @@ typedef enum {
#define DD_HEAD_TRACK_MASK (DD_HEAD_MASK | DD_TRACK_MASK)
#define DD_HEAD_TRACK_INDEX_LOCK (1 << 13)
+#define CIC_SEED_BIT (16)
+#define CIC_REGION (1 << 24)
+#define CIC_64DD_MODE (1 << 25)
+#define CIC_DISABLED (1 << 26)
+#define CIC_INVALID_REGION_DETECTED (1 << 27)
+#define CIC_INVALID_REGION_RESET (1 << 28)
+
uint8_t fpga_id_get (void);
uint32_t fpga_reg_get (fpga_reg_t reg);
diff --git a/sw/controller/src/gvr.c b/sw/controller/src/gvr.c
index 0dc6cf7..70c7909 100644
--- a/sw/controller/src/gvr.c
+++ b/sw/controller/src/gvr.c
@@ -1,5 +1,6 @@
#include "button.h"
#include "cfg.h"
+#include "cic.h"
#include "dd.h"
#include "flashram.h"
#include "fpga.h"
@@ -15,6 +16,7 @@ void gvr_task (void) {
button_init();
cfg_init();
+ cic_init();
dd_init();
flashram_init();
isv_init();
@@ -25,6 +27,7 @@ void gvr_task (void) {
while (1) {
button_process();
cfg_process();
+ cic_process();
dd_process();
flashram_process();
isv_process();
diff --git a/sw/controller/src/hw.c b/sw/controller/src/hw.c
index 25bdf37..0c50787 100644
--- a/sw/controller/src/hw.c
+++ b/sw/controller/src/hw.c
@@ -83,6 +83,7 @@ static void hw_gpio_init (gpio_id_t id, gpio_mode_t mode, gpio_ot_t ot, gpio_osp
void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void)) {
uint8_t port = ((id >> 4) & 0x07);
uint8_t pin = (id & 0x0F);
+ __disable_irq();
if (irq == GPIO_IRQ_FALLING) {
EXTI->FTSR1 |= (EXTI_FTSR1_FT0 << pin);
gpio_irq_callbacks[pin].falling = callback;
@@ -92,6 +93,7 @@ void hw_gpio_irq_setup (gpio_id_t id, gpio_irq_t irq, void (*callback)(void)) {
}
EXTI->EXTICR[pin / 4] |= (port << (8 * (pin % 4)));
EXTI->IMR1 |= (EXTI_IMR1_IM0 << pin);
+ __enable_irq();
}
uint32_t hw_gpio_get (gpio_id_t id) {
@@ -509,7 +511,7 @@ static void hw_init_crc (void) {
static void hw_init_misc (void) {
hw_gpio_init(GPIO_ID_N64_RESET, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_DOWN, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_N64_CIC_CLK, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
- hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_OUTPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1);
+ hw_gpio_init(GPIO_ID_N64_CIC_DQ, GPIO_INPUT, GPIO_OD, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 1);
hw_gpio_init(GPIO_ID_FPGA_INT, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
hw_gpio_init(GPIO_ID_RTC_MFP, GPIO_INPUT, GPIO_PP, GPIO_SPEED_VLOW, GPIO_PULL_UP, GPIO_AF_0, 0);
}
@@ -528,14 +530,14 @@ void hw_init (void) {
hw_init_misc();
NVIC_SetPriority(EXTI0_1_IRQn, 0);
- NVIC_SetPriority(EXTI2_3_IRQn, 1);
- NVIC_SetPriority(EXTI4_15_IRQn, 2);
- NVIC_SetPriority(I2C1_IRQn, 1);
+ NVIC_SetPriority(EXTI2_3_IRQn, 0);
+ NVIC_SetPriority(EXTI4_15_IRQn, 0);
+ NVIC_SetPriority(I2C1_IRQn, 0);
NVIC_SetPriority(TIM14_IRQn, 0);
- NVIC_SetPriority(TIM16_IRQn, 1);
- NVIC_SetPriority(TIM17_IRQn, 2);
- NVIC_SetPriority(TIM3_IRQn, 2);
- NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 1);
+ NVIC_SetPriority(TIM16_IRQn, 0);
+ NVIC_SetPriority(TIM17_IRQn, 0);
+ NVIC_SetPriority(TIM3_IRQn, 0);
+ NVIC_SetPriority(TIM1_BRK_UP_TRG_COM_IRQn, 0);
NVIC_EnableIRQ(EXTI0_1_IRQn);
NVIC_EnableIRQ(EXTI2_3_IRQn);
diff --git a/sw/controller/src/rtc.c b/sw/controller/src/rtc.c
index 5ffd443..99e251b 100644
--- a/sw/controller/src/rtc.c
+++ b/sw/controller/src/rtc.c
@@ -48,6 +48,7 @@ static rtc_settings_t rtc_settings = {
.led_enabled = true,
};
static volatile bool rtc_settings_pending = false;
+static volatile bool rtc_initialized = false;
static const uint8_t rtc_regs_bit_mask[7] = {
0b01111111,
@@ -199,9 +200,15 @@ static void rtc_init (void) {
rtc_write(RTC_ADDRESS_SRAM_VERSION, (uint8_t *) (&settings_version), 4);
rtc_write_settings();
}
+
+ rtc_initialized = true;
}
+bool rtc_is_initialized (void) {
+ return rtc_initialized;
+}
+
bool rtc_get_time (rtc_time_t *time) {
bool vaild;
diff --git a/sw/controller/src/rtc.h b/sw/controller/src/rtc.h
index 06c70cf..be7dc8a 100644
--- a/sw/controller/src/rtc.h
+++ b/sw/controller/src/rtc.h
@@ -21,6 +21,7 @@ typedef struct {
} rtc_settings_t;
+bool rtc_is_initialized (void);
bool rtc_get_time (rtc_time_t *time);
void rtc_set_time (rtc_time_t *time);
uint8_t rtc_get_region (void);
diff --git a/sw/controller/src/task.c b/sw/controller/src/task.c
index b2ddac5..8240aa4 100644
--- a/sw/controller/src/task.c
+++ b/sw/controller/src/task.c
@@ -1,3 +1,4 @@
+#include
#include
#include
#include "task.h"
@@ -8,18 +9,9 @@
#define TASK_STACK_FILL_VALUE (0xDEADBEEF)
-typedef enum {
- TASK_FLAG_NONE = 0,
- TASK_FLAG_READY = (1 << 0),
- TASK_FLAG_RESET = (1 << 1),
-} task_flags_t;
-
-
typedef struct {
- uint32_t initial_pc;
- uint32_t initial_sp;
- uint32_t sp;
- task_flags_t flags;
+ volatile uint32_t sp;
+ volatile bool ready;
} task_t;
@@ -28,42 +20,21 @@ static volatile task_id_t task_current = 0;
static void task_exit (void) {
- task_table[task_current].flags = TASK_FLAG_NONE;
- task_yield();
- while (1);
-}
-
-static void task_initialize (task_id_t id) {
- task_t *task = &task_table[id];
- uint32_t *sp = ((uint32_t *) (task->initial_sp));
- *--sp = TASK_INITIAL_XPSR;
- *--sp = task->initial_pc;
- *--sp = ((uint32_t) (task_exit));
- for (int i = 0; i < 13; i++) {
- *--sp = 0;
+ while (1) {
+ task_yield();
}
- task->sp = ((uint32_t) (sp));
-}
-
-static void task_reset (task_id_t id) {
- task_table[id].flags &= ~(TASK_FLAG_RESET);
- task_initialize(id);
}
static uint32_t task_switch_context (uint32_t sp) {
task_table[task_current].sp = sp;
for (task_id_t id = 0; id < __TASK_ID_MAX; id++) {
- if (task_table[id].flags & TASK_FLAG_READY) {
+ if (task_table[id].ready) {
task_current = id;
break;
}
}
- if (task_table[task_current].flags & TASK_FLAG_RESET) {
- task_reset(task_current);
- }
-
return task_table[task_current].sp;
}
@@ -73,26 +44,30 @@ void task_create (task_id_t id, void (*code)(void), void *stack, size_t stack_si
for (size_t i = 0; i < stack_size; i += sizeof(uint32_t)) {
(*(uint32_t *) (stack + i)) = TASK_STACK_FILL_VALUE;
}
+ uint32_t *sp = ((uint32_t *) ((uint32_t) (stack) + stack_size));
+ *--sp = TASK_INITIAL_XPSR;
+ *--sp = (uint32_t) (code);
+ *--sp = ((uint32_t) (task_exit));
+ for (int i = 0; i < 13; i++) {
+ *--sp = 0;
+ }
task_t *task = &task_table[id];
- task->initial_pc = (uint32_t) (code);
- task->initial_sp = (((uint32_t) (stack)) + stack_size);
- task->flags = TASK_FLAG_READY;
- task_initialize(id);
+ task->sp = ((uint32_t) (sp));
+ task->ready = true;
}
}
void task_yield (void) {
- task_table[task_current].flags &= ~(TASK_FLAG_READY);
+ __disable_irq();
+ task_table[task_current].ready = false;
+ __enable_irq();
TASK_CONTEXT_SWITCH();
}
void task_set_ready (task_id_t id) {
- task_table[id].flags |= TASK_FLAG_READY;
- TASK_CONTEXT_SWITCH();
-}
-
-void task_set_ready_and_reset (task_id_t id) {
- task_table[id].flags |= (TASK_FLAG_RESET | TASK_FLAG_READY);
+ __disable_irq();
+ task_table[id].ready = true;
+ __enable_irq();
TASK_CONTEXT_SWITCH();
}
diff --git a/sw/controller/src/task.h b/sw/controller/src/task.h
index 684f5d7..71ad4e3 100644
--- a/sw/controller/src/task.h
+++ b/sw/controller/src/task.h
@@ -6,7 +6,6 @@
typedef enum {
- TASK_ID_CIC,
TASK_ID_RTC,
TASK_ID_LED,
TASK_ID_GVR,
@@ -17,7 +16,6 @@ typedef enum {
void task_create (task_id_t id, void (*code)(void), void *stack, size_t stack_size);
void task_yield (void);
void task_set_ready (task_id_t id);
-void task_set_ready_and_reset (task_id_t id);
size_t task_get_stack_usage (void *stack, size_t stack_size);
void task_scheduler_start (void);
diff --git a/sw/deployer/src/sc64/types.rs b/sw/deployer/src/sc64/types.rs
index 0164d61..505db68 100644
--- a/sw/deployer/src/sc64/types.rs
+++ b/sw/deployer/src/sc64/types.rs
@@ -852,9 +852,12 @@ impl TryFrom> for McuStackUsage {
impl Display for McuStackUsage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if self.cic > 0 {
+ f.write_fmt(format_args!("CIC: {}, ", self.cic))?;
+ }
f.write_fmt(format_args!(
- "CIC: {}, RTC: {}, LED: {}, GVR: {}",
- self.cic, self.rtc, self.led, self.gvr
+ "RTC: {}, LED: {}, GVR: {}",
+ self.rtc, self.led, self.gvr
))
}
}