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 0000000..3d71f51 Binary files /dev/null and b/images/rars-data-export.png differ diff --git a/images/rars-memory-configuration.png b/images/rars-memory-configuration.png new file mode 100644 index 0000000..9d6e883 Binary files /dev/null and b/images/rars-memory-configuration.png differ diff --git a/images/rars-text-export.png b/images/rars-text-export.png new file mode 100644 index 0000000..3a64da4 Binary files /dev/null and b/images/rars-text-export.png differ 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 + +