From 3dcef8bce884a3fa0aaf8c2a7b10ef0b6b496a9d Mon Sep 17 00:00:00 2001 From: Douglas Santos Date: Thu, 17 Jun 2021 17:23:41 +0200 Subject: [PATCH] HARV project --- .gitignore | 12 + README.md | 44 ++- hdl/alu.vhd | 59 ++++ hdl/control.vhd | 282 ++++++++++++++++++ hdl/csr.vhd | 357 ++++++++++++++++++++++ hdl/ft_components/alu_tmr.vhd | 80 +++++ hdl/ft_components/control_tmr.vhd | 299 +++++++++++++++++++ hdl/ft_components/hamming_decoder.vhd | 80 +++++ hdl/ft_components/hamming_encoder.vhd | 45 +++ hdl/ft_components/hamming_pkg.vhd | 129 ++++++++ hdl/ft_components/hamming_register.vhd | 101 +++++++ hdl/harv.vhd | 396 +++++++++++++++++++++++++ hdl/harv_pkg.vhd | 265 +++++++++++++++++ hdl/instr_fetch.vhd | 91 ++++++ hdl/regfile.vhd | 142 +++++++++ images/rars-data-export.png | Bin 0 -> 9362 bytes images/rars-memory-configuration.png | Bin 0 -> 27228 bytes images/rars-text-export.png | Bin 0 -> 8894 bytes script/project.tcl | 311 +++++++++++++++++++ sim/sim_from_dump.vhd | 240 +++++++++++++++ src/test.asm | 20 ++ xilinx/sim_from_dump_behav.wcfg | 210 +++++++++++++ 22 files changed, 3161 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 hdl/alu.vhd create mode 100644 hdl/control.vhd create mode 100644 hdl/csr.vhd create mode 100644 hdl/ft_components/alu_tmr.vhd create mode 100644 hdl/ft_components/control_tmr.vhd create mode 100644 hdl/ft_components/hamming_decoder.vhd create mode 100644 hdl/ft_components/hamming_encoder.vhd create mode 100644 hdl/ft_components/hamming_pkg.vhd create mode 100644 hdl/ft_components/hamming_register.vhd create mode 100644 hdl/harv.vhd create mode 100644 hdl/harv_pkg.vhd create mode 100644 hdl/instr_fetch.vhd create mode 100644 hdl/regfile.vhd create mode 100644 images/rars-data-export.png create mode 100644 images/rars-memory-configuration.png create mode 100644 images/rars-text-export.png create mode 100644 script/project.tcl create mode 100644 sim/sim_from_dump.vhd create mode 100644 src/test.asm create mode 100644 xilinx/sim_from_dump_behav.wcfg diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b677369 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +*/** +!*/ +!/hdl/**/*.vhd +!/sim/**/*.vhd +!/src/**/*.asm +!/script/*.sh +!/script/*.py +!/script/*.do +!/script/*.tcl +!/script/*.ld +!/xilinx/*.wcfg +!/images/*.png diff --git a/README.md b/README.md index f4ff9ca..578f0d6 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,42 @@ -# harv -HARV - HArdened Risc-V +# HARV - HArdened Risc-V + +The focus of the HARV processor core is harsh environments. It implements the integer instruction-set of the RISC-V specification (RV32I), except system calls. To provide reliability for harsh environments, we implement the fault tolerance techniques TMR (Triple-Modular Redundancy) and Hamming code to the different parts of the processor. These techniques improve the reliability by mitigating or correcting errors caused by the single-event effects SEU (Single-Event Upset) and SET (Single-Event Transient). + +HARV is being developed in partnership between the **LEDS - Laboratory of Embedded and Distributed Systems** and the **LIRMM - Laboratoire d’Informatique, de Robotique et de Microélectronique de Montpellier**. + +The HARV was introduced by the following paper published at the IEEE DTIS 2021: + +D. A. Santos, L. M. Luza, C. A. Zeferino, L. Dilillo and D. R. Melo, "A Low-Cost Fault-Tolerant RISC-V Processor for Space Systems," *2020 15th Design & Technology of Integrated Systems in Nanoscale Era (DTIS), 2020*, pp. 1-5, doi: [10.1109/DTIS48698.2020.9081185](https://doi.org/10.1109/DTIS48698.2020.9081185). + +The current mantainer of this repository is [Douglas Almeida dos Santos](https://github.com/Douglasas). + +## Getting started + +This getting started is a tutorial for the simulation of the simple assembly program `src/test.asm` + +Requirements: +- Vivado 2020.2 +- RARS 1.5 + +Open the RARS and open the assembly file from the sources folder. + +You will need to configure the memory to work with the testbench parameters. The following image shows the required memory configuration. + +![RARS memory configuration](images/rars-memory-configuration.png) + +After that, you may export the assembly code so it can be used by the testbench. +Dump both the `.text` and `.data` sections to the `src` folder. The following images shows the configurations that must be used for the memory dump. +The file paths must be `src/test_text.dump` and `src/test_data.dump` for the sections, respectively. + +![RARS .text export](images/rars-text-export.png) +![RARS .data export](images/rars-data-export.png) + +The next step is to create and open the Vivado project. + +Execute the following command at the terminal and at the root project directory. Note that Vivado must be in the path. + +``` +vivado -mode tcl -source script/project.tcl +``` + +After that, you may open the Vivado project through the interface and run the simulation set 1. diff --git a/hdl/alu.vhd b/hdl/alu.vhd new file mode 100644 index 0000000..b92b99a --- /dev/null +++ b/hdl/alu.vhd @@ -0,0 +1,59 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.harv_pkg.all; + +entity alu is + port ( + -- input ports + data1_i : in std_logic_vector(31 downto 0); + data2_i : in std_logic_vector(31 downto 0); + operation_i : in std_logic_vector(ALUOP_SIZE-1 downto 0); + -- output ports + zero_o : out std_logic; + data_o : out std_logic_vector(31 downto 0) + ); +end entity; + +architecture arch of alu is + signal add_sub_data2_w : signed(31 downto 0); + signal add_sub_w : std_logic_vector(31 downto 0); + signal and_w : std_logic_vector(31 downto 0); + signal or_w : std_logic_vector(31 downto 0); + signal xor_w : std_logic_vector(31 downto 0); + signal sll_w : std_logic_vector(31 downto 0); + signal srl_w : std_logic_vector(31 downto 0); + signal sra_w : std_logic_vector(31 downto 0); + signal slt_w : std_logic_vector(31 downto 0); + signal sltu_w : std_logic_vector(31 downto 0); + signal result_w : std_logic_vector(31 downto 0); +begin + add_sub_data2_w <= signed(data2_i) when operation_i = ALU_ADD_OP else -signed(data2_i); + add_sub_w <= std_logic_vector(signed(data1_i) + add_sub_data2_w); + and_w <= data1_i and data2_i; + or_w <= data1_i or data2_i; + xor_w <= data1_i xor data2_i; + sll_w <= std_logic_vector(shift_left(unsigned(data1_i), to_integer(unsigned(data2_i)))); + srl_w <= std_logic_vector(shift_right(unsigned(data1_i), to_integer(unsigned(data2_i)))); + sra_w <= std_logic_vector(shift_right(signed(data1_i), to_integer(unsigned(data2_i)))); + slt_w <= (0 => '1', others => '0') when signed(data1_i) < signed(data2_i) else (others => '0'); + sltu_w <= (0 => '1', others => '0') when unsigned(data1_i) < unsigned(data2_i) else (others => '0'); + + with operation_i select result_w <= + add_sub_w when ALU_ADD_OP, + add_sub_w when ALU_SUB_OP, + sll_w when ALU_SLL_OP, + slt_w when ALU_SLT_OP, + sltu_w when ALU_SLTU_OP, + xor_w when ALU_XOR_OP, + srl_w when ALU_SRL_OP, + sra_w when ALU_SRA_OP, + or_w when ALU_OR_OP, + and_w when ALU_AND_OP, + (others => '0') when others; + + data_o <= result_w; + zero_o <= '1' when result_w = (31 downto 0 => '0') else '0'; +end architecture; diff --git a/hdl/control.vhd b/hdl/control.vhd new file mode 100644 index 0000000..6a32d33 --- /dev/null +++ b/hdl/control.vhd @@ -0,0 +1,282 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.harv_pkg.all; + +entity control is + port ( + -- input ports + -- processor status + imem_gnt_i : in std_logic; + imem_err_i : in std_logic; + dmem_gnt_i : in std_logic; + dmem_outofrange_i : in std_logic; + dmem_sbu_i : in std_logic; + dmem_dbu_i : in std_logic; + + -- instruction decode + opcode_i : in std_logic_vector(6 downto 0); + funct3_i : in std_logic_vector(2 downto 0); + funct7_i : in std_logic_vector(6 downto 0); + funct12_i : in std_logic_vector(11 downto 0); + + -- sync + rstn_i : in std_logic; + clk_i : in std_logic; + start_i : in std_logic; + + -- output ports + -- processor status + imem_req_o : out std_logic; + dmem_req_o : out std_logic; + + update_pc_o : out std_logic; + trap_o : out std_logic; + + -- ALU operations + aluop_o : out std_logic_vector(ALUOP_SIZE-1 downto 0); + alusrc_imm_o : out std_logic; + -- immediate selector + imm_shamt_o : out std_logic; + imm_up_o : out std_logic; + -- register bank + regwr_o : out std_logic; + -- control transfer + inv_branch_o : out std_logic; + branch_o : out std_logic; + jump_o : out std_logic; + jalr_o : out std_logic; + ecall_o : out std_logic; + -- mem access + memrd_o : out std_logic; + memwr_o : out std_logic; + byte_en_o : out std_logic_vector(1 downto 0); + mem_usgn_o : out std_logic; -- unsigned data + -- U type + load_upimm_o : out std_logic; + auipc_o : out std_logic; + -- csr control + csr_enable_o : out std_logic; + csr_source_imm_o : out std_logic; + csr_maskop_o : out std_logic; + csr_clearop_o : out std_logic + ); +end entity; + +architecture arch of control is + --------- PROCESSOR STATUS ----------- + subtype proc_status_t is std_logic_vector(2 downto 0); + constant STAT_IDLE : proc_status_t := "000"; + constant STAT_REQ_INSTR : proc_status_t := "001"; + constant STAT_RUN : proc_status_t := "010"; + constant STAT_DMEM_STALL : proc_status_t := "011"; + constant STAT_UPDATE_PC : proc_status_t := "100"; + constant STAT_TRAP : proc_status_t := "101"; + + signal proc_status_r : proc_status_t; + signal next_proc_status_w : proc_status_t; + + -------- INSTRUCTION DECODE ---------- + subtype instr_format_t is std_logic_vector(3 downto 0); + constant R : instr_format_t := x"1"; + constant I_jalr : instr_format_t := x"2"; + constant I_load : instr_format_t := x"3"; + constant I_arith : instr_format_t := x"4"; + constant I_fence : instr_format_t := x"5"; + constant I_system : instr_format_t := x"6"; + constant S : instr_format_t := x"7"; + constant B : instr_format_t := x"8"; + constant U_lui : instr_format_t := x"9"; + constant U_auipc : instr_format_t := x"A"; + constant U_jal : instr_format_t := x"B"; + + --- CSR TYPES --- + constant SYS_ECALL : std_logic_vector(2 downto 0) := "000"; + constant SYS_CSRRW : std_logic_vector(2 downto 0) := "001"; -- Atomic Read/Write CSR + constant SYS_CSRRS : std_logic_vector(2 downto 0) := "010"; -- Atomic Read and Set Bits in CSR + constant SYS_CSRRC : std_logic_vector(2 downto 0) := "011"; -- Atomic Read and Clear Bits in CSR + constant SYS_CSRRWI : std_logic_vector(2 downto 0) := "101"; + constant SYS_CSRRSI : std_logic_vector(2 downto 0) := "110"; + constant SYS_CSRRCI : std_logic_vector(2 downto 0) := "111"; + + -- auxiliar signals + signal memwr_w : std_logic; + signal memrd_w : std_logic; + signal memreq_w : std_logic; + + -- opcodes + + signal instr_format_w : instr_format_t; + + -- signal rshift_op_w : std_logic_vector(ALUOP_SIZE-1 downto 0); + -- signal add_op_w : std_logic_vector(ALUOP_SIZE-1 downto 0); + signal arith_aluop_w : std_logic_vector(ALUOP_SIZE-1 downto 0); + signal branch_op_w : std_logic_vector(ALUOP_SIZE-1 downto 0); + +begin + ------------------------- PROCESSOR STATUS ------------------------------ + -- STAT_REQ_INSTR + imem_req_o <= '1' when proc_status_r = STAT_REQ_INSTR else '0'; + + -- STAT_DMEM_STALL + memreq_w <= memrd_w or memwr_w; + dmem_req_o <= '1' when proc_status_r = STAT_DMEM_STALL else '0'; + + -- STAT_UPDATE_PC + update_pc_o <= '1' when proc_status_r = STAT_UPDATE_PC else + '1' when proc_status_r = STAT_TRAP else + '0'; + trap_o <= '1' when proc_status_r = STAT_TRAP else '0'; + + + PROC_CURRENT_STATUS : process(clk_i, rstn_i) + begin + if rstn_i = '0' then + proc_status_r <= STAT_IDLE; + elsif rising_edge(clk_i) then + proc_status_r <= next_proc_status_w; + end if; + end process; + + PROC_NEXT_STATUS : process(proc_status_r, start_i, imem_gnt_i, imem_err_i, dmem_outofrange_i, memreq_w, dmem_gnt_i) + begin + case proc_status_r is + + when STAT_IDLE => + if start_i = '1' then + next_proc_status_w <= STAT_REQ_INSTR; + else + next_proc_status_w <= STAT_IDLE; + end if; + + when STAT_REQ_INSTR => + if imem_err_i = '1' then + next_proc_status_w <= STAT_IDLE; + + elsif imem_gnt_i = '1' then + next_proc_status_w <= STAT_RUN; + + else + next_proc_status_w <= STAT_REQ_INSTR; + end if; + + when STAT_RUN => + if memreq_w = '1' then + next_proc_status_w <= STAT_DMEM_STALL; + else + next_proc_status_w <= STAT_UPDATE_PC; + end if; + + when STAT_DMEM_STALL => + if dmem_outofrange_i = '1' then -- or dmem_sbu_i = '1' or dmem_dbu_i = '1' then + next_proc_status_w <= STAT_TRAP; + elsif dmem_gnt_i = '1' then + next_proc_status_w <= STAT_UPDATE_PC; + else + next_proc_status_w <= STAT_DMEM_STALL; + end if; + + when STAT_UPDATE_PC => + next_proc_status_w <= STAT_REQ_INSTR; + + when STAT_TRAP => + next_proc_status_w <= STAT_REQ_INSTR; + + when others => + next_proc_status_w <= STAT_TRAP; + + end case; + end process; + + ------------------------ INSTRUCTIONS DECODE ---------------------------- + with opcode_i select instr_format_w <= + R when "0110011", + I_jalr when "1100111", + I_load when "0000011", + I_arith when "0010011", + I_fence when "0001111", + I_system when "1110011", + S when "0100011", + B when "1100011", + U_lui when "0110111", + U_auipc when "0010111", + U_jal when "1101111", + (others => '0') when others; + --------------------------------- ALU ----------------------------------- + -- rshift_op_w <= ALU_SRL_OP when funct7_i = "0000000" else ALU_SRA_OP; + -- add_op_w <= ALU_SUB_OP when funct7_i = "0100000" and instr_format_w = R else ALU_ADD_OP; + -- + -- with funct3_i select arith_aluop_w <= + -- add_op_w when "000", + -- ALU_SLL_OP when "001", + -- ALU_SLT_OP when "010", + -- ALU_SLTU_OP when "011", + -- ALU_XOR_OP when "100", + -- rshift_op_w when "101", + -- ALU_OR_OP when "110", + -- ALU_AND_OP when "111", + -- (others => '0') when others; + arith_aluop_w <= funct7_i(5) & funct3_i; + + with funct3_i(2 downto 1) select branch_op_w <= + ALU_XOR_OP when "00", -- beq or bne + ALU_SLT_OP when "10", -- blt or bge + ALU_SLTU_OP when "11", -- bltu or bgeu + (others => '0') when others; + + aluop_o <= arith_aluop_w when instr_format_w = I_arith or + instr_format_w = R else + branch_op_w when instr_format_w = B else + ALU_ADD_OP; -- when instr_format_w = U_auipc, I_load, S + alusrc_imm_o <= '1' when instr_format_w /= R and instr_format_w /= B else '0'; + + ------------------------ IMMEDIATE SELECTOR ------------------------------ + -- instr[24:20] + imm_shamt_o <= '1' when (arith_aluop_w = ALU_SLL_OP or + arith_aluop_w = ALU_SRL_OP or + arith_aluop_w = ALU_SRA_OP) and + instr_format_w = I_arith else '0'; + -- instr[31:12] -> imm[31:12] + imm_up_o <= '1' when instr_format_w = U_lui or + instr_format_w = U_auipc else '0'; + + ----------------------------- REGISTER BANK ------------------------------- + regwr_o <= '1' when proc_status_r = STAT_UPDATE_PC and not ( + instr_format_w = I_fence or + (instr_format_w = I_system and funct3_i = SYS_ECALL) or + instr_format_w = S or instr_format_w = I_load or + instr_format_w = B) else + '1' when proc_status_r = STAT_DMEM_STALL and + instr_format_w = I_load and + dmem_gnt_i = '1' else + '0'; + + ------------------------------- BRANCHES ---------------------------------- + inv_branch_o <= funct3_i(2) xor funct3_i(0); + branch_o <= '1' when instr_format_w = B else '0'; + jump_o <= '1' when instr_format_w = U_jal or instr_format_w = I_jalr else '0'; + jalr_o <= '1' when instr_format_w = I_jalr else '0'; + + ecall_o <= '0'; -- '1' when instr_format_w = I_system else + + ------------------------------ MEM ACCESS --------------------------------- + memrd_w <= '1' when instr_format_w = I_load else '0'; + memrd_o <= memrd_w; + memwr_w <= '1' when instr_format_w = S else '0'; + memwr_o <= memwr_w; + byte_en_o <= funct3_i(1 downto 0) when funct3_i(1) = '0' else "11"; -- byte or halfword -- else word + mem_usgn_o <= funct3_i(2); + + -------------------------------- U type ----------------------------------- + load_upimm_o <= '1' when instr_format_w = U_lui else '0'; + auipc_o <= '1' when instr_format_w = U_auipc else '0'; + + -------------------------- CSR instructions ------------------------------ + csr_enable_o <= '1' when instr_format_w = I_system and funct3_i /= SYS_ECALL else '0'; + csr_source_imm_o <= funct3_i(2); -- select source to write the CSR (immediate or register) + csr_maskop_o <= funct3_i(1); -- write operation based on mask + csr_clearop_o <= funct3_i(0); -- operation is CLEAR, if not, operation is SET + +end architecture; diff --git a/hdl/csr.vhd b/hdl/csr.vhd new file mode 100644 index 0000000..be5e8d8 --- /dev/null +++ b/hdl/csr.vhd @@ -0,0 +1,357 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.math_real.ceil; +use ieee.math_real.log2; +use ieee.numeric_std.all; + +entity csr is + generic ( + TMR_CONTROL : boolean; + TMR_ALU : boolean; + HAMMING_REGFILE : boolean; + HAMMING_PC : boolean + ); + port ( + -- sync + rstn_i : in std_logic; + clk_i : in std_logic; + -- access interface + addr_i : in std_logic_vector(11 downto 0); + data_o : out std_logic_vector(31 downto 0); + rs1_data_i : in std_logic_vector(31 downto 0); + imm_data_i : in std_logic_vector(4 downto 0); + -- write control + wren_i : in std_logic; + source_imm_i : in std_logic; + csr_maskop_i : in std_logic; + csr_clearop_i : in std_logic; + -- trap handling + trap_i : in std_logic; + uscratch_i : in std_logic_vector(31 downto 0); + uepc_i : in std_logic_vector(31 downto 0); + ucause_i : in std_logic_vector(31 downto 0); + utval_i : in std_logic_vector(31 downto 0); + uip_i : in std_logic_vector(31 downto 0); + -- error counter inputs + reg1_cen_i : in std_logic; + reg1_sbu_i : in std_logic; + reg1_dbu_i : in std_logic; + reg2_cen_i : in std_logic; + reg2_sbu_i : in std_logic; + reg2_dbu_i : in std_logic; + pc_cen_i : in std_logic; + pc_sbu_i : in std_logic; + pc_dbu_i : in std_logic; + dmem_cen_i : in std_logic; + dmem_sbu_i : in std_logic; + dmem_dbu_i : in std_logic; + control_cen_i : in std_logic; + control_err_i : in std_logic; + alu_cen_i : in std_logic; + alu_err_i : in std_logic; + -- hardening configuration outputs + hard_pc_o : out std_logic; + hard_regfile_o : out std_logic; + hard_dmem_o : out std_logic; + hard_control_o : out std_logic; + hard_alu_o : out std_logic; + -- reset cause input + poweron_rstn_i : in std_logic; + wdt_rstn_i : in std_logic + ); +end entity; + +architecture arch of csr is + -- USER: Counter/Timers + constant CYCLE_ADDR : std_logic_vector(11 downto 0) := x"C00"; + constant TIME_ADDR : std_logic_vector(11 downto 0) := x"C01"; + constant INSTRET_ADDR : std_logic_vector(11 downto 0) := x"C02"; + constant CYCLEH_ADDR : std_logic_vector(11 downto 0) := x"C80"; + constant TIMEH_ADDR : std_logic_vector(11 downto 0) := x"C81"; + constant INSTRETH_ADDR : std_logic_vector(11 downto 0) := x"C82"; + -- USER: trap handling + constant USCRATCH_ADDR : std_logic_vector(11 downto 0) := x"040"; + constant UEPC_ADDR : std_logic_vector(11 downto 0) := x"041"; + constant UCAUSE_ADDR : std_logic_vector(11 downto 0) := x"042"; + constant UTVAL_ADDR : std_logic_vector(11 downto 0) := x"043"; + constant UIP_ADDR : std_logic_vector(11 downto 0) := x"044"; + -- MACHINE: custom error counter registers + constant REG1_SBU_ADDR : std_logic_vector(11 downto 0) := x"7C0"; + constant REG1_DBU_ADDR : std_logic_vector(11 downto 0) := x"7C1"; + constant REG2_SBU_ADDR : std_logic_vector(11 downto 0) := x"7C2"; + constant REG2_DBU_ADDR : std_logic_vector(11 downto 0) := x"7C3"; + constant PC_SBU_ADDR : std_logic_vector(11 downto 0) := x"7C4"; + constant PC_DBU_ADDR : std_logic_vector(11 downto 0) := x"7C5"; + constant DMEM_SBU_ADDR : std_logic_vector(11 downto 0) := x"7C6"; + constant DMEM_DBU_ADDR : std_logic_vector(11 downto 0) := x"7C7"; + constant CONTROL_ERR_ADDR : std_logic_vector(11 downto 0) := x"7C8"; + constant ALU_ERR_ADDR : std_logic_vector(11 downto 0) := x"7C9"; + -- MACHINE: hardening configuration + constant HARDEN_CONF_ADDR : std_logic_vector(11 downto 0) := x"BC0"; + -- MACHINE: information + constant MVENDORID_ADDR : std_logic_vector(11 downto 0) := x"F11"; + constant MARCHID_ADDR : std_logic_vector(11 downto 0) := x"F12"; + constant MIMPID_ADDR : std_logic_vector(11 downto 0) := x"F13"; + constant MHARTID_ADDR : std_logic_vector(11 downto 0) := x"F14"; + -- MACHINE: reset cause + constant RSTCAUSE_ADDR : std_logic_vector(11 downto 0) := x"FC0"; + + -- Registers from unprivileged specification -- except float CSR + signal cycle_r : std_logic_vector(31 downto 0); -- read by RDCYCLE + signal time_r : std_logic_vector(31 downto 0); -- read by RDTIME + signal instret_r : std_logic_vector(31 downto 0); -- read by RDINSTRET + signal cycleh_r : std_logic_vector(31 downto 0); -- read by RDCYCLEH + signal timeh_r : std_logic_vector(31 downto 0); -- read by RDTIMEH + signal instreth_r : std_logic_vector(31 downto 0); -- read by RDINSTRETH + + -- Registers for trap handling + signal uscratch_r : std_logic_vector(31 downto 0); --at 0x040 + signal uepc_r : std_logic_vector(31 downto 0); --at 0x041 + signal ucause_r : std_logic_vector(31 downto 0); --at 0x042 + signal utval_r : std_logic_vector(31 downto 0); --at 0x043 + signal uip_r : std_logic_vector(31 downto 0); --at 0x044 + + -- Registers for error counting + signal reg1_sbu_r : std_logic_vector(31 downto 0); -- at 0x7C0 + signal reg1_dbu_r : std_logic_vector(31 downto 0); -- at 0x7C1 + + signal reg2_sbu_r : std_logic_vector(31 downto 0); -- at 0x7C2 + signal reg2_dbu_r : std_logic_vector(31 downto 0); -- at 0x7C3 + + signal pc_sbu_r : std_logic_vector(31 downto 0); -- at 0x7C4 + signal pc_dbu_r : std_logic_vector(31 downto 0); -- at 0x7C5 + + signal dmem_sbu_r : std_logic_vector(31 downto 0); -- at 0x7C6 + signal dmem_dbu_r : std_logic_vector(31 downto 0); -- at 0x7C7 + + signal control_err_r : std_logic_vector(31 downto 0); -- at 0x7C8 + signal alu_err_r : std_logic_vector(31 downto 0); -- at 0x7C9 + + -- Register for hardening flags + signal harden_conf_r : std_logic_vector(31 downto 0); -- at 0xBC0 + + -- Registers for information registers + signal mvendorid_r : std_logic_vector(31 downto 0); + signal marchid_r : std_logic_vector(31 downto 0); + signal mimpid_r : std_logic_vector(31 downto 0); + signal mhartid_r : std_logic_vector(31 downto 0); + + -- Register for reset cause + signal rstcause_r : std_logic_vector(31 downto 0); + + -- write and read signals + signal wdata_w : std_logic_vector(31 downto 0); + signal rdata_w : std_logic_vector(31 downto 0); + + -- auxiliar signals + signal mask_w : std_logic_vector(31 downto 0); + signal cleared_data_w : std_logic_vector(31 downto 0); + signal setted_data_w : std_logic_vector(31 downto 0); + signal maskop_res_w : std_logic_vector(31 downto 0); + +begin + + rdata_w <= cycle_r when addr_i = CYCLE_ADDR else + time_r when addr_i = TIME_ADDR else + instret_r when addr_i = INSTRET_ADDR else + cycleh_r when addr_i = CYCLEH_ADDR else + timeh_r when addr_i = TIMEH_ADDR else + instreth_r when addr_i = INSTRETH_ADDR else + -- USER TRAP + uscratch_r when addr_i = USCRATCH_ADDR else + uepc_r when addr_i = UEPC_ADDR else + ucause_r when addr_i = UCAUSE_ADDR else + utval_r when addr_i = UTVAL_ADDR else + uip_r when addr_i = UIP_ADDR else + -- MACHINE INFORMATION + mvendorid_r when addr_i = MVENDORID_ADDR else + marchid_r when addr_i = MARCHID_ADDR else + mimpid_r when addr_i = MIMPID_ADDR else + mhartid_r when addr_i = MHARTID_ADDR else + -- MACHINE HARDENING CONFIGURATION + harden_conf_r when addr_i = HARDEN_CONF_ADDR else + -- MACHINE RSTCAUSE + rstcause_r when addr_i = RSTCAUSE_ADDR else + -- CUSTOM ERROR + reg1_sbu_r when addr_i = REG1_SBU_ADDR else + reg1_dbu_r when addr_i = REG1_DBU_ADDR else + reg2_sbu_r when addr_i = REG2_SBU_ADDR else + reg2_dbu_r when addr_i = REG2_DBU_ADDR else + pc_sbu_r when addr_i = PC_SBU_ADDR else + pc_dbu_r when addr_i = PC_DBU_ADDR else + dmem_sbu_r when addr_i = DMEM_SBU_ADDR else + dmem_dbu_r when addr_i = DMEM_DBU_ADDR else + control_err_r when addr_i = CONTROL_ERR_ADDR else + alu_err_r when addr_i = ALU_ERR_ADDR else + x"deadbeef"; + data_o <= rdata_w; + + -- define data to be written + mask_w <= ((31 downto 5 => '0') & imm_data_i) when source_imm_i = '1' else rs1_data_i; + + cleared_data_w <= rdata_w and (not mask_w); + setted_data_w <= rdata_w or mask_w; + + maskop_res_w <= cleared_data_w when csr_clearop_i = '1' else setted_data_w; + + -- select data that will be written + wdata_w <= maskop_res_w when csr_maskop_i = '1' else rs1_data_i; + + + -------------------------------------------------------------------------------------- + --------------------------------------- CSRs ----------------------------------------- + -------------------------------------------------------------------------------------- + + p_CYCLE_COUNT : process(clk_i, rstn_i) + begin + if rstn_i = '0' then + cycle_r <= (others => '0'); + cycleh_r <= (others => '0'); + elsif rising_edge(clk_i) then + -- increment cycle + cycle_r <= std_logic_vector(unsigned(cycle_r) + 1); + -- in case of cycle_r overflow, increase cycleh_r + if cycle_r = x"FFFFFFFF" then + cycleh_r <= std_logic_vector(unsigned(cycleh_r) + 1); + end if; + end if; + end process; + + p_TIME_COUNT : process(clk_i, rstn_i) + begin + if rstn_i = '0' then + time_r <= (others => '0'); + timeh_r <= (others => '0'); + elsif rising_edge(clk_i) then + -- increment time + time_r <= std_logic_vector(unsigned(time_r) + 1); + -- in case of time_r overflow, increase timeh_r + if time_r = x"FFFFFFFF" then + timeh_r <= std_logic_vector(unsigned(timeh_r) + 1); + end if; + end if; + end process; + + p_TRAP_REGISTERS : process(clk_i) + begin + if rising_edge(clk_i) then + if trap_i = '1' then + uscratch_r <= uscratch_i; + uepc_r <= uepc_i; + ucause_r <= ucause_i; + utval_r <= utval_i; + uip_r <= uip_i; + end if; + end if; + end process; + + -- information registers + mvendorid_r <= x"CAFECAFE"; + marchid_r <= x"000000CA"; + mimpid_r(31 downto 6) <= (others => '0'); + mimpid_r( 3 downto 2) <= (others => '0'); + mimpid_r(0) <= '1' when HAMMING_PC else '0'; + mimpid_r(1) <= '1' when HAMMING_REGFILE else '0'; + mimpid_r(4) <= '1' when TMR_CONTROL else '0'; + mimpid_r(5) <= '1' when TMR_ALU else '0'; + mhartid_r <= x"00000000"; + + p_RSTCAUSE : process(poweron_rstn_i, wdt_rstn_i) + begin + if poweron_rstn_i = '0' then + rstcause_r <= x"00000001"; + elsif wdt_rstn_i = '0' then + rstcause_r <= x"00000002"; + end if; + end process; + + p_HARDENING : process(clk_i) + begin + if rising_edge(clk_i) then + if wren_i = '1' and addr_i = HARDEN_CONF_ADDR then + harden_conf_r <= wdata_w; + end if; + end if; + end process; + -- Hamming + hard_pc_o <= harden_conf_r(0); + hard_regfile_o <= harden_conf_r(1); + hard_dmem_o <= harden_conf_r(2); + -- TMR + hard_control_o <= harden_conf_r(4); + hard_alu_o <= harden_conf_r(5); + + p_ERROR_COUNT : process(clk_i) + begin + if rising_edge(clk_i) then + + -- Register file upsets + if wren_i = '1' and addr_i = REG1_SBU_ADDR then + reg1_sbu_r <= wdata_w; + elsif reg1_cen_i = '1' and reg1_sbu_i = '1' then + reg1_sbu_r <= std_logic_vector(unsigned(reg1_sbu_r)+1); + end if; + + if wren_i = '1' and addr_i = REG1_DBU_ADDR then + reg1_dbu_r <= wdata_w; + elsif reg1_cen_i = '1' and reg1_dbu_i = '1' then + reg1_dbu_r <= std_logic_vector(unsigned(reg1_dbu_r)+1); + end if; + + -- Register file upsets + if wren_i = '1' and addr_i = REG2_SBU_ADDR then + reg2_sbu_r <= wdata_w; + elsif reg2_cen_i = '1' and reg2_sbu_i = '1' then + reg2_sbu_r <= std_logic_vector(unsigned(reg2_sbu_r)+1); + end if; + + if wren_i = '1' and addr_i = REG2_DBU_ADDR then + reg2_dbu_r <= wdata_w; + elsif reg2_cen_i = '1' and reg2_dbu_i = '1' then + reg2_dbu_r <= std_logic_vector(unsigned(reg2_dbu_r)+1); + end if; + + -- PC upsets + if wren_i = '1' and addr_i = PC_SBU_ADDR then + pc_sbu_r <= wdata_w; + elsif pc_cen_i = '1' and pc_sbu_i = '1' then + pc_sbu_r <= std_logic_vector(unsigned(pc_sbu_r)+1); + end if; + + if wren_i = '1' and addr_i = PC_DBU_ADDR then + pc_dbu_r <= wdata_w; + elsif pc_cen_i = '1' and pc_dbu_i = '1' then + pc_dbu_r <= std_logic_vector(unsigned(pc_dbu_r)+1); + end if; + + -- Data memory upsets + if wren_i = '1' and addr_i = DMEM_SBU_ADDR then + dmem_sbu_r <= wdata_w; + elsif dmem_cen_i = '1' and dmem_sbu_i = '1' then + dmem_sbu_r <= std_logic_vector(unsigned(dmem_sbu_r)+1); + end if; + + if wren_i = '1' and addr_i = DMEM_DBU_ADDR then + dmem_dbu_r <= wdata_w; + elsif dmem_cen_i = '1' and dmem_dbu_i = '1' then + dmem_dbu_r <= std_logic_vector(unsigned(dmem_dbu_r)+1); + end if; + + -- CONTROL errors + if wren_i = '1' and addr_i = CONTROL_ERR_ADDR then + control_err_r <= wdata_w; + elsif control_cen_i = '1' and control_err_i = '1' then + control_err_r <= std_logic_vector(unsigned(control_err_r)+1); + end if; + + -- ALU errors + if wren_i = '1' and addr_i = ALU_ERR_ADDR then + alu_err_r <= wdata_w; + elsif alu_cen_i = '1' and alu_err_i = '1' then + alu_err_r <= std_logic_vector(unsigned(alu_err_r)+1); + end if; + + end if; + end process; + +end architecture; diff --git a/hdl/ft_components/alu_tmr.vhd b/hdl/ft_components/alu_tmr.vhd new file mode 100644 index 0000000..7cb1c72 --- /dev/null +++ b/hdl/ft_components/alu_tmr.vhd @@ -0,0 +1,80 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_misc.all; + +library work; +use work.harv_pkg.all; + +entity alu_tmr is + port ( + -- input ports + data1_i : in std_logic_vector(31 downto 0); + data2_i : in std_logic_vector(31 downto 0); + operation_i : in std_logic_vector(ALUOP_SIZE-1 downto 0); + correct_error_i : in std_logic; + -- output ports + error_o : out std_logic; + zero_o : out std_logic; + data_o : out std_logic_vector(31 downto 0) + ); +end entity; + +architecture arch of alu_tmr is + type tmr_std_logic_t is array(2 downto 0) of std_logic; + signal zero_w : tmr_std_logic_t; + signal corr_zero_w : std_logic; + signal error_zero_w : std_logic; + + type tmr_data_t is array(2 downto 0) of std_logic_vector(31 downto 0); + signal data_w : tmr_data_t; + signal corr_data_w : std_logic_vector(31 downto 0); + signal error_data_w : std_logic; + +begin + gen_TMR : for i in 2 downto 0 generate + -- Xilinx attributes to prevent optimization of TMR + attribute DONT_TOUCH : string; + attribute DONT_TOUCH of alu_i : label is "TRUE"; + -- Synplify attributes to prevent optimization of TMR + attribute syn_radhardlevel : string; + attribute syn_keep : boolean; + attribute syn_safe_case : boolean; + attribute syn_noprune : boolean; + attribute syn_radhardlevel of alu_i : label is "tmr"; + attribute syn_keep of alu_i : label is TRUE; + attribute syn_safe_case of alu_i : label is TRUE; + attribute syn_noprune of alu_i : label is TRUE; + begin + alu_i : alu + port map ( + data1_i => data1_i, + data2_i => data2_i, + operation_i => operation_i, + zero_o => zero_w(i), + data_o => data_w(i) + ); + end generate; + + corr_zero_w <= (zero_w(2) and zero_w(1)) or + (zero_w(2) and zero_w(0)) or + (zero_w(1) and zero_w(0)); + + corr_data_w <= (data_w(2) and data_w(1)) or + (data_w(2) and data_w(0)) or + (data_w(1) and data_w(0)); + + error_zero_w <= (zero_w(2) xor zero_w(1)) or + (zero_w(2) xor zero_w(0)) or + (zero_w(1) xor zero_w(0)); + + error_data_w <= or_reduce((data_w(2) xor data_w(1)) or + (data_w(2) xor data_w(0)) or + (data_w(1) xor data_w(0))); + + error_o <= error_zero_w or error_data_w; + + zero_o <= corr_zero_w when correct_error_i = '1' else zero_w(0); + data_o <= corr_data_w when correct_error_i = '1' else data_w(0); + +end architecture; diff --git a/hdl/ft_components/control_tmr.vhd b/hdl/ft_components/control_tmr.vhd new file mode 100644 index 0000000..037a7b0 --- /dev/null +++ b/hdl/ft_components/control_tmr.vhd @@ -0,0 +1,299 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_misc.all; + +library work; +use work.harv_pkg.all; + +entity control_tmr is + port ( + -- input ports + -- processor status + imem_gnt_i : in std_logic; + imem_err_i : in std_logic; + dmem_gnt_i : in std_logic; + dmem_outofrange_i : in std_logic; + dmem_sbu_i : in std_logic; + dmem_dbu_i : in std_logic; + + -- instruction decode + opcode_i : in std_logic_vector(6 downto 0); + funct3_i : in std_logic_vector(2 downto 0); + funct7_i : in std_logic_vector(6 downto 0); + funct12_i : in std_logic_vector(11 downto 0); + + -- hardening + correct_error_i : in std_logic; + + -- sync + rstn_i : in std_logic; + clk_i : in std_logic; + start_i : in std_logic; + + -- output ports + -- processor status + imem_req_o : out std_logic; + dmem_req_o : out std_logic; + + update_pc_o : out std_logic; + trap_o : out std_logic; + + -- hardening + error_o : out std_logic; + + -- ALU operations + aluop_o : out std_logic_vector(ALUOP_SIZE-1 downto 0); + alusrc_imm_o : out std_logic; + -- immediate selector + imm_shamt_o : out std_logic; + imm_up_o : out std_logic; + -- register bank + regwr_o : out std_logic; + -- control transfer + inv_branch_o : out std_logic; + branch_o : out std_logic; + jump_o : out std_logic; + jalr_o : out std_logic; + ecall_o : out std_logic; + -- mem access + memrd_o : out std_logic; + memwr_o : out std_logic; + byte_en_o : out std_logic_vector(1 downto 0); + mem_usgn_o : out std_logic; -- unsigned data + -- U type + load_upimm_o : out std_logic; + auipc_o : out std_logic; + -- csr control + csr_enable_o : out std_logic; + csr_source_imm_o : out std_logic; + csr_maskop_o : out std_logic; + csr_clearop_o : out std_logic + ); +end entity; + +architecture arch of control_tmr is + type tmr_std_logic_t is array(2 downto 0) of std_logic; + signal imem_req_w : tmr_std_logic_t; + signal dmem_req_w : tmr_std_logic_t; + signal update_pc_w : tmr_std_logic_t; + signal trap_w : tmr_std_logic_t; + signal alusrc_imm_w : tmr_std_logic_t; + signal imm_shamt_w : tmr_std_logic_t; + signal imm_up_w : tmr_std_logic_t; + signal regwr_w : tmr_std_logic_t; + signal inv_branch_w : tmr_std_logic_t; + signal branch_w : tmr_std_logic_t; + signal jump_w : tmr_std_logic_t; + signal jalr_w : tmr_std_logic_t; + signal ecall_w : tmr_std_logic_t; + signal memrd_w : tmr_std_logic_t; + signal memwr_w : tmr_std_logic_t; + signal mem_usgn_w : tmr_std_logic_t; + signal load_upimm_w : tmr_std_logic_t; + signal auipc_w : tmr_std_logic_t; + signal csr_enable_w : tmr_std_logic_t; + signal csr_source_imm_w : tmr_std_logic_t; + signal csr_maskop_w : tmr_std_logic_t; + signal csr_clearop_w : tmr_std_logic_t; + + signal corr_imem_req_w : std_logic; + signal corr_dmem_req_w : std_logic; + signal corr_update_pc_w : std_logic; + signal corr_trap_w : std_logic; + signal corr_alusrc_imm_w : std_logic; + signal corr_imm_shamt_w : std_logic; + signal corr_imm_up_w : std_logic; + signal corr_regwr_w : std_logic; + signal corr_inv_branch_w : std_logic; + signal corr_branch_w : std_logic; + signal corr_jump_w : std_logic; + signal corr_jalr_w : std_logic; + signal corr_ecall_w : std_logic; + signal corr_memrd_w : std_logic; + signal corr_memwr_w : std_logic; + signal corr_mem_usgn_w : std_logic; + signal corr_load_upimm_w : std_logic; + signal corr_auipc_w : std_logic; + signal corr_csr_enable_w : std_logic; + signal corr_csr_source_imm_w : std_logic; + signal corr_csr_maskop_w : std_logic; + signal corr_csr_clearop_w : std_logic; + + signal error_imem_req_w : std_logic; + signal error_dmem_req_w : std_logic; + signal error_update_pc_w : std_logic; + signal error_trap_w : std_logic; + signal error_alusrc_imm_w : std_logic; + signal error_imm_shamt_w : std_logic; + signal error_imm_up_w : std_logic; + signal error_regwr_w : std_logic; + signal error_inv_branch_w : std_logic; + signal error_branch_w : std_logic; + signal error_jump_w : std_logic; + signal error_jalr_w : std_logic; + signal error_ecall_w : std_logic; + signal error_memrd_w : std_logic; + signal error_memwr_w : std_logic; + signal error_mem_usgn_w : std_logic; + signal error_load_upimm_w : std_logic; + signal error_auipc_w : std_logic; + signal error_csr_enable_w : std_logic; + signal error_csr_source_imm_w : std_logic; + signal error_csr_maskop_w : std_logic; + signal error_csr_clearop_w : std_logic; + + type tmr_alu_operations_t is array(2 downto 0) of std_logic_vector(ALUOP_SIZE-1 downto 0); + signal aluop_w : tmr_alu_operations_t; + signal corr_aluop_w : std_logic_vector(ALUOP_SIZE-1 downto 0); + signal error_aluop_w : std_logic; + + type tmr_std_logic_2_t is array(2 downto 0) of std_logic_vector(1 downto 0); + signal byte_en_w : tmr_std_logic_2_t; + signal corr_byte_en_w : std_logic_vector(1 downto 0); + signal error_byte_en_w : std_logic; + +begin + gen_TMR : for i in 2 downto 0 generate + -- Xilinx attributes to prevent optimization of TMR + attribute DONT_TOUCH : string; + attribute DONT_TOUCH of control_i : label is "TRUE"; + -- Synplify attributes to prevent optimization of TMR + attribute syn_radhardlevel : string; + attribute syn_keep : boolean; + attribute syn_safe_case : boolean; + attribute syn_noprune : boolean; + attribute syn_radhardlevel of control_i : label is "tmr"; + attribute syn_keep of control_i : label is TRUE; + attribute syn_safe_case of control_i : label is TRUE; + attribute syn_noprune of control_i : label is TRUE; + begin + control_i : control + port map ( + imem_gnt_i => imem_gnt_i, + imem_err_i => imem_err_i, + dmem_gnt_i => dmem_gnt_i, + dmem_outofrange_i => dmem_outofrange_i, + dmem_sbu_i => dmem_sbu_i, + dmem_dbu_i => dmem_dbu_i, + opcode_i => opcode_i, + funct3_i => funct3_i, + funct7_i => funct7_i, + funct12_i => funct12_i, + rstn_i => rstn_i, + clk_i => clk_i, + start_i => start_i, + imem_req_o => imem_req_w(i), + dmem_req_o => dmem_req_w(i), + update_pc_o => update_pc_w(i), + trap_o => trap_w(i), + aluop_o => aluop_w(i), + alusrc_imm_o => alusrc_imm_w(i), + imm_shamt_o => imm_shamt_w(i), + imm_up_o => imm_up_w(i), + regwr_o => regwr_w(i), + inv_branch_o => inv_branch_w(i), + branch_o => branch_w(i), + jump_o => jump_w(i), + jalr_o => jalr_w(i), + ecall_o => ecall_w(i), + memrd_o => memrd_w(i), + memwr_o => memwr_w(i), + byte_en_o => byte_en_w(i), + mem_usgn_o => mem_usgn_w(i), + load_upimm_o => load_upimm_w(i), + auipc_o => auipc_w(i), + csr_enable_o => csr_enable_w(i), + csr_source_imm_o => csr_source_imm_w(i), + csr_maskop_o => csr_maskop_w(i), + csr_clearop_o => csr_clearop_w(i) + ); + end generate; + + corr_imem_req_w <= ( imem_req_w(2) and imem_req_w(1)) or ( imem_req_w(2) and imem_req_w(0)) or ( imem_req_w(1) and imem_req_w(0)); + corr_dmem_req_w <= ( dmem_req_w(2) and dmem_req_w(1)) or ( dmem_req_w(2) and dmem_req_w(0)) or ( dmem_req_w(1) and dmem_req_w(0)); + corr_update_pc_w <= ( update_pc_w(2) and update_pc_w(1)) or ( update_pc_w(2) and update_pc_w(0)) or ( update_pc_w(1) and update_pc_w(0)); + corr_trap_w <= ( trap_w(2) and trap_w(1)) or ( trap_w(2) and trap_w(0)) or ( trap_w(1) and trap_w(0)); + corr_aluop_w <= ( aluop_w(2) and aluop_w(1)) or ( aluop_w(2) and aluop_w(0)) or ( aluop_w(1) and aluop_w(0)); + corr_alusrc_imm_w <= ( alusrc_imm_w(2) and alusrc_imm_w(1)) or ( alusrc_imm_w(2) and alusrc_imm_w(0)) or ( alusrc_imm_w(1) and alusrc_imm_w(0)); + corr_imm_shamt_w <= ( imm_shamt_w(2) and imm_shamt_w(1)) or ( imm_shamt_w(2) and imm_shamt_w(0)) or ( imm_shamt_w(1) and imm_shamt_w(0)); + corr_imm_up_w <= ( imm_up_w(2) and imm_up_w(1)) or ( imm_up_w(2) and imm_up_w(0)) or ( imm_up_w(1) and imm_up_w(0)); + corr_regwr_w <= ( regwr_w(2) and regwr_w(1)) or ( regwr_w(2) and regwr_w(0)) or ( regwr_w(1) and regwr_w(0)); + corr_inv_branch_w <= ( inv_branch_w(2) and inv_branch_w(1)) or ( inv_branch_w(2) and inv_branch_w(0)) or ( inv_branch_w(1) and inv_branch_w(0)); + corr_branch_w <= ( branch_w(2) and branch_w(1)) or ( branch_w(2) and branch_w(0)) or ( branch_w(1) and branch_w(0)); + corr_jump_w <= ( jump_w(2) and jump_w(1)) or ( jump_w(2) and jump_w(0)) or ( jump_w(1) and jump_w(0)); + corr_jalr_w <= ( jalr_w(2) and jalr_w(1)) or ( jalr_w(2) and jalr_w(0)) or ( jalr_w(1) and jalr_w(0)); + corr_ecall_w <= ( ecall_w(2) and ecall_w(1)) or ( ecall_w(2) and ecall_w(0)) or ( ecall_w(1) and ecall_w(0)); + corr_memrd_w <= ( memrd_w(2) and memrd_w(1)) or ( memrd_w(2) and memrd_w(0)) or ( memrd_w(1) and memrd_w(0)); + corr_memwr_w <= ( memwr_w(2) and memwr_w(1)) or ( memwr_w(2) and memwr_w(0)) or ( memwr_w(1) and memwr_w(0)); + corr_byte_en_w <= ( byte_en_w(2) and byte_en_w(1)) or ( byte_en_w(2) and byte_en_w(0)) or ( byte_en_w(1) and byte_en_w(0)); + corr_mem_usgn_w <= ( mem_usgn_w(2) and mem_usgn_w(1)) or ( mem_usgn_w(2) and mem_usgn_w(0)) or ( mem_usgn_w(1) and mem_usgn_w(0)); + corr_load_upimm_w <= ( load_upimm_w(2) and load_upimm_w(1)) or ( load_upimm_w(2) and load_upimm_w(0)) or ( load_upimm_w(1) and load_upimm_w(0)); + corr_auipc_w <= ( auipc_w(2) and auipc_w(1)) or ( auipc_w(2) and auipc_w(0)) or ( auipc_w(1) and auipc_w(0)); + corr_csr_enable_w <= ( csr_enable_w(2) and csr_enable_w(1)) or ( csr_enable_w(2) and csr_enable_w(0)) or ( csr_enable_w(1) and csr_enable_w(0)); + corr_csr_source_imm_w <= ( csr_source_imm_w(2) and csr_source_imm_w(1)) or ( csr_source_imm_w(2) and csr_source_imm_w(0)) or ( csr_source_imm_w(1) and csr_source_imm_w(0)); + corr_csr_maskop_w <= ( csr_maskop_w(2) and csr_maskop_w(1)) or ( csr_maskop_w(2) and csr_maskop_w(0)) or ( csr_maskop_w(1) and csr_maskop_w(0)); + corr_csr_clearop_w <= ( csr_clearop_w(2) and csr_clearop_w(1)) or ( csr_clearop_w(2) and csr_clearop_w(0)) or ( csr_clearop_w(1) and csr_clearop_w(0)); + + error_imem_req_w <= ( imem_req_w(2) xor imem_req_w(1)) or ( imem_req_w(2) xor imem_req_w(0)) or ( imem_req_w(1) xor imem_req_w(0)); + error_dmem_req_w <= ( dmem_req_w(2) xor dmem_req_w(1)) or ( dmem_req_w(2) xor dmem_req_w(0)) or ( dmem_req_w(1) xor dmem_req_w(0)); + error_update_pc_w <= ( update_pc_w(2) xor update_pc_w(1)) or ( update_pc_w(2) xor update_pc_w(0)) or ( update_pc_w(1) xor update_pc_w(0)); + error_trap_w <= ( trap_w(2) xor trap_w(1)) or ( trap_w(2) xor trap_w(0)) or ( trap_w(1) xor trap_w(0)); + error_aluop_w <= or_reduce(( aluop_w(2) xor aluop_w(1)) or ( aluop_w(2) xor aluop_w(0)) or ( aluop_w(1) xor aluop_w(0))); + error_alusrc_imm_w <= ( alusrc_imm_w(2) xor alusrc_imm_w(1)) or ( alusrc_imm_w(2) xor alusrc_imm_w(0)) or ( alusrc_imm_w(1) xor alusrc_imm_w(0)); + error_imm_shamt_w <= ( imm_shamt_w(2) xor imm_shamt_w(1)) or ( imm_shamt_w(2) xor imm_shamt_w(0)) or ( imm_shamt_w(1) xor imm_shamt_w(0)); + error_imm_up_w <= ( imm_up_w(2) xor imm_up_w(1)) or ( imm_up_w(2) xor imm_up_w(0)) or ( imm_up_w(1) xor imm_up_w(0)); + error_regwr_w <= ( regwr_w(2) xor regwr_w(1)) or ( regwr_w(2) xor regwr_w(0)) or ( regwr_w(1) xor regwr_w(0)); + error_inv_branch_w <= ( inv_branch_w(2) xor inv_branch_w(1)) or ( inv_branch_w(2) xor inv_branch_w(0)) or ( inv_branch_w(1) xor inv_branch_w(0)); + error_branch_w <= ( branch_w(2) xor branch_w(1)) or ( branch_w(2) xor branch_w(0)) or ( branch_w(1) xor branch_w(0)); + error_jump_w <= ( jump_w(2) xor jump_w(1)) or ( jump_w(2) xor jump_w(0)) or ( jump_w(1) xor jump_w(0)); + error_jalr_w <= ( jalr_w(2) xor jalr_w(1)) or ( jalr_w(2) xor jalr_w(0)) or ( jalr_w(1) xor jalr_w(0)); + error_ecall_w <= ( ecall_w(2) xor ecall_w(1)) or ( ecall_w(2) xor ecall_w(0)) or ( ecall_w(1) xor ecall_w(0)); + error_memrd_w <= ( memrd_w(2) xor memrd_w(1)) or ( memrd_w(2) xor memrd_w(0)) or ( memrd_w(1) xor memrd_w(0)); + error_memwr_w <= ( memwr_w(2) xor memwr_w(1)) or ( memwr_w(2) xor memwr_w(0)) or ( memwr_w(1) xor memwr_w(0)); + error_byte_en_w <= or_reduce(( byte_en_w(2) xor byte_en_w(1)) or ( byte_en_w(2) xor byte_en_w(0)) or ( byte_en_w(1) xor byte_en_w(0))); + error_mem_usgn_w <= ( mem_usgn_w(2) xor mem_usgn_w(1)) or ( mem_usgn_w(2) xor mem_usgn_w(0)) or ( mem_usgn_w(1) xor mem_usgn_w(0)); + error_load_upimm_w <= ( load_upimm_w(2) xor load_upimm_w(1)) or ( load_upimm_w(2) xor load_upimm_w(0)) or ( load_upimm_w(1) xor load_upimm_w(0)); + error_auipc_w <= ( auipc_w(2) xor auipc_w(1)) or ( auipc_w(2) xor auipc_w(0)) or ( auipc_w(1) xor auipc_w(0)); + error_csr_enable_w <= ( csr_enable_w(2) xor csr_enable_w(1)) or ( csr_enable_w(2) xor csr_enable_w(0)) or ( csr_enable_w(1) xor csr_enable_w(0)); + error_csr_source_imm_w <= ( csr_source_imm_w(2) xor csr_source_imm_w(1)) or ( csr_source_imm_w(2) xor csr_source_imm_w(0)) or ( csr_source_imm_w(1) xor csr_source_imm_w(0)); + error_csr_maskop_w <= ( csr_maskop_w(2) xor csr_maskop_w(1)) or ( csr_maskop_w(2) xor csr_maskop_w(0)) or ( csr_maskop_w(1) xor csr_maskop_w(0)); + error_csr_clearop_w <= ( csr_clearop_w(2) xor csr_clearop_w(1)) or ( csr_clearop_w(2) xor csr_clearop_w(0)) or ( csr_clearop_w(1) xor csr_clearop_w(0)); + + + error_o <= error_imem_req_w or error_dmem_req_w or error_update_pc_w or + error_trap_w or error_aluop_w or error_alusrc_imm_w or + error_imm_shamt_w or error_imm_up_w or error_regwr_w or + error_inv_branch_w or error_branch_w or error_jump_w or + error_jalr_w or error_ecall_w or error_memrd_w or + error_memwr_w or error_byte_en_w or error_mem_usgn_w or + error_load_upimm_w or error_auipc_w or error_csr_enable_w or + error_csr_source_imm_w or error_csr_maskop_w or error_csr_clearop_w; + + + imem_req_o <= corr_imem_req_w when correct_error_i = '1' else imem_req_w (0); + dmem_req_o <= corr_dmem_req_w when correct_error_i = '1' else dmem_req_w (0); + update_pc_o <= corr_update_pc_w when correct_error_i = '1' else update_pc_w (0); + trap_o <= corr_trap_w when correct_error_i = '1' else trap_w (0); + aluop_o <= corr_aluop_w when correct_error_i = '1' else aluop_w (0); + alusrc_imm_o <= corr_alusrc_imm_w when correct_error_i = '1' else alusrc_imm_w (0); + imm_shamt_o <= corr_imm_shamt_w when correct_error_i = '1' else imm_shamt_w (0); + imm_up_o <= corr_imm_up_w when correct_error_i = '1' else imm_up_w (0); + regwr_o <= corr_regwr_w when correct_error_i = '1' else regwr_w (0); + inv_branch_o <= corr_inv_branch_w when correct_error_i = '1' else inv_branch_w (0); + branch_o <= corr_branch_w when correct_error_i = '1' else branch_w (0); + jump_o <= corr_jump_w when correct_error_i = '1' else jump_w (0); + jalr_o <= corr_jalr_w when correct_error_i = '1' else jalr_w (0); + ecall_o <= corr_ecall_w when correct_error_i = '1' else ecall_w (0); + memrd_o <= corr_memrd_w when correct_error_i = '1' else memrd_w (0); + memwr_o <= corr_memwr_w when correct_error_i = '1' else memwr_w (0); + byte_en_o <= corr_byte_en_w when correct_error_i = '1' else byte_en_w (0); + mem_usgn_o <= corr_mem_usgn_w when correct_error_i = '1' else mem_usgn_w (0); + load_upimm_o <= corr_load_upimm_w when correct_error_i = '1' else load_upimm_w (0); + auipc_o <= corr_auipc_w when correct_error_i = '1' else auipc_w (0); + csr_enable_o <= corr_csr_enable_w when correct_error_i = '1' else csr_enable_w (0); + csr_source_imm_o <= corr_csr_source_imm_w when correct_error_i = '1' else csr_source_imm_w(0); + csr_maskop_o <= corr_csr_maskop_w when correct_error_i = '1' else csr_maskop_w (0); + csr_clearop_o <= corr_csr_clearop_w when correct_error_i = '1' else csr_clearop_w (0); + +end architecture; diff --git a/hdl/ft_components/hamming_decoder.vhd b/hdl/ft_components/hamming_decoder.vhd new file mode 100644 index 0000000..33ff2b5 --- /dev/null +++ b/hdl/ft_components/hamming_decoder.vhd @@ -0,0 +1,80 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_misc.all; + +library work; +use work.hamming_pkg.all; + +entity hamming_decoder is + generic ( + DATA_SIZE : integer := 32; -- 64(7), 32(6), 16(5), 8(4), 4(3) + DETECT_DOUBLE : boolean + ); + port ( + encoded_i : in std_logic_vector(DATA_SIZE+get_ecc_size(DATA_SIZE, DETECT_DOUBLE)-1 downto 0); + correct_error_i : in std_logic; + single_err_o : out std_logic; + double_err_o : out std_logic; + data_o : out std_logic_vector(DATA_SIZE-1 downto 0) + ); +end entity; + +architecture arch of hamming_decoder is + constant HAMM_PARITY_SIZE : integer := get_ecc_size(DATA_SIZE, FALSE); + constant TOTAL_PARITY_SIZE : integer := get_ecc_size(DATA_SIZE, DETECT_DOUBLE); + signal parity_data_w : std_logic_vector(HAMM_PARITY_SIZE-1 downto 0); + signal parity_diff_w : std_logic_vector(HAMM_PARITY_SIZE-1 downto 0); + signal corr_mask_w : std_logic_vector(DATA_SIZE-1 downto 0); + signal corr_data_w : std_logic_vector(DATA_SIZE-1 downto 0); + + signal single_err_w : std_logic; + signal double_err_w : std_logic; +begin + + gen_ENCODE : for i in HAMM_PARITY_SIZE-1 downto 0 generate + constant BITS_QT : integer := get_parity_qt(DATA_SIZE, i); + signal ecc_data_w : std_logic_vector(BITS_QT-1 downto 0); + begin + gen_DATA : for j in ecc_data_w'range generate + ecc_data_w(j) <= encoded_i(PARITY_POS(i, j)); + end generate; + parity_data_w(i) <= xor_reduce(ecc_data_w); + end generate; + + parity_diff_w <= parity_data_w xor encoded_i(DATA_SIZE+HAMM_PARITY_SIZE-1 downto DATA_SIZE); + + gen_CORRECTION_MASK : for i in corr_mask_w'range generate + corr_mask_w(i) <= nor_reduce(ERROR_BIT(i)(HAMM_PARITY_SIZE-1 downto 0) xor parity_diff_w); + end generate; + + corr_data_w <= (encoded_i(DATA_SIZE-1 downto 0) xor corr_mask_w) when correct_error_i = '1' else encoded_i(DATA_SIZE-1 downto 0); + + gen_DOUBLE_DETECT : if DETECT_DOUBLE generate + signal addit_parity_w : std_logic; + signal hamm_err_w : std_logic; + begin + -- calculate additional parity + addit_parity_w <= xor_reduce(encoded_i); + -- get 1 if hamming has detected an error + hamm_err_w <= or_reduce(parity_diff_w); + -- check double error + double_err_w <= (not addit_parity_w) and hamm_err_w; + -- set single error only when dont have double error + single_err_w <= hamm_err_w and not double_err_w; + end generate; + gen_NOT_DOUBLE_DETECT : if not DETECT_DOUBLE generate + -- set single error when hamming detects one + single_err_w <= or_reduce(parity_diff_w); + -- never detects two errors + double_err_w <= '0'; + end generate; + + -- assign error wires to output + single_err_o <= single_err_w; + double_err_o <= double_err_w; + + -- output corrected data only when has corrected single error. If not, output not-modified data + data_o <= corr_data_w when single_err_w = '1' else encoded_i(DATA_SIZE-1 downto 0); + +end architecture; diff --git a/hdl/ft_components/hamming_encoder.vhd b/hdl/ft_components/hamming_encoder.vhd new file mode 100644 index 0000000..d4583b2 --- /dev/null +++ b/hdl/ft_components/hamming_encoder.vhd @@ -0,0 +1,45 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_misc.all; + +library work; +use work.hamming_pkg.all; + +entity hamming_encoder is + generic ( + DATA_SIZE : integer := 32; -- 64(7), 32(6), 16(5), 8(4), 4(3) + DETECT_DOUBLE : boolean + ); + port ( + data_i : in std_logic_vector(DATA_SIZE-1 downto 0); + encoded_o : out std_logic_vector(DATA_SIZE+get_ecc_size(DATA_SIZE, DETECT_DOUBLE)-1 downto 0) + ); +end entity; + +architecture arch of hamming_encoder is + constant HAMM_PARITY_SIZE : integer := get_ecc_size(DATA_SIZE, FALSE); + constant TOTAL_PARITY_SIZE : integer := get_ecc_size(DATA_SIZE, DETECT_DOUBLE); + signal parity_data_w : std_logic_vector(TOTAL_PARITY_SIZE-1 downto 0); + signal encoded_w : std_logic_vector(DATA_SIZE+TOTAL_PARITY_SIZE-1 downto 0); +begin + + gen_ENCODE : for i in HAMM_PARITY_SIZE-1 downto 0 generate + constant BITS_QT : integer := get_parity_qt(DATA_SIZE, i); + signal ecc_data_w : std_logic_vector(BITS_QT-1 downto 0); + begin + gen_DATA : for j in ecc_data_w'range generate + ecc_data_w(j) <= data_i(PARITY_POS(i, j)); + end generate; + parity_data_w(i) <= xor_reduce(ecc_data_w); + end generate; + + gen_ADDITIONAL_PARITY : if DETECT_DOUBLE generate + signal hamm_encoded_w : std_logic_vector(DATA_SIZE+HAMM_PARITY_SIZE-1 downto 0); + begin + hamm_encoded_w <= parity_data_w(HAMM_PARITY_SIZE-1 downto 0) & data_i; + parity_data_w(TOTAL_PARITY_SIZE-1) <= xor_reduce(hamm_encoded_w); + end generate; + + encoded_w <= parity_data_w & data_i; + encoded_o <= encoded_w; +end architecture; diff --git a/hdl/ft_components/hamming_pkg.vhd b/hdl/ft_components/hamming_pkg.vhd new file mode 100644 index 0000000..b6991d4 --- /dev/null +++ b/hdl/ft_components/hamming_pkg.vhd @@ -0,0 +1,129 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_misc.all; + +package hamming_pkg is + + -- TYPES + type parity_pos_t is array (natural range <>, natural range <>) of integer; + type err_bit_t is array(natural range <>) of std_logic_vector(6 downto 0); + + -- CONSTANTS + constant PARITY_POS : parity_pos_t := ( + 0 => ( 0, 1, 3, 4, 6, 8, 10, 11, 13, 15, 17, 19, 21, 23, 25, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 57, 59, 61, 63), + 1 => ( 0, 2, 3, 5, 6, 9, 10, 12, 13, 16, 17, 20, 21, 24, 25, 27, 28, 31, 32, 35, 36, 39, 40, 43, 44, 47, 48, 51, 52, 55, 56, 58, 59, 62, 63), + 2 => ( 1, 2, 3, 7, 8, 9, 10, 14, 15, 16, 17, 22, 23, 24, 25, 29, 30, 31, 32, 37, 38, 39, 40, 45, 46, 47, 48, 53, 54, 55, 56, 60, 61, 62, 63), + 3 => ( 4, 5, 6, 7, 8, 9, 10, 18, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 49, 50, 51, 52, 53, 54, 55, 56, 64, -1, -1, -1), + 4 => (11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, -1, -1, -1), + 5 => (26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, -1, -1, -1, -1), + 6 => (57, 58, 59, 60, 61, 62, 63, 64, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1) + ); + + constant ERROR_BIT : err_bit_t := ( + 0 => "0000011", 1 => "0000101", 2 => "0000110", 3 => "0000111", 4 => "0001001", 5 => "0001010", + 6 => "0001011", 7 => "0001100", 8 => "0001101", 9 => "0001110", 10 => "0001111", 11 => "0010001", + 12 => "0010010", 13 => "0010011", 14 => "0010100", 15 => "0010101", 16 => "0010110", 17 => "0010111", + 18 => "0011000", 19 => "0011001", 20 => "0011010", 21 => "0011011", 22 => "0011100", 23 => "0011101", + 24 => "0011110", 25 => "0011111", 26 => "0100001", 27 => "0100010", 28 => "0100011", 29 => "0100100", + 30 => "0100101", 31 => "0100110", 32 => "0100111", 33 => "0101000", 34 => "0101001", 35 => "0101010", + 36 => "0101011", 37 => "0101100", 38 => "0101101", 39 => "0101110", 40 => "0101111", 41 => "0110000", + 42 => "0110001", 43 => "0110010", 44 => "0110011", 45 => "0110100", 46 => "0110101", 47 => "0110110", + 48 => "0110111", 49 => "0111000", 50 => "0111001", 51 => "0111010", 52 => "0111011", 53 => "0111100", + 54 => "0111101", 55 => "0111110", 56 => "0111111", 57 => "1000001", 58 => "1000010", 59 => "1000011", + 60 => "1000100", 61 => "1000101", 62 => "1000110", 63 => "1000111", 64 => "1001000" + ); + + -- FUNCTIONS -- runs only at synthesis + function get_parity_qt (data_size : in integer; pos : in integer) return integer; + function get_ecc_size (data_size : in integer; detect_double : in boolean) return integer; + function get_parity_data_result (data : in std_logic_vector; detect_double : in boolean) return std_logic_vector; + + -- COMPONENTS + component hamming_encoder + generic ( + DATA_SIZE : integer; + DETECT_DOUBLE : boolean + ); + port ( + data_i : in std_logic_vector(DATA_SIZE-1 downto 0); + encoded_o : out std_logic_vector(DATA_SIZE+get_ecc_size(DATA_SIZE, DETECT_DOUBLE)-1 downto 0) + ); + end component hamming_encoder; + + component hamming_decoder + generic ( + DATA_SIZE : integer := 32; + DETECT_DOUBLE : boolean + ); + port ( + encoded_i : in std_logic_vector(DATA_SIZE+get_ecc_size(DATA_SIZE, DETECT_DOUBLE)-1 downto 0); + correct_error_i : in std_logic; + single_err_o : out std_logic; + double_err_o : out std_logic; + data_o : out std_logic_vector(DATA_SIZE-1 downto 0) + ); + end component hamming_decoder; + + component hamming_register + generic ( + HAMMING_ENABLE : boolean; + RESET_VALUE : std_logic_vector + ); + port ( + correct_en_i : in std_logic; + write_en_i : in std_logic; + data_i : in std_logic_vector(31 downto 0); + rstn_i : in std_logic; + clk_i : in std_logic; + single_err_o : out std_logic; + double_err_o : out std_logic; + data_o : out std_logic_vector(31 downto 0) + ); + end component hamming_register; + +end package; + +package body hamming_pkg is + + function get_parity_qt (data_size : in integer; pos : in integer) return integer is + begin + for j in 0 to PARITY_POS'length(2)-1 loop + if PARITY_POS(pos, j) >= data_size or PARITY_POS(pos, j) = -1 then + return j; + end if; + end loop; + return PARITY_POS'length(2); + end function; + + function get_ecc_size (data_size : in integer; detect_double : in boolean) return integer is + begin + if detect_double then + return 1 + get_ecc_size(data_size, FALSE); + end if; + for j in 0 to PARITY_POS'length(1)-1 loop + if data_size < PARITY_POS(j, 0) then + return j; + end if; + end loop; + return PARITY_POS'length(1); + end function; + + function get_parity_data_result (data : in std_logic_vector; detect_double : in boolean) return std_logic_vector is + constant HAMM_PARITY_SIZE : integer := get_ecc_size(data'length, FALSE); + constant TOTAL_PARITY_SIZE : integer := get_ecc_size(data'length, detect_double); + variable par_data : std_logic_vector(HAMM_PARITY_SIZE-1 downto 0) := (others => '0'); + begin + for i in 0 to HAMM_PARITY_SIZE-1 loop + for j in 0 to get_parity_qt(data'length, i)-1 loop + if PARITY_POS(i, j) < data'length and PARITY_POS(i, j) /= -1 then + par_data(i) := par_data(i) xor data(PARITY_POS(i, j)); + end if; + end loop; + end loop; + if detect_double then + return xor_reduce(par_data) & par_data; + end if; + return par_data; + end function; + +end hamming_pkg; diff --git a/hdl/ft_components/hamming_register.vhd b/hdl/ft_components/hamming_register.vhd new file mode 100644 index 0000000..8114fd6 --- /dev/null +++ b/hdl/ft_components/hamming_register.vhd @@ -0,0 +1,101 @@ +library ieee; +use ieee.std_logic_1164.all; + +library work; +use work.hamming_pkg.hamming_encoder; +use work.hamming_pkg.hamming_decoder; +use work.hamming_pkg.get_parity_data_result; +use work.hamming_pkg.get_ecc_size; + +entity hamming_register is + generic ( + HAMMING_ENABLE : boolean; + RESET_VALUE : std_logic_vector(31 downto 0) := x"00000000" + ); + port ( + correct_en_i : in std_logic; + write_en_i : in std_logic; + data_i : in std_logic_vector(31 downto 0); + rstn_i : in std_logic; + clk_i : in std_logic; + single_err_o : out std_logic; + double_err_o : out std_logic; + data_o : out std_logic_vector(31 downto 0) + ); +end entity; + +architecture arch of hamming_register is +begin + + ----------------------------------------------------------------------------------------------- + ------------------------------------- HAMMING DISABLED ---------------------------------------- + ----------------------------------------------------------------------------------------------- + + g_NORMAL_REG : if not HAMMING_ENABLE generate + signal reg_r : std_logic_vector(31 downto 0); + begin + p_REG : process(clk_i, rstn_i) + begin + if rstn_i = '0' then + reg_r <= RESET_VALUE; + elsif rising_edge(clk_i) then + if write_en_i = '1' then + reg_r <= data_i; + end if; + end if; + end process; + single_err_o <= '0'; + double_err_o <= '0'; + data_o <= reg_r; + end generate; + + ----------------------------------------------------------------------------------------------- + -------------------------------------- HAMMING ENABLED ---------------------------------------- + ----------------------------------------------------------------------------------------------- + g_HAMMING_REG : if HAMMING_ENABLE generate + constant DETECT_DOUBLE : boolean := TRUE; + constant REG_DATA_WIDTH : integer := 32 + get_ecc_size(32, DETECT_DOUBLE); + constant RESET_VALUE_HAMMING : std_logic_vector(REG_DATA_WIDTH+31 downto 0) := get_parity_data_result(RESET_VALUE, DETECT_DOUBLE) & RESET_VALUE; + signal enc_w : std_logic_vector(REG_DATA_WIDTH-1 downto 0); + signal reg_r : std_logic_vector(REG_DATA_WIDTH-1 downto 0); + begin + + -- encode next register data + hamming_encoder_i : hamming_encoder + generic map ( + DATA_SIZE => 32, + DETECT_DOUBLE => DETECT_DOUBLE + ) + port map ( + data_i => data_i, + encoded_o => enc_w + ); + + -- create register + p_REG : process(clk_i, rstn_i) + begin + if rstn_i = '0' then + reg_r <= RESET_VALUE_HAMMING; + elsif rising_edge(clk_i) then + if write_en_i = '1' then + reg_r <= enc_w; + end if; + end if; + end process; + + -- decode the data + hamming_decoder_i : hamming_decoder + generic map ( + DATA_SIZE => 32, + DETECT_DOUBLE => DETECT_DOUBLE + ) + port map ( + encoded_i => reg_r, + correct_error_i => correct_en_i, + single_err_o => single_err_o, + double_err_o => double_err_o, + data_o => data_o + ); + end generate; + +end architecture; diff --git a/hdl/harv.vhd b/hdl/harv.vhd new file mode 100644 index 0000000..f5abf0e --- /dev/null +++ b/hdl/harv.vhd @@ -0,0 +1,396 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.harv_pkg.all; + +entity harv is + generic ( + PROGRAM_START_ADDR : std_logic_vector(31 downto 0) := x"00000000"; + TRAP_HANDLER_ADDR : std_logic_vector(31 downto 0) := x"00000000"; + TMR_CONTROL : boolean := FALSE; + TMR_ALU : boolean := FALSE; + HAMMING_REGFILE : boolean := FALSE; + HAMMING_PC : boolean := FALSE + ); + port ( + -- syncronization + rstn_i : in std_logic; + clk_i : in std_logic; + start_i : in std_logic; + -- reset cause + poweron_rstn_i : in std_logic; + wdt_rstn_i : in std_logic; + -- INSTRUCTION MEMORY + imem_instr_i : in std_logic_vector(31 downto 0); + imem_pc_o : out std_logic_vector(31 downto 0); + imem_req_o : out std_logic; + imem_gnt_i : in std_logic; + imem_err_i : in std_logic; + -- DATA MEMORY + hard_dmem_o : out std_logic; + dmem_data_i : in std_logic_vector(31 downto 0); + dmem_req_o : out std_logic; + dmem_wren_o : out std_logic; + dmem_gnt_i : in std_logic; + dmem_outofrange_i : in std_logic; + dmem_sbu_i : in std_logic; + dmem_dbu_i : in std_logic; + dmem_byte_en_o : out std_logic_vector(1 downto 0); + dmem_usgn_dat_o : out std_logic; + dmem_data_o : out std_logic_vector(31 downto 0); + dmem_addr_o : out std_logic_vector(31 downto 0) + ); +end entity; + +architecture arch of harv is + signal clk_w : std_logic; + ---------Instruction Fetch --------- + signal if_pc_w : std_logic_vector(31 downto 0); + signal if_pc_4_w : std_logic_vector(31 downto 0); + signal update_pc_w : std_logic; + signal trap_w : std_logic; + + --------- Instruction Decode -------- + signal opcode_w : std_logic_vector( 6 downto 0); + signal funct3_w : std_logic_vector( 2 downto 0); + signal funct7_w : std_logic_vector( 6 downto 0); + signal funct12_w : std_logic_vector(11 downto 0); + signal rd_w : std_logic_vector( 4 downto 0); + signal rs1_w : std_logic_vector( 4 downto 0); + signal rs2_w : std_logic_vector( 4 downto 0); + signal imm_shamt_w : std_logic_vector( 4 downto 0); + signal imm_up_w : std_logic_vector(19 downto 0); + signal imm_upj_w : std_logic_vector(20 downto 0); + signal imm_branch_w : std_logic_vector(12 downto 0); + signal imm_store_w : std_logic_vector(11 downto 0); + signal imm_i_w : std_logic_vector(11 downto 0); + -- Immediate value + signal imm_sel_w : std_logic_vector(3 downto 0); + signal imm_w : std_logic_vector(31 downto 0); + -------------- CONTROL ------------- + signal ctl_aluop_w : std_logic_vector(ALUOP_SIZE-1 downto 0); + signal ctl_alusrc_imm_w : std_logic; + signal ctl_imm_shamt_w : std_logic; + signal ctl_imm_up_w : std_logic; + signal ctl_regwr_w : std_logic; + signal ctl_inv_branch_w : std_logic; + signal ctl_branch_w : std_logic; + signal ctl_jump_w : std_logic; + signal ctl_jalr_w : std_logic; + signal ctl_ecall_w : std_logic; + signal ctl_memrd_w : std_logic; + signal ctl_memwr_w : std_logic; + signal ctl_byte_en_w : std_logic_vector(1 downto 0); + signal ctl_mem_usgn_w : std_logic; + signal ctl_load_upimm_w : std_logic; + signal ctl_auipc_w : std_logic; + signal ctl_csr_enable_w : std_logic; + signal ctl_csr_source_imm_w : std_logic; + signal ctl_csr_maskop_w : std_logic; + signal ctl_csr_clearop_w : std_logic; + signal instr_w : std_logic_vector(31 downto 0); + ------------- REGFILE ------------- + signal data_wr_w : std_logic_vector(31 downto 0); + signal reg_data1_w : std_logic_vector(31 downto 0); + signal reg_data2_w : std_logic_vector(31 downto 0); + -------------- ALU ----------------- + signal alu_data1_w : std_logic_vector(31 downto 0); + signal alu_data2_w : std_logic_vector(31 downto 0); + signal alu_zero_w : std_logic; + signal alu_data_w : std_logic_vector(31 downto 0); + --------------- CSR ----------------- + signal csr_rdata_w : std_logic_vector(31 downto 0); + signal csr_ucause_w : std_logic_vector(31 downto 0); + signal hard_pc_w : std_logic; + signal hard_regfile_w : std_logic; + signal hard_control_w : std_logic; + signal hard_alu_w : std_logic; + ----------- ERROR wires ------------- + -- signal reg1_cen_w : std_logic; + signal reg1_sbu_w : std_logic; + signal reg1_dbu_w : std_logic; + -- signal reg2_cen_w : std_logic; + signal reg2_sbu_w : std_logic; + signal reg2_dbu_w : std_logic; + -- signal pc_cen_w : std_logic; + signal pc_sbu_w : std_logic; + signal pc_dbu_w : std_logic; + + signal control_err_w : std_logic; + signal alu_err_w : std_logic; +begin + + clk_w <= clk_i; + + instr_fetch_i : instr_fetch + generic map ( + PROGRAM_START_ADDR => PROGRAM_START_ADDR, + TRAP_HANDLER_ADDR => TRAP_HANDLER_ADDR, + HAMMING_PC => HAMMING_PC + ) + port map ( + branch_imm_i => imm_branch_w, + jump_imm_i => alu_data_w, + inv_branch_i => ctl_inv_branch_w, + branch_i => ctl_branch_w, + zero_i => alu_zero_w, + jump_i => ctl_jump_w, + ecall_i => ctl_ecall_w, + correct_error_i => hard_pc_w, + instr_gnt_i => imem_gnt_i, + instr_i => imem_instr_i, + rstn_i => rstn_i, + clk_i => clk_w, + update_pc_i => update_pc_w, + trap_i => trap_w, + instr_o => instr_w, + sbu_o => pc_sbu_w, + dbu_o => pc_dbu_w, + pc_o => if_pc_w, + pc_4_o => if_pc_4_w + ); + imem_pc_o <= if_pc_w; + + opcode_w <= instr_w( 6 downto 0); + funct3_w <= instr_w(14 downto 12); + funct7_w <= instr_w(31 downto 25); + funct12_w <= instr_w(31 downto 20); + rd_w <= instr_w(11 downto 7); + rs1_w <= instr_w(19 downto 15); + rs2_w <= instr_w(24 downto 20); + imm_shamt_w <= instr_w(24 downto 20); + imm_up_w <= instr_w(31 downto 12); + imm_upj_w <= instr_w(31) & instr_w(19 downto 12) & instr_w(20) & instr_w(30 downto 21) & '0'; + imm_branch_w <= instr_w(31) & instr_w(7) & instr_w(30 downto 25) & instr_w(11 downto 8) & '0'; + imm_store_w <= instr_w(31 downto 25) & instr_w(11 downto 7); + imm_i_w <= instr_w(31 downto 20); + + gen_ft_control : if TMR_CONTROL generate + control_i : control_tmr + port map ( + start_i => start_i, + imem_gnt_i => imem_gnt_i, + imem_err_i => imem_err_i, + dmem_gnt_i => dmem_gnt_i, + dmem_outofrange_i => dmem_outofrange_i, + dmem_sbu_i => dmem_sbu_i and dmem_gnt_i and not ctl_memwr_w, + dmem_dbu_i => dmem_dbu_i and dmem_gnt_i and not ctl_memwr_w, + opcode_i => opcode_w, + funct3_i => funct3_w, + funct7_i => funct7_w, + funct12_i => funct12_w, + rstn_i => rstn_i, + clk_i => clk_i, + imem_req_o => imem_req_o, + dmem_req_o => dmem_req_o, + update_pc_o => update_pc_w, + trap_o => trap_w, + aluop_o => ctl_aluop_w, + alusrc_imm_o => ctl_alusrc_imm_w, + imm_shamt_o => ctl_imm_shamt_w, + imm_up_o => ctl_imm_up_w, + regwr_o => ctl_regwr_w, + inv_branch_o => ctl_inv_branch_w, + branch_o => ctl_branch_w, + jump_o => ctl_jump_w, + jalr_o => ctl_jalr_w, + ecall_o => ctl_ecall_w, + memrd_o => ctl_memrd_w, + memwr_o => ctl_memwr_w, + byte_en_o => ctl_byte_en_w, + mem_usgn_o => ctl_mem_usgn_w, + load_upimm_o => ctl_load_upimm_w, + auipc_o => ctl_auipc_w, + csr_enable_o => ctl_csr_enable_w, + csr_source_imm_o => ctl_csr_source_imm_w, + csr_maskop_o => ctl_csr_maskop_w, + csr_clearop_o => ctl_csr_clearop_w, + correct_error_i => hard_control_w, + error_o => control_err_w + ); + end generate; + gen_normal_control : if not TMR_CONTROL generate + control_i : control + port map ( + -- processor status + start_i => start_i, + imem_gnt_i => imem_gnt_i, + imem_err_i => imem_err_i, + dmem_gnt_i => dmem_gnt_i, + dmem_outofrange_i => dmem_outofrange_i, + dmem_sbu_i => dmem_sbu_i, + dmem_dbu_i => dmem_dbu_i, + + -- instruction decode + opcode_i => opcode_w, + funct3_i => funct3_w, + funct7_i => funct7_w, + funct12_i => funct12_w, + + rstn_i => rstn_i, + clk_i => clk_i, + + -- processor status + imem_req_o => imem_req_o, + dmem_req_o => dmem_req_o, + update_pc_o => update_pc_w, + trap_o => trap_w, + + -- instruction decode + aluop_o => ctl_aluop_w, + alusrc_imm_o => ctl_alusrc_imm_w, + imm_shamt_o => ctl_imm_shamt_w, + imm_up_o => ctl_imm_up_w, + regwr_o => ctl_regwr_w, + inv_branch_o => ctl_inv_branch_w, + branch_o => ctl_branch_w, + jump_o => ctl_jump_w, + jalr_o => ctl_jalr_w, + ecall_o => ctl_ecall_w, + memrd_o => ctl_memrd_w, + memwr_o => ctl_memwr_w, + byte_en_o => ctl_byte_en_w, + mem_usgn_o => ctl_mem_usgn_w, + load_upimm_o => ctl_load_upimm_w, + auipc_o => ctl_auipc_w, + csr_enable_o => ctl_csr_enable_w, + csr_source_imm_o => ctl_csr_source_imm_w, + csr_maskop_o => ctl_csr_maskop_w, + csr_clearop_o => ctl_csr_clearop_w + ); + end generate; + + data_wr_w <= dmem_data_i when ctl_memrd_w = '1' else + imm_w when ctl_load_upimm_w = '1' else + if_pc_4_w when ctl_jump_w = '1' else + csr_rdata_w when ctl_csr_enable_w = '1' else + alu_data_w; + + regfile_i : regfile + generic map ( + HAMMING_ENABLE => HAMMING_REGFILE + ) + port map ( + data_i => data_wr_w, + wren_i => ctl_regwr_w, + rd_i => rd_w, + rs1_i => rs1_w, + rs2_i => rs2_w, + correct_en_i => hard_regfile_w, + clk_i => clk_w, + sbu1_o => reg1_sbu_w, + dbu1_o => reg1_dbu_w, + data1_o => reg_data1_w, + sbu2_o => reg2_sbu_w, + dbu2_o => reg2_dbu_w, + data2_o => reg_data2_w + ); + + imm_sel_w <= ctl_imm_shamt_w & ctl_imm_up_w & ctl_memwr_w & (ctl_jump_w and not ctl_jalr_w); + + with imm_sel_w select imm_w <= + std_logic_vector(resize(unsigned(imm_shamt_w), 32)) when "1000", -- ctl_imm_shamt_w = '1' else + std_logic_vector(shift_left(resize(signed(imm_up_w), 32), 12)) when "0100", -- ctl_imm_up_w = '1' else + std_logic_vector(resize(signed(imm_store_w), 32)) when "0010", -- ctl_memwr_w = '1' else + std_logic_vector(resize(signed(imm_upj_w), 32)) when "0001", -- (ctl_jump_w and not ctl_jalr_w) = '1' else + std_logic_vector(resize(signed(imm_i_w), 32)) when others; + + alu_data1_w <= if_pc_w when (ctl_auipc_w or (ctl_jump_w and not ctl_jalr_w)) = '1' else + reg_data1_w; + alu_data2_w <= imm_w when ctl_alusrc_imm_w = '1' else reg_data2_w; + + gen_ft_alu : if TMR_ALU generate + alu_i : alu_tmr + port map ( + data1_i => alu_data1_w, + data2_i => alu_data2_w, + operation_i => ctl_aluop_w, + zero_o => alu_zero_w, + data_o => alu_data_w, + correct_error_i => hard_alu_w, + error_o => alu_err_w + ); + end generate; + gen_normal_alu : if not TMR_ALU generate + alu_i : alu + port map ( + data1_i => alu_data1_w, + data2_i => alu_data2_w, + operation_i => ctl_aluop_w, + zero_o => alu_zero_w, + data_o => alu_data_w + ); + end generate; + + ---------- CSR registers --------- + csr_ucause_w <= x"00000010" when dmem_sbu_i = '1' else -- SBU + x"00000020" when dmem_dbu_i = '1' else -- DBU + x"00000007" when ctl_memwr_w = '1' else -- store address fault + x"00000005"; -- load address fault + csr_i : csr + generic map ( + TMR_CONTROL => TMR_CONTROL, + TMR_ALU => TMR_ALU, + HAMMING_REGFILE => HAMMING_REGFILE, + HAMMING_PC => HAMMING_PC + ) + port map ( + -- sync + rstn_i => rstn_i, + clk_i => clk_i, + -- access interface + addr_i => imm_i_w, + data_o => csr_rdata_w, + rs1_data_i => reg_data1_w, + imm_data_i => rs1_w, + wren_i => ctl_csr_enable_w, + source_imm_i => ctl_csr_source_imm_w, + csr_maskop_i => ctl_csr_maskop_w, + csr_clearop_i => ctl_csr_clearop_w, + -- trap handling + trap_i => trap_w, + uscratch_i => alu_data_w, + uepc_i => if_pc_w, + ucause_i => csr_ucause_w, + utval_i => reg_data2_w, + uip_i => x"00000000", + -- errors + reg1_cen_i => update_pc_w, + reg1_sbu_i => reg1_sbu_w, + reg1_dbu_i => reg1_dbu_w, + reg2_cen_i => update_pc_w, + reg2_sbu_i => reg2_sbu_w, + reg2_dbu_i => reg2_dbu_w, + pc_cen_i => update_pc_w, + pc_sbu_i => pc_sbu_w, + pc_dbu_i => pc_dbu_w, + dmem_cen_i => dmem_gnt_i and not ctl_memwr_w, + dmem_sbu_i => dmem_sbu_i, + dmem_dbu_i => dmem_dbu_i, + control_cen_i => '1', + control_err_i => control_err_w, + alu_cen_i => dmem_gnt_i or update_pc_w or ctl_regwr_w, + alu_err_i => alu_err_w, + -- hardening + hard_pc_o => hard_pc_w, + hard_regfile_o => hard_regfile_w, + hard_dmem_o => hard_dmem_o, + hard_control_o => hard_control_w, + hard_alu_o => hard_alu_w, + -- resets + poweron_rstn_i => poweron_rstn_i, + wdt_rstn_i => wdt_rstn_i + ); + + -------- DATA MEMORY -------- + -- output signals + -- dmem_req_o is set by the control unit + dmem_wren_o <= ctl_memwr_w; + dmem_byte_en_o <= ctl_byte_en_w; + dmem_usgn_dat_o <= ctl_mem_usgn_w; + dmem_data_o <= reg_data2_w; + dmem_addr_o <= alu_data_w; + +end architecture; diff --git a/hdl/harv_pkg.vhd b/hdl/harv_pkg.vhd new file mode 100644 index 0000000..fd5f63d --- /dev/null +++ b/hdl/harv_pkg.vhd @@ -0,0 +1,265 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package harv_pkg is + + ----- CONSTANTS ------- + constant ALUOP_SIZE : integer := 4; + constant ALU_ADD_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "0000"; + constant ALU_SUB_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "1000"; + constant ALU_SLL_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "0001"; + constant ALU_SLT_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "0010"; + constant ALU_SLTU_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "0011"; + constant ALU_XOR_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "0100"; + constant ALU_SRL_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "0101"; + constant ALU_SRA_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "1101"; + constant ALU_OR_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "0110"; + constant ALU_AND_OP : std_logic_vector(ALUOP_SIZE-1 downto 0) := "0111"; + + ------- COMPONENTS ----- + component harv + generic ( + PROGRAM_START_ADDR : std_logic_vector(31 downto 0); + TRAP_HANDLER_ADDR : std_logic_vector(31 downto 0); + TMR_CONTROL : boolean; + TMR_ALU : boolean; + HAMMING_REGFILE : boolean; + HAMMING_PC : boolean + ); + port ( + rstn_i : in std_logic; + clk_i : in std_logic; + start_i : in std_logic; + poweron_rstn_i : in std_logic; + wdt_rstn_i : in std_logic; + imem_instr_i : in std_logic_vector(31 downto 0); + imem_pc_o : out std_logic_vector(31 downto 0); + imem_req_o : out std_logic; + imem_gnt_i : in std_logic; + imem_err_i : in std_logic; + hard_dmem_o : out std_logic; + dmem_data_i : in std_logic_vector(31 downto 0); + dmem_req_o : out std_logic; + dmem_wren_o : out std_logic; + dmem_gnt_i : in std_logic; + dmem_outofrange_i : in std_logic; + dmem_sbu_i : in std_logic; + dmem_dbu_i : in std_logic; + dmem_byte_en_o : out std_logic_vector(1 downto 0); + dmem_usgn_dat_o : out std_logic; + dmem_data_o : out std_logic_vector(31 downto 0); + dmem_addr_o : out std_logic_vector(31 downto 0) + ); + end component harv; + + component control + port ( + imem_gnt_i : in std_logic; + imem_err_i : in std_logic; + dmem_gnt_i : in std_logic; + dmem_outofrange_i : in std_logic; + dmem_sbu_i : in std_logic; + dmem_dbu_i : in std_logic; + opcode_i : in std_logic_vector(6 downto 0); + funct3_i : in std_logic_vector(2 downto 0); + funct7_i : in std_logic_vector(6 downto 0); + funct12_i : in std_logic_vector(11 downto 0); + rstn_i : in std_logic; + clk_i : in std_logic; + start_i : in std_logic; + imem_req_o : out std_logic; + dmem_req_o : out std_logic; + update_pc_o : out std_logic; + trap_o : out std_logic; + aluop_o : out std_logic_vector(ALUOP_SIZE-1 downto 0); + alusrc_imm_o : out std_logic; + imm_shamt_o : out std_logic; + imm_up_o : out std_logic; + regwr_o : out std_logic; + inv_branch_o : out std_logic; + branch_o : out std_logic; + jump_o : out std_logic; + jalr_o : out std_logic; + ecall_o : out std_logic; + memrd_o : out std_logic; + memwr_o : out std_logic; + byte_en_o : out std_logic_vector(1 downto 0); + mem_usgn_o : out std_logic; + load_upimm_o : out std_logic; + auipc_o : out std_logic; + csr_enable_o : out std_logic; + csr_source_imm_o : out std_logic; + csr_maskop_o : out std_logic; + csr_clearop_o : out std_logic + ); + end component control; + + component instr_fetch + generic ( + PROGRAM_START_ADDR : std_logic_vector; + TRAP_HANDLER_ADDR : std_logic_vector; + HAMMING_PC : boolean + ); + port ( + branch_imm_i : in std_logic_vector(12 downto 0); + jump_imm_i : in std_logic_vector(31 downto 0); + inv_branch_i : in std_logic; + branch_i : in std_logic; + zero_i : in std_logic; + jump_i : in std_logic; + ecall_i : in std_logic; + correct_error_i : in std_logic; + instr_gnt_i : in std_logic; + instr_i : in std_logic_vector(31 downto 0); + rstn_i : in std_logic; + clk_i : in std_logic; + update_pc_i : in std_logic; + trap_i : in std_logic; + instr_o : out std_logic_vector(31 downto 0); + sbu_o : out std_logic; + dbu_o : out std_logic; + pc_o : out std_logic_vector(31 downto 0); + pc_4_o : out std_logic_vector(31 downto 0) + ); + end component instr_fetch; + + component regfile + generic ( + HAMMING_ENABLE : boolean + ); + port ( + data_i : in std_logic_vector(31 downto 0); + wren_i : in std_logic; + rd_i : in std_logic_vector(4 downto 0); + rs1_i : in std_logic_vector(4 downto 0); + rs2_i : in std_logic_vector(4 downto 0); + correct_en_i : in std_logic; + clk_i : in std_logic; + sbu1_o : out std_logic; + dbu1_o : out std_logic; + data1_o : out std_logic_vector(31 downto 0); + sbu2_o : out std_logic; + dbu2_o : out std_logic; + data2_o : out std_logic_vector(31 downto 0) + ); + end component regfile; + + component alu + port ( + data1_i : in std_logic_vector(31 downto 0); + data2_i : in std_logic_vector(31 downto 0); + operation_i : in std_logic_vector(ALUOP_SIZE-1 downto 0); + zero_o : out std_logic; + data_o : out std_logic_vector(31 downto 0) + ); + end component alu; + + component csr + generic ( + TMR_CONTROL : boolean; + TMR_ALU : boolean; + HAMMING_REGFILE : boolean; + HAMMING_PC : boolean + ); + port ( + rstn_i : in std_logic; + clk_i : in std_logic; + addr_i : in std_logic_vector(11 downto 0); + data_o : out std_logic_vector(31 downto 0); + rs1_data_i : in std_logic_vector(31 downto 0); + imm_data_i : in std_logic_vector(4 downto 0); + wren_i : in std_logic; + source_imm_i : in std_logic; + csr_maskop_i : in std_logic; + csr_clearop_i : in std_logic; + trap_i : in std_logic; + uscratch_i : in std_logic_vector(31 downto 0); + uepc_i : in std_logic_vector(31 downto 0); + ucause_i : in std_logic_vector(31 downto 0); + utval_i : in std_logic_vector(31 downto 0); + uip_i : in std_logic_vector(31 downto 0); + reg1_cen_i : in std_logic; + reg1_sbu_i : in std_logic; + reg1_dbu_i : in std_logic; + reg2_cen_i : in std_logic; + reg2_sbu_i : in std_logic; + reg2_dbu_i : in std_logic; + pc_cen_i : in std_logic; + pc_sbu_i : in std_logic; + pc_dbu_i : in std_logic; + dmem_cen_i : in std_logic; + dmem_sbu_i : in std_logic; + dmem_dbu_i : in std_logic; + control_cen_i : in std_logic; + control_err_i : in std_logic; + alu_cen_i : in std_logic; + alu_err_i : in std_logic; + hard_pc_o : out std_logic; + hard_regfile_o : out std_logic; + hard_dmem_o : out std_logic; + hard_control_o : out std_logic; + hard_alu_o : out std_logic; + poweron_rstn_i : in std_logic; + wdt_rstn_i : in std_logic + ); + end component csr; + + ------------- FAULT TOLERANT COMPONENTS -------------------- + component control_tmr + port ( + imem_gnt_i : in std_logic; + imem_err_i : in std_logic; + dmem_gnt_i : in std_logic; + dmem_outofrange_i : in std_logic; + dmem_sbu_i : in std_logic; + dmem_dbu_i : in std_logic; + opcode_i : in std_logic_vector(6 downto 0); + funct3_i : in std_logic_vector(2 downto 0); + funct7_i : in std_logic_vector(6 downto 0); + funct12_i : in std_logic_vector(11 downto 0); + correct_error_i : in std_logic; + rstn_i : in std_logic; + clk_i : in std_logic; + start_i : in std_logic; + imem_req_o : out std_logic; + dmem_req_o : out std_logic; + update_pc_o : out std_logic; + trap_o : out std_logic; + error_o : out std_logic; + aluop_o : out std_logic_vector(ALUOP_SIZE-1 downto 0); + alusrc_imm_o : out std_logic; + imm_shamt_o : out std_logic; + imm_up_o : out std_logic; + regwr_o : out std_logic; + inv_branch_o : out std_logic; + branch_o : out std_logic; + jump_o : out std_logic; + jalr_o : out std_logic; + ecall_o : out std_logic; + memrd_o : out std_logic; + memwr_o : out std_logic; + byte_en_o : out std_logic_vector(1 downto 0); + mem_usgn_o : out std_logic; + load_upimm_o : out std_logic; + auipc_o : out std_logic; + csr_enable_o : out std_logic; + csr_source_imm_o : out std_logic; + csr_maskop_o : out std_logic; + csr_clearop_o : out std_logic + ); + end component control_tmr; + + component alu_tmr + port ( + data1_i : in std_logic_vector(31 downto 0); + data2_i : in std_logic_vector(31 downto 0); + operation_i : in std_logic_vector(ALUOP_SIZE-1 downto 0); + correct_error_i : in std_logic; + error_o : out std_logic; + zero_o : out std_logic; + data_o : out std_logic_vector(31 downto 0) + ); + end component alu_tmr; + +end package; diff --git a/hdl/instr_fetch.vhd b/hdl/instr_fetch.vhd new file mode 100644 index 0000000..09e1fe4 --- /dev/null +++ b/hdl/instr_fetch.vhd @@ -0,0 +1,91 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.hamming_pkg.hamming_register; + +entity instr_fetch is + generic ( + PROGRAM_START_ADDR : std_logic_vector(31 downto 0); + TRAP_HANDLER_ADDR : std_logic_vector(31 downto 0); + HAMMING_PC : boolean + ); + port ( + -- input ports + branch_imm_i : in std_logic_vector(12 downto 0); + jump_imm_i : in std_logic_vector(31 downto 0); + inv_branch_i : in std_logic; + branch_i : in std_logic; + zero_i : in std_logic; + jump_i : in std_logic; + ecall_i : in std_logic; + correct_error_i : in std_logic; + -- instruction data + instr_gnt_i : in std_logic; + instr_i : in std_logic_vector(31 downto 0); + -- sync + rstn_i : in std_logic; + clk_i : in std_logic; + update_pc_i : in std_logic; + trap_i : in std_logic; + -- output ports + instr_o : out std_logic_vector(31 downto 0); + sbu_o : out std_logic; + dbu_o : out std_logic; + pc_o : out std_logic_vector(31 downto 0); + pc_4_o : out std_logic_vector(31 downto 0) + ); +end entity; + +architecture arch of instr_fetch is + signal pc_par_w : std_logic_vector(31 downto 0); + signal pc_adder_w : std_logic_vector(31 downto 0); + signal next_pc_w : std_logic_vector(31 downto 0); + signal pc_w : std_logic_vector(31 downto 0); +begin + -- calculate (PC + 4) or (PC + branch_eq) + pc_par_w <= std_logic_vector(resize(signed(branch_imm_i), 32)) when (branch_i and (zero_i xor inv_branch_i)) = '1' else x"00000004"; + pc_adder_w <= std_logic_vector(signed(pc_w) + signed(pc_par_w)); + pc_4_o <= pc_adder_w; + + -- define the next PC address + next_pc_w <= TRAP_HANDLER_ADDR when trap_i = '1' else + jump_imm_i when jump_i = '1' else + pc_adder_w; + -- set PC output + pc_o <= pc_w; + + register_pc_i : hamming_register + generic map ( + HAMMING_ENABLE => HAMMING_PC, + RESET_VALUE => PROGRAM_START_ADDR + ) + port map ( + correct_en_i => correct_error_i, + write_en_i => update_pc_i, + data_i => next_pc_w, + rstn_i => rstn_i, + clk_i => clk_i, + single_err_o => sbu_o, + double_err_o => dbu_o, + data_o => pc_w + ); + + register_instr_i : hamming_register + generic map ( + HAMMING_ENABLE => HAMMING_PC, + RESET_VALUE => (31 downto 0 => '0') + ) + port map ( + correct_en_i => correct_error_i, + write_en_i => instr_gnt_i, + data_i => instr_i, + rstn_i => rstn_i, + clk_i => clk_i, + single_err_o => open, + double_err_o => open, + data_o => instr_o + ); + +end architecture; diff --git a/hdl/regfile.vhd b/hdl/regfile.vhd new file mode 100644 index 0000000..541198e --- /dev/null +++ b/hdl/regfile.vhd @@ -0,0 +1,142 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; +use ieee.std_logic_misc.all; + +library work; +use work.hamming_pkg.all; + +entity regfile is + generic ( + HAMMING_ENABLE : boolean + ); + port ( + -- input ports + data_i : in std_logic_vector(31 downto 0); + wren_i : in std_logic; + rd_i : in std_logic_vector(4 downto 0); + rs1_i : in std_logic_vector(4 downto 0); + rs2_i : in std_logic_vector(4 downto 0); + correct_en_i : in std_logic; + -- synchronization + clk_i : in std_logic; + -- output ports + sbu1_o : out std_logic; + dbu1_o : out std_logic; + data1_o : out std_logic_vector(31 downto 0); + sbu2_o : out std_logic; + dbu2_o : out std_logic; + data2_o : out std_logic_vector(31 downto 0) + ); +end entity; + +architecture arch of regfile is +begin + + ----------------------------------------------------------------------------------------------- + ------------------------------------- HAMMING DISABLED ---------------------------------------- + ----------------------------------------------------------------------------------------------- + + g_NORMAL : if not HAMMING_ENABLE generate + type regfile_t is array(natural range <>) of std_logic_vector(31 downto 0); + signal regfile_r : regfile_t(31 downto 1); + signal regfile_w : regfile_t(31 downto 0); + + signal rs1_w : std_logic_vector(4 downto 0); + signal rs2_w : std_logic_vector(4 downto 0); + begin + -- WRITE REGISTERS + p_WR : process(clk_i) + begin + if rising_edge(clk_i) then + if wren_i = '1' and rd_i /= "00000" and rd_i /= "UUUUU" then + regfile_r(to_integer(unsigned(rd_i))) <= data_i; + end if; + end if; + end process; + + regfile_w(31 downto 1) <= regfile_r; + regfile_w(0) <= (others => '0'); + + -- READ REGISTERS + sbu1_o <= '0'; + dbu1_o <= '0'; + data1_o <= regfile_w(to_integer(unsigned(rs1_i))); + + sbu2_o <= '0'; + dbu2_o <= '0'; + data2_o <= regfile_w(to_integer(unsigned(rs2_i))); + end generate; + + ----------------------------------------------------------------------------------------------- + -------------------------------------- HAMMING ENABLED ---------------------------------------- + ----------------------------------------------------------------------------------------------- + + g_HAMMING : if HAMMING_ENABLE generate + constant DETECT_DOUBLE : boolean := TRUE; + constant PARITY_BITS_QT : integer := get_ecc_size(32, DETECT_DOUBLE); + type regfile_hamming_t is array(natural range <>) of std_logic_vector(31+PARITY_BITS_QT downto 0); + + signal regfile_r : regfile_hamming_t(31 downto 1); + signal regfile_w : regfile_hamming_t(31 downto 0); + + signal data_wr_enc_w : std_logic_vector(PARITY_BITS_QT+31 downto 0); + signal data_s1_enc_w : std_logic_vector(PARITY_BITS_QT+31 downto 0); + signal data_s2_enc_w : std_logic_vector(PARITY_BITS_QT+31 downto 0); + begin + hamming_encoder_i : hamming_encoder + generic map ( + DATA_SIZE => 32, + DETECT_DOUBLE => DETECT_DOUBLE + ) + port map ( + data_i => data_i, + encoded_o => data_wr_enc_w + ); + + -- WRITE REGISTER + p_WR : process(clk_i, wren_i) + begin + if rising_edge(clk_i) then + if wren_i = '1' and rd_i /= "00000" then + regfile_r(to_integer(unsigned(rd_i))) <= data_wr_enc_w; + end if; + end if; + end process; + + -- READ REGISTERS + regfile_w(31 downto 1) <= regfile_r; + regfile_w(0) <= (others => '0'); + + data_s1_enc_w <= regfile_w(to_integer(unsigned(rs1_i))); + data_s2_enc_w <= regfile_w(to_integer(unsigned(rs2_i))); + + hamming_decoder_data1_i : hamming_decoder + generic map ( + DATA_SIZE => 32, + DETECT_DOUBLE => DETECT_DOUBLE + ) + port map ( + encoded_i => data_s1_enc_w, + correct_error_i => correct_en_i, + single_err_o => sbu1_o, + double_err_o => dbu1_o, + data_o => data1_o + ); + + hamming_decoder_data2_i : hamming_decoder + generic map ( + DATA_SIZE => 32, + DETECT_DOUBLE => DETECT_DOUBLE + ) + port map ( + encoded_i => data_s2_enc_w, + correct_error_i => correct_en_i, + single_err_o => sbu2_o, + double_err_o => dbu2_o, + data_o => data2_o + ); + end generate; + + +end architecture; diff --git a/images/rars-data-export.png b/images/rars-data-export.png new file mode 100644 index 0000000000000000000000000000000000000000..3d71f51b4b18919dad3eb6bea2a1b6d994bee4fc GIT binary patch literal 9362 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 DDdcZJ literal 0 HcmV?d00001 diff --git a/images/rars-memory-configuration.png b/images/rars-memory-configuration.png new file mode 100644 index 0000000000000000000000000000000000000000..9d6e8830dad4c28d95ad101b0b7be30c089df3da GIT binary patch literal 27228 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 literal 0 HcmV?d00001 diff --git a/images/rars-text-export.png b/images/rars-text-export.png new file mode 100644 index 0000000000000000000000000000000000000000..3a64da42f4cbcad83d51e07faadd98b7806ae79f GIT binary patch literal 8894 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 literal 0 HcmV?d00001 diff --git a/script/project.tcl b/script/project.tcl new file mode 100644 index 0000000..2e0caee --- /dev/null +++ b/script/project.tcl @@ -0,0 +1,311 @@ +#***************************************************************************************** +# Vivado (TM) v2020.2 (64-bit) +# +# project.tcl: Tcl script for re-creating project 'harv' +# +# Generated by Vivado on Tue Jun 15 18:52:54 CEST 2021 +# IP Build 3064653 on Wed Nov 18 14:17:31 MST 2020 +# +# This file contains the Vivado Tcl commands for re-creating the project to the state* +# when this script was generated. In order to re-create the project, please source this +# file in the Vivado Tcl Shell. +# +# * Note that the runs in the created project will be configured the same way as the +# original project, however they will not be launched automatically. To regenerate the +# run results please launch the synthesis/implementation runs as needed. +# +#***************************************************************************************** +# NOTE: In order to use this script for source control purposes, please make sure that the +# following files are added to the source control system:- +# +# 1. This project restoration tcl script (project.tcl) that was generated. +# +# 2. The following source(s) files that were local or imported into the original project. +# (Please see the '$orig_proj_dir' and '$origin_dir' variable setting below at the start of the script) +# +# "xilinx/sim_from_dump_behav.wcfg" +# +# 3. The following remote source files that were added to the original project:- +# +# "hdl/harv_pkg.vhd" +# "hdl/alu.vhd" +# "hdl/ft_components/alu_tmr.vhd" +# "hdl/control.vhd" +# "hdl/ft_components/control_tmr.vhd" +# "hdl/csr.vhd" +# "hdl/ft_components/hamming_pkg.vhd" +# "hdl/ft_components/hamming_decoder.vhd" +# "hdl/ft_components/hamming_encoder.vhd" +# "hdl/ft_components/hamming_register.vhd" +# "hdl/instr_fetch.vhd" +# "hdl/regfile.vhd" +# "hdl/harv.vhd" +# "sim/sim_from_dump.vhd" +# +#***************************************************************************************** + +# Check file required for this script exists +proc checkRequiredFiles { origin_dir} { + set status true + set files [list \ + "xilinx/sim_from_dump_behav.wcfg" \ + ] + foreach ifile $files { + if { ![file isfile $ifile] } { + puts " Could not find local file $ifile " + set status false + } + } + + set files [list \ + "hdl/harv_pkg.vhd" \ + "hdl/alu.vhd" \ + "hdl/ft_components/alu_tmr.vhd" \ + "hdl/control.vhd" \ + "hdl/ft_components/control_tmr.vhd" \ + "hdl/csr.vhd" \ + "hdl/ft_components/hamming_pkg.vhd" \ + "hdl/ft_components/hamming_decoder.vhd" \ + "hdl/ft_components/hamming_encoder.vhd" \ + "hdl/ft_components/hamming_register.vhd" \ + "hdl/instr_fetch.vhd" \ + "hdl/regfile.vhd" \ + "hdl/harv.vhd" \ + "sim/sim_from_dump.vhd" \ + ] + foreach ifile $files { + if { ![file isfile $ifile] } { + puts " Could not find remote file $ifile " + set status false + } + } + + return $status +} +# Set the reference directory for source file relative paths (by default the value is script directory path) +set origin_dir "." + +# Use origin directory path location variable, if specified in the tcl shell +if { [info exists ::origin_dir_loc] } { + set origin_dir $::origin_dir_loc +} + +# Set the project name +set _xil_proj_name_ "harv" + +# Use project name variable, if specified in the tcl shell +if { [info exists ::user_project_name] } { + set _xil_proj_name_ $::user_project_name +} + +variable script_file +set script_file "project.tcl" + +# Help information for this script +proc print_help {} { + variable script_file + puts "\nDescription:" + puts "Recreate a Vivado project from this script. The created project will be" + puts "functionally equivalent to the original project for which this script was" + puts "generated. The script contains commands for creating a project, filesets," + puts "runs, adding/importing sources and setting properties on various objects.\n" + puts "Syntax:" + puts "$script_file" + puts "$script_file -tclargs \[--origin_dir \]" + puts "$script_file -tclargs \[--project_name \]" + puts "$script_file -tclargs \[--help\]\n" + puts "Usage:" + puts "Name Description" + puts "-------------------------------------------------------------------------" + puts "\[--origin_dir \] Determine source file paths wrt this path. Default" + puts " origin_dir path value is \".\", otherwise, the value" + puts " that was set with the \"-paths_relative_to\" switch" + puts " when this script was generated.\n" + puts "\[--project_name \] Create project with the specified name. Default" + puts " name is the name of the project from where this" + puts " script was generated.\n" + puts "\[--help\] Print help information for this script" + puts "-------------------------------------------------------------------------\n" + exit 0 +} + +if { $::argc > 0 } { + for {set i 0} {$i < $::argc} {incr i} { + set option [string trim [lindex $::argv $i]] + switch -regexp -- $option { + "--origin_dir" { incr i; set origin_dir [lindex $::argv $i] } + "--project_name" { incr i; set _xil_proj_name_ [lindex $::argv $i] } + "--help" { print_help } + default { + if { [regexp {^-} $option] } { + puts "ERROR: Unknown option '$option' specified, please type '$script_file -tclargs --help' for usage info.\n" + return 1 + } + } + } + } +} + +# Set the directory path for the original project from where this script was exported +set orig_proj_dir "[file normalize "$origin_dir/xilinx"]" + +# Check for paths and files needed for project creation +set validate_required 0 +if { $validate_required } { + if { [checkRequiredFiles $origin_dir] } { + puts "Tcl file $script_file is valid. All files required for project creation is accesable. " + } else { + puts "Tcl file $script_file is not valid. Not all files required for project creation is accesable. " + return + } +} + +# Create project +create_project ${_xil_proj_name_} "xilinx/" -part xc7z020clg484-1 + +# Set the directory path for the new project +set proj_dir [get_property directory [current_project]] + +# Set project properties +set obj [current_project] +set_property -name "board_part" -value "em.avnet.com:zed:part0:1.4" -objects $obj +set_property -name "default_lib" -value "xil_defaultlib" -objects $obj +set_property -name "enable_vhdl_2008" -value "1" -objects $obj +set_property -name "ip_cache_permissions" -value "read write" -objects $obj +set_property -name "ip_output_repo" -value "$proj_dir/${_xil_proj_name_}.cache/ip" -objects $obj +set_property -name "mem.enable_memory_map_generation" -value "1" -objects $obj +set_property -name "platform.board_id" -value "zed" -objects $obj +set_property -name "sim.central_dir" -value "$proj_dir/${_xil_proj_name_}.ip_user_files" -objects $obj +set_property -name "sim.ip.auto_export_scripts" -value "1" -objects $obj +set_property -name "simulator_language" -value "VHDL" -objects $obj +set_property -name "target_language" -value "VHDL" -objects $obj +set_property -name "webtalk.xsim_launch_sim" -value "30" -objects $obj + +# Create 'sources_1' fileset (if not found) +if {[string equal [get_filesets -quiet sources_1] ""]} { + create_fileset -srcset sources_1 +} + +# Set 'sources_1' fileset object +set obj [get_filesets sources_1] +set files [list \ + [file normalize "${origin_dir}/hdl/harv_pkg.vhd"] \ + [file normalize "${origin_dir}/hdl/alu.vhd"] \ + [file normalize "${origin_dir}/hdl/ft_components/alu_tmr.vhd"] \ + [file normalize "${origin_dir}/hdl/control.vhd"] \ + [file normalize "${origin_dir}/hdl/ft_components/control_tmr.vhd"] \ + [file normalize "${origin_dir}/hdl/csr.vhd"] \ + [file normalize "${origin_dir}/hdl/ft_components/hamming_pkg.vhd"] \ + [file normalize "${origin_dir}/hdl/ft_components/hamming_decoder.vhd"] \ + [file normalize "${origin_dir}/hdl/ft_components/hamming_encoder.vhd"] \ + [file normalize "${origin_dir}/hdl/ft_components/hamming_register.vhd"] \ + [file normalize "${origin_dir}/hdl/instr_fetch.vhd"] \ + [file normalize "${origin_dir}/hdl/regfile.vhd"] \ + [file normalize "${origin_dir}/hdl/harv.vhd"] \ +] +add_files -norecurse -fileset $obj $files + +# Set 'sources_1' fileset file properties for remote files +set file "$origin_dir/hdl/harv_pkg.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/alu.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/ft_components/alu_tmr.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/control.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/ft_components/control_tmr.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/csr.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/ft_components/hamming_pkg.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/ft_components/hamming_decoder.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/ft_components/hamming_encoder.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/ft_components/hamming_register.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/instr_fetch.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/regfile.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +set file "$origin_dir/hdl/harv.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sources_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +# Set 'sources_1' fileset properties +set obj [get_filesets sources_1] +set_property -name "top" -value "harv" -objects $obj + +# Create 'sim_1' fileset (if not found) +if {[string equal [get_filesets -quiet sim_1] ""]} { + create_fileset -simset sim_1 +} + +# Set 'sim_1' fileset object +set obj [get_filesets sim_1] +set files [list \ + [file normalize "${origin_dir}/sim/sim_from_dump.vhd"] \ +] +add_files -norecurse -fileset $obj $files + +# Import local files from the original project +set files [list \ + [file normalize "${origin_dir}/xilinx/sim_from_dump_behav.wcfg" ]\ +] +add_files -norecurse -fileset sim_1 $files + +# Set 'sim_1' fileset file properties for remote files +set file "$origin_dir/sim/sim_from_dump.vhd" +set file [file normalize $file] +set file_obj [get_files -of_objects [get_filesets sim_1] [list "*$file"]] +set_property -name "file_type" -value "VHDL 2008" -objects $file_obj + +# Set 'sim_1' fileset properties +set obj [get_filesets sim_1] +set_property -name "hbs.configure_design_for_hier_access" -value "1" -objects $obj +set_property -name "top" -value "sim_from_dump" -objects $obj +set_property -name "top_lib" -value "xil_defaultlib" -objects $obj + +puts "INFO: Project created: ${_xil_proj_name_}" + + +exit diff --git a/sim/sim_from_dump.vhd b/sim/sim_from_dump.vhd new file mode 100644 index 0000000..d44f5fb --- /dev/null +++ b/sim/sim_from_dump.vhd @@ -0,0 +1,240 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use std.textio.all; +use ieee.std_logic_textio.all; + +library work; +use work.harv_pkg.harv; + +entity sim_from_dump is +end entity; + +architecture arch of sim_from_dump is + constant period : time := 100 ns; + signal rstn : std_logic := '0'; + signal clk : std_logic := '0'; + signal start : std_logic := '0'; + + constant INST_BASE_ADDR : integer := 0; + constant INST_SIZE : integer := 4096; + constant DATA_BASE_ADDR : integer := 8192; + constant DATA_SIZE : integer := 4096; + + type mem_t is array(natural range <>) of std_logic_vector(7 downto 0); + signal inst_mem : mem_t(INST_SIZE + INST_BASE_ADDR - 1 downto INST_BASE_ADDR); + signal data_mem : mem_t(DATA_SIZE + DATA_BASE_ADDR - 1 downto DATA_BASE_ADDR); + + -- instruction memory interface + signal imem_instr_i : std_logic_vector(31 downto 0); + signal imem_pc_o : std_logic_vector(31 downto 0); + signal imem_req_o : std_logic; + signal imem_gnt_i : std_logic; + + -- data memory interface + signal dmem_data_i : std_logic_vector(31 downto 0); + signal dmem_req_o : std_logic; + signal dmem_wren_o : std_logic; + signal dmem_gnt_i : std_logic; + signal dmem_outofrange_i : std_logic; + signal dmem_byte_en_o : std_logic_vector(1 downto 0); + signal dmem_usgn_dat_o : std_logic; + signal dmem_data_o : std_logic_vector(31 downto 0); + signal dmem_addr_o : std_logic_vector(31 downto 0); + + constant INST_DUMP_FILE_PATH : string := "../../../../../src/test_text.dump"; + constant DATA_DUMP_FILE_PATH : string := "../../../../../src/test_data.dump"; + + procedure load_memory ( + constant FILE_PATH : in string; + constant BASE_ADDR : in integer; + signal mem : out mem_t + ) is + file file_v : text; + variable line_v : line; + variable addr_v : integer; + variable byte_v : std_logic_vector(7 downto 0); + variable error_v : boolean; + begin + -- read data dump file + file_open(file_v, FILE_PATH, READ_MODE); + -- initialize instructions address counter + addr_v := BASE_ADDR; + -- iterate through all lines in the file + while not endfile(file_v) loop + -- read line from file_v + readline(file_v, line_v); + -- ensure that the line is not empty + if line_v'length > 0 then + -- iterate in each byte of the data + for i in 3 downto 0 loop + -- read hex byte from line + hread(line_v, byte_v, error_v); + -- assert if the hread had an error + assert (error_v) report "Text I/O read error" severity FAILURE; + -- write byte to memory + mem(addr_v + i) <= byte_v; + end loop; + -- increment address + addr_v := addr_v + 4; + end if; + end loop; + file_close(file_v); + end procedure; +begin + rstn <= '1' after period; + clk <= not clk after period/2; + start <= '1' after period * 2; -- set start signal after 2 clock cycles + + harv_i : harv + generic map ( + PROGRAM_START_ADDR => x"00000000", + TRAP_HANDLER_ADDR => x"00000000", + TMR_CONTROL => FALSE, + TMR_ALU => FALSE, + HAMMING_REGFILE => FALSE, + HAMMING_PC => FALSE + ) + port map ( + rstn_i => rstn, + clk_i => clk, + start_i => start, + poweron_rstn_i => rstn, + wdt_rstn_i => '1', + imem_instr_i => imem_instr_i, + imem_pc_o => imem_pc_o, + imem_req_o => imem_req_o, + imem_gnt_i => imem_gnt_i, + imem_err_i => '0', + hard_dmem_o => open, + dmem_data_i => dmem_data_i, + dmem_req_o => dmem_req_o, + dmem_wren_o => dmem_wren_o, + dmem_gnt_i => dmem_gnt_i, + dmem_outofrange_i => dmem_outofrange_i, + dmem_sbu_i => '0', + dmem_dbu_i => '0', + dmem_byte_en_o => dmem_byte_en_o, + dmem_usgn_dat_o => dmem_usgn_dat_o, + dmem_data_o => dmem_data_o, + dmem_addr_o => dmem_addr_o + ); + + -- INSTRUCTION MEMORY ACCESS + process + variable addr_v : integer; + begin + -- load instruction memory + report "Loading instruction memory from " & INST_DUMP_FILE_PATH severity NOTE; + load_memory(INST_DUMP_FILE_PATH, INST_BASE_ADDR, inst_mem); + -- infinite loop to provide instruction memory access + loop + -- disable grant signal + imem_gnt_i <= '0'; + imem_instr_i <= (others => 'X'); + -- wait memory request + wait until rising_edge(clk) and imem_req_o = '1'; + -- wait 1 cycle to give response + wait for period; + -- grant response + imem_gnt_i <= '1'; + addr_v := to_integer(unsigned(imem_pc_o)); + imem_instr_i <= inst_mem(addr_v+3) & + inst_mem(addr_v+2) & + inst_mem(addr_v+1) & + inst_mem(addr_v); + -- grant response for 1 cycle + wait for period; + end loop; + end process; + + -- DATA MEMORY ACCESS + process + variable addr_v : integer; + begin + -- if there is no data dump file + if DATA_DUMP_FILE_PATH = "" then + report "No data memory to load" severity NOTE; + else -- if data dump file is defined + -- load data memory from file + report "Loading data memory from " & DATA_DUMP_FILE_PATH severity NOTE; + load_memory (DATA_DUMP_FILE_PATH, DATA_BASE_ADDR, data_mem); + end if; + -- infinite loop to provide data memory access + loop + -- disable grant signal + dmem_gnt_i <= '0'; + dmem_data_i <= (others => 'X'); + dmem_outofrange_i <= '0'; + -- wait memory request + wait until rising_edge(clk) and dmem_req_o = '1'; + -- wait 1 cycle to give response + wait for period; + -- convert address to integer + addr_v := to_integer(unsigned(dmem_addr_o)); + -- check if range is ok + if addr_v < DATA_BASE_ADDR or addr_v > (DATA_BASE_ADDR + DATA_SIZE) then + dmem_outofrange_i <= '1'; + else + -- grant response + dmem_gnt_i <= '1'; + -- if it will perform a write + if dmem_wren_o = '1' then + -- write the first byte + data_mem(addr_v) <= dmem_data_o(7 downto 0); + -- write the second byte for half-word and word + if dmem_byte_en_o(0) = '1' then + data_mem(addr_v+1) <= dmem_data_o(15 downto 8); + end if; + -- write the upper 16 bits, only for full word + if dmem_byte_en_o(1) = '1' then + data_mem(addr_v+2) <= dmem_data_o(23 downto 16); + data_mem(addr_v+3) <= dmem_data_o(31 downto 24); + end if; + + -- read data memory + else + -- case between all acess possibilities + case dmem_byte_en_o is + -- byte read with and without sign-extension + when "00" => + if dmem_usgn_dat_o = '1' then + dmem_data_i <= x"000000" & data_mem(addr_v); + else + dmem_data_i <= ( + 31 downto 8 => data_mem(addr_v)(7), + 7 downto 0 => data_mem(0) + ); + end if; + + -- half-word read with and without sign-extension + when "01" => + if dmem_usgn_dat_o = '1' then + dmem_data_i <= ( + 31 downto 16 => data_mem(addr_v + 1)(7), + 15 downto 8 => data_mem(addr_v + 1), + 7 downto 0 => data_mem(addr_v) + ); + else + dmem_data_i <= x"000000" & data_mem(addr_v); + end if; + + -- word read - concatanate bytes + when "11" => + dmem_data_i <= data_mem(addr_v + 3) & + data_mem(addr_v + 2) & + data_mem(addr_v + 1) & + data_mem(addr_v); + when others => + report "Wrong parameters to data memory" severity ERROR; + + end case; + end if; + end if; + -- response for 1 cycle + wait for period; + end loop; + end process; + +end architecture; diff --git a/src/test.asm b/src/test.asm new file mode 100644 index 0000000..b1965be --- /dev/null +++ b/src/test.asm @@ -0,0 +1,20 @@ +.data + var0: 100 + var1: 200 + var3: +.text + lw t0, var0 + lw t1, var1 + + sub t2, t1, t0 + + add t3, t1, t2 + add t3, t3, t3 + + la t4, var3 + sw t3, 0(t4) + lw t4, 0(t4) + +end_loop: + j end_loop + diff --git a/xilinx/sim_from_dump_behav.wcfg b/xilinx/sim_from_dump_behav.wcfg new file mode 100644 index 0000000..12f9245 --- /dev/null +++ b/xilinx/sim_from_dump_behav.wcfg @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + INST_DUMP_FILE_PATH[1:33] + INST_DUMP_FILE_PATH[1:33] + + + DATA_DUMP_FILE_PATH[1:33] + DATA_DUMP_FILE_PATH[1:33] + + + period + period + + + rstn + rstn + + + clk + clk + + + start + start + + + imem_gnt_i + imem_gnt_i + + + if_pc_w[31:0] + if_pc_w[31:0] + + + instr_o[31:0] + instr_o[31:0] + + + label + [29][31:0] + [29][31:0] + reg_t4 + SIGNEDDECRADIX + + + label + [28][31:0] + [28][31:0] + reg_t3 + SIGNEDDECRADIX + + + label + [7][31:0] + [7][31:0] + reg_t2 + SIGNEDDECRADIX + + + label + [6][31:0] + [6][31:0] + reg_t1 + SIGNEDDECRADIX + + + label + [5][31:0] + [5][31:0] + reg_t0 + SIGNEDDECRADIX + + + regfile_w[31:0][31:0] + regfile_w[31:0][31:0] + + + CORE + label + + + proc_status_r[2:0] + proc_status_r[2:0] + + + data_i[31:0] + data_i[31:0] + + + wren_i + wren_i + + + MEMORIES + label + + + imem + label + + DATA_SIZE + DATA_SIZE + + + imem_instr_i[31:0] + imem_instr_i[31:0] + + + imem_pc_o[31:0] + imem_pc_o[31:0] + + + imem_req_o + imem_req_o + + + imem_gnt_i + imem_gnt_i + + + + dmem + label + + + dmem_data_i[31:0] + dmem_data_i[31:0] + + + dmem_req_o + dmem_req_o + + + dmem_wren_o + dmem_wren_o + + + dmem_gnt_i + dmem_gnt_i + + + dmem_outofrange_i + dmem_outofrange_i + + + dmem_byte_en_o[1:0] + dmem_byte_en_o[1:0] + BINARYRADIX + + + dmem_usgn_dat_o + dmem_usgn_dat_o + + + dmem_data_o[31:0] + dmem_data_o[31:0] + + + dmem_addr_o[31:0] + dmem_addr_o[31:0] + HEXRADIX + + + + data_mem[12287:8192][7:0] + data_mem[12287:8192][7:0] + + + inst_mem[4095:0][7:0] + inst_mem[4095:0][7:0] + + + INST_BASE_ADDR + INST_BASE_ADDR + + + INST_SIZE + INST_SIZE + + + DATA_BASE_ADDR + DATA_BASE_ADDR + + + DATA_SIZE + DATA_SIZE + +