mirror of
https://github.com/Domipheus/RPU.git
synced 2025-04-18 19:15:13 -04:00
Core can now boot Zephyr RTOS
Added Interrupt handling support: - Int enable masks - external interrupt - interrupt enable CSR - illegal instruction - system call instruction - breakpoints - interrupt CSR manipulation - correct nextPC resume/branch target selection Added debug data for CPU trace support Added vexrisc IRQ csrs for testing with 3rd party sw Added LINT unit locally arbitrates IRQs into priorities FIX: correctly sign extend data from memory controller FIX: set ALU to not branch on CSR unit ops FIX: correctly detect invalid operations in decode stage FIX: set signals not outputs in decode Change to use two regs arrays in register set to infer two port rams
This commit is contained in:
parent
01ac31c43d
commit
8803d1392d
9 changed files with 385 additions and 141 deletions
|
@ -3,7 +3,7 @@
|
|||
-- Description: control unit
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2016 Colin Riley
|
||||
-- Copyright 2016,2018,2019,2020 Colin Riley
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
|
@ -27,6 +27,7 @@ entity control_unit is
|
|||
Port (
|
||||
I_clk : in STD_LOGIC;
|
||||
I_reset : in STD_LOGIC;
|
||||
I_halt: in STD_LOGIC;
|
||||
I_aluop : in STD_LOGIC_VECTOR (6 downto 0);
|
||||
|
||||
-- interrupts
|
||||
|
@ -79,7 +80,7 @@ begin
|
|||
|
||||
process(I_clk)
|
||||
begin
|
||||
if rising_edge(I_clk) then
|
||||
if rising_edge(I_clk) and I_halt = '0' then
|
||||
if I_reset = '1' then
|
||||
s_state <= "0000001";
|
||||
next_s_state <= "0000001";
|
||||
|
@ -93,11 +94,11 @@ begin
|
|||
set_idata <= '0';
|
||||
instTick <= '0';
|
||||
else
|
||||
if I_int = '0' then
|
||||
interrupt_was_inactive <= '1';
|
||||
end if;
|
||||
case s_state is
|
||||
when "0000001" => -- fetch
|
||||
if I_int = '0' then
|
||||
interrupt_was_inactive <= '1';
|
||||
end if;
|
||||
instTick <= '0';
|
||||
if mem_cycles = 0 and mem_ready = '1' then
|
||||
mem_execute <= '1';
|
||||
|
@ -114,21 +115,28 @@ begin
|
|||
end if;
|
||||
end if;
|
||||
when "0000010" => --- decode
|
||||
if I_int = '0' then
|
||||
interrupt_was_inactive <= '1';
|
||||
end if;
|
||||
s_state <= "0001000"; --E "0000100"; --R
|
||||
when "0000100" => -- read -- DEPRECATED STAGE
|
||||
s_state <= "0001000"; --E
|
||||
when "0001000" => -- execute
|
||||
if I_int = '0' then
|
||||
interrupt_was_inactive <= '1';
|
||||
end if;
|
||||
--MEM/WB
|
||||
-- if it's not a memory alu op, goto writeback
|
||||
if (I_aluop(6 downto 2) = OPCODE_LOAD or
|
||||
I_aluop(6 downto 2) = OPCODE_STORE) then
|
||||
s_state <= "0010000"; -- MEM
|
||||
-- elsif (I_aluop(6 downto 2) = OPCODE_SYSTEM) then
|
||||
-- s_state <= "1001000"; -- alu stall
|
||||
else
|
||||
s_state <= "0100000"; -- WB
|
||||
end if;
|
||||
when "0010000" => -- mem
|
||||
if I_int = '0' then
|
||||
interrupt_was_inactive <= '1';
|
||||
end if;
|
||||
-- sometimes memory can be busy, if so we need to relook here
|
||||
if mem_cycles = 0 and mem_ready = '1' then
|
||||
mem_execute <= '1';
|
||||
|
@ -155,28 +163,31 @@ begin
|
|||
next_s_state <= "0000001"; --F
|
||||
s_state <= "1000000"; --F
|
||||
else
|
||||
if I_int = '0' then
|
||||
interrupt_was_inactive <= '1';
|
||||
end if;
|
||||
s_state <= "0000001"; --F
|
||||
end if;
|
||||
instTick <= '1';
|
||||
when "1000000" => -- stalls
|
||||
if I_int = '0' then
|
||||
interrupt_was_inactive <= '1';
|
||||
end if;
|
||||
instTick <= '0';
|
||||
-- interrupt stall
|
||||
if interrupt_state = "001" then
|
||||
-- give a cycle of latency
|
||||
-- interrupt_state <= "010";
|
||||
-- elsif interrupt_state = "010" then
|
||||
-- -- sample input data for state?
|
||||
-- O_idata <= I_int_mem_data;
|
||||
-- set_idata <= '1';
|
||||
-- interrupt_state <= "100";
|
||||
-- elsif interrupt_state = "100" then
|
||||
-- set_idata <= '0';
|
||||
-- set PC to interrupt vector.
|
||||
|
||||
set_ipc <= '1';
|
||||
interrupt_state <= "101";
|
||||
elsif interrupt_state = "101" then
|
||||
set_ipc <= '0';
|
||||
interrupt_ack <= '0';
|
||||
interrupt_state <= "101";
|
||||
|
||||
-- interrupt_ack <= '0';
|
||||
elsif interrupt_state = "101" then
|
||||
set_ipc <= '0';
|
||||
interrupt_ack <= '0';
|
||||
interrupt_state <= "111";
|
||||
elsif interrupt_state = "111" then
|
||||
interrupt_state <= "000";
|
||||
s_state <= "0000001"; --F
|
||||
end if;
|
||||
|
|
129
vhdl/core.vhd
129
vhdl/core.vhd
|
@ -6,7 +6,7 @@
|
|||
-- This is the CPU interface required.
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2016 Colin Riley
|
||||
-- Copyright 2018,2019,2020 Colin Riley
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
|
@ -50,6 +50,7 @@ entity core is
|
|||
MEM_I_dataReady : IN std_logic
|
||||
|
||||
; -- This debug output contains some internal state for debugging
|
||||
O_halted: OUT std_logic;
|
||||
O_DBG:out std_logic_vector(63 downto 0)
|
||||
);
|
||||
end core;
|
||||
|
@ -68,6 +69,7 @@ architecture Behavioral of core is
|
|||
COMPONENT control_unit
|
||||
PORT (
|
||||
I_clk : in STD_LOGIC;
|
||||
I_halt: in STD_LOGIC;
|
||||
I_reset : in STD_LOGIC;
|
||||
I_aluop : in STD_LOGIC_VECTOR (6 downto 0);
|
||||
O_state : out STD_LOGIC_VECTOR (6 downto 0);
|
||||
|
@ -105,6 +107,7 @@ architecture Behavioral of core is
|
|||
O_memOp : out STD_LOGIC_VECTOR(4 downto 0);
|
||||
O_csrOP : out STD_LOGIC_VECTOR(4 downto 0);
|
||||
O_csrAddr : out STD_LOGIC_VECTOR(11 downto 0);
|
||||
O_trapExit: out STD_LOGIC;
|
||||
O_int : out STD_LOGIC;
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_int_ack: in STD_LOGIC
|
||||
|
@ -126,6 +129,7 @@ architecture Behavioral of core is
|
|||
O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
O_branchTarget : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
O_dataWriteReg : out STD_LOGIC;
|
||||
O_lastPC: out STD_LOGIC_VECTOR(XLEN32M1 downto 0);
|
||||
O_shouldBranch : out std_logic
|
||||
|
||||
);
|
||||
|
@ -162,9 +166,16 @@ architecture Behavioral of core is
|
|||
|
||||
I_instRetTick : in STD_LOGIC;
|
||||
|
||||
-- mcause has a fast path in from other units
|
||||
I_int_cause: in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
I_int_pc: in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
|
||||
-- interrupt handling causes many data dependencies
|
||||
-- mcause has a fast path in from other units
|
||||
I_int_cause: in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
I_int_pc: in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
-- We need to know when an interrupt occurs as to perform the
|
||||
-- relevant csr modifications. Same with exit.
|
||||
I_int_entry: IN STD_LOGIC;
|
||||
I_int_exit: IN STD_LOGIC;
|
||||
|
||||
-- Currently just feeds machine level CSR values
|
||||
O_csr_status : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
O_csr_cause : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
|
@ -178,6 +189,8 @@ architecture Behavioral of core is
|
|||
PORT (
|
||||
I_clk : in STD_LOGIC;
|
||||
I_reset : in STD_LOGIC;
|
||||
I_nextPc : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_enMask : in STD_LOGIC_VECTOR (3 downto 0);
|
||||
I_pc : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_int0 : in STD_LOGIC;
|
||||
I_int_data0 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
|
@ -187,8 +200,10 @@ architecture Behavioral of core is
|
|||
O_int1_ack: out STD_LOGIC;
|
||||
I_int2 : in STD_LOGIC;
|
||||
I_int_data2 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int2_ack: out STD_LOGIC;
|
||||
I_int3 : in STD_LOGIC;
|
||||
I_int_data3 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int3_ack: out STD_LOGIC;
|
||||
O_int : out STD_LOGIC;
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int_epc : out STD_LOGIC_VECTOR (31 downto 0)
|
||||
|
@ -205,6 +220,7 @@ architecture Behavioral of core is
|
|||
I_address : IN std_logic_vector(XLENM1 downto 0);
|
||||
I_data : IN std_logic_vector(XLENM1 downto 0);
|
||||
I_dataByteEn : IN std_logic_vector(1 downto 0);
|
||||
I_signExtend : in STD_LOGIC;
|
||||
O_data : OUT std_logic_vector(XLENM1 downto 0);
|
||||
O_dataReady : OUT std_logic;
|
||||
MEM_I_ready : IN std_logic;
|
||||
|
@ -250,6 +266,7 @@ architecture Behavioral of core is
|
|||
signal decoder_int: STD_LOGIC;
|
||||
signal decoder_int_data: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal decoder_int_ack: STD_LOGIC := '0';
|
||||
signal decoder_trap_exit: STD_LOGIC := '0';
|
||||
|
||||
|
||||
signal reg_en: std_logic := '0';
|
||||
|
@ -268,6 +285,9 @@ architecture Behavioral of core is
|
|||
|
||||
signal PC : std_logic_vector(XLENM1 downto 0) := (others => '0');
|
||||
signal PC_at_int : std_logic_vector(XLENM1 downto 0) := (others => '0');
|
||||
signal lastPC_dec : std_logic_vector(XLENM1 downto 0) := (others => '0');
|
||||
signal lastPC_alu : std_logic_vector(XLENM1 downto 0) := (others => '0');
|
||||
signal nextPC_stall : std_logic_vector(XLENM1 downto 0) := (others => '0');
|
||||
|
||||
signal memctl_ready : std_logic;
|
||||
signal memctl_execute : std_logic := '0';
|
||||
|
@ -284,9 +304,12 @@ architecture Behavioral of core is
|
|||
|
||||
signal int_idata: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal int_set_idata: STD_LOGIC;
|
||||
signal int_enabled: std_logic := '0';
|
||||
signal int_enabled: std_logic := '1'; --'0';
|
||||
signal int_set_irpc: STD_LOGIC;
|
||||
|
||||
signal I_int_entry: STD_LOGIC := '0';
|
||||
signal I_int_exit: STD_LOGIC := '0';
|
||||
|
||||
signal csru_int: STD_LOGIC;
|
||||
signal csru_int_data: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
signal csru_int_ack: STD_LOGIC := '0';
|
||||
|
@ -315,8 +338,19 @@ architecture Behavioral of core is
|
|||
signal lint_int: STD_LOGIC;
|
||||
signal lint_int_data: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
|
||||
signal lint_enable_mask : STD_LOGIC_VECTOR (3 downto 0):= (others => '0');
|
||||
|
||||
signal external_int_ack : STD_LOGIC := '0';
|
||||
|
||||
signal dbg_data_line: STD_LOGIC_VECTOR(XLENM1 downto 0);
|
||||
|
||||
signal is_illegal :std_logic:='0';
|
||||
|
||||
signal should_halt: STD_LOGIC := '0';
|
||||
begin
|
||||
|
||||
should_halt <= I_halt;
|
||||
O_halted <= should_halt;
|
||||
core_clock <= I_clk;
|
||||
|
||||
memctl: mem_controller PORT MAP (
|
||||
|
@ -329,6 +363,7 @@ begin
|
|||
I_address => memctl_address,
|
||||
I_data => memctl_in_data,
|
||||
I_dataByteEn => memctl_dataByteEn,
|
||||
I_signExtend => memctl_signExtend,
|
||||
O_data => memctl_out_data,
|
||||
O_dataReady => memctl_dataReady,
|
||||
|
||||
|
@ -353,6 +388,7 @@ begin
|
|||
control: control_unit PORT MAP (
|
||||
I_clk => core_clock,
|
||||
I_reset => I_reset,
|
||||
I_halt => should_halt,
|
||||
I_aluop => aluop,
|
||||
|
||||
I_int => lint_int,
|
||||
|
@ -384,6 +420,7 @@ begin
|
|||
O_memOp => memOp,
|
||||
O_csrOp => csru_csrOp,
|
||||
O_csrAddr => csru_csrAddr,
|
||||
O_trapExit => decoder_trap_exit,
|
||||
-- This unit can raise exceptions
|
||||
O_int => decoder_int,
|
||||
O_int_data => decoder_int_data,
|
||||
|
@ -404,6 +441,7 @@ begin
|
|||
O_dataResult => dataResult,
|
||||
O_branchTarget => branchTarget,
|
||||
O_dataWriteReg => dataWriteReg,
|
||||
O_lastPC => lastPC_alu,
|
||||
O_shouldBranch => shouldBranch
|
||||
);
|
||||
|
||||
|
@ -440,6 +478,9 @@ begin
|
|||
I_int_cause => lint_int_data,
|
||||
I_int_pc => PC_at_int,
|
||||
|
||||
I_int_entry => I_int_entry,
|
||||
I_int_exit => I_int_exit,
|
||||
|
||||
O_csr_status => csr_status,
|
||||
O_csr_tvec => csr_tvec,
|
||||
O_csr_cause => csr_cause,
|
||||
|
@ -450,22 +491,45 @@ begin
|
|||
lint: lint_unit PORT MAP (
|
||||
I_clk => core_clock,
|
||||
I_reset => lint_reset,
|
||||
I_pc => PC,
|
||||
I_nextPc => nextPC_stall,
|
||||
|
||||
I_enMask => lint_enable_mask,
|
||||
I_pc => lastPC_dec,
|
||||
|
||||
I_int0 => decoder_int,
|
||||
I_int_data0 => decoder_int_data,
|
||||
O_int0_ack => decoder_int_ack,
|
||||
|
||||
I_int1 => csru_int,
|
||||
I_int_data1 => csru_int_data,
|
||||
O_int1_ack => csru_int_ack,
|
||||
I_int2 => lint_nothing,
|
||||
I_int_data2 => lint_nothing_data,
|
||||
|
||||
I_int2 => I_int,
|
||||
I_int_data2 => I_int_data,
|
||||
O_int2_ack => external_int_ack,
|
||||
|
||||
|
||||
I_int3 => lint_nothing,
|
||||
I_int_data3 => lint_nothing_data,
|
||||
|
||||
O_int => lint_int,
|
||||
O_int_data => lint_int_data,
|
||||
O_int_epc => PC_at_int
|
||||
O_int_data => lint_int_data--,
|
||||
-- O_int_epc => PC_at_int
|
||||
);
|
||||
|
||||
O_int_ack <= external_int_ack;
|
||||
|
||||
state_latcher: process(core_clock)
|
||||
begin
|
||||
if rising_edge(core_clock) then
|
||||
if en_decode = '1' then
|
||||
lastPC_dec <= PC;
|
||||
end if;
|
||||
if state(6) = '1' then
|
||||
nextPC_stall <= PC;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
-- Register file controls
|
||||
reg_en <= en_decode or en_regwrite;
|
||||
|
@ -474,7 +538,7 @@ begin
|
|||
-- These are the pipeline stage enable bits
|
||||
en_fetch <= state(0);
|
||||
en_decode <= state(1);
|
||||
en_alu <= '0' when (aluop(6 downto 2) = OPCODE_SYSTEM and aluFunc(2 downto 0) /= "000") else state(3);
|
||||
en_alu <= state(3);
|
||||
en_csru <= state(3) when (aluop(6 downto 2) = OPCODE_SYSTEM and aluFunc(2 downto 0) /= "000") else '0';
|
||||
en_memory <= state(4);
|
||||
en_regwrite <= state(5);
|
||||
|
@ -486,22 +550,51 @@ begin
|
|||
PCU_OP_INC when shouldBranch = '0' and state(5) = '1' else
|
||||
PCU_OP_ASSIGN when PCintvec = '1' else
|
||||
PCU_OP_NOP;
|
||||
|
||||
-- this is lint interrupt enable for consuming the interrupt
|
||||
-- unused/external/crsu/decoder
|
||||
-- Only accept external on ALU stage to prevent issues with externals taking decode int's in fetch cycles
|
||||
-- externals are also programmable via csr register bit
|
||||
lint_enable_mask <= '0' & (csr_status(3)and state(3)) & '1' & '1';
|
||||
|
||||
-- interrupts are controlled by mstatus.mie - this is proper control unit acceptance
|
||||
int_enabled <= '1' when (lint_int_data(31) = '0' and lint_int = '1') else csr_status(3);
|
||||
|
||||
PC_at_int <= branchTarget when (shouldBranch = '1' and lint_int_data(31) = '1' and state(6) = '1' and lint_int = '1') else PC when (lint_int_data(31) = '1' and lint_int = '1') else lastPC_dec;
|
||||
|
||||
-- On Interrupt service entry, CSRs need some maintenance.
|
||||
-- We need to strobe the CSR unit on this event.
|
||||
I_int_entry <= PCintvec;
|
||||
-- To detect exit, we strobe using the ALU enable with the decoder trap request bit
|
||||
I_int_exit <= decoder_trap_exit and en_alu;
|
||||
|
||||
-- The input PC is just always the branch target output from ALU
|
||||
-- todo: tvec needs modifiec for vectored exceptions
|
||||
-- todo: tvec needs modified for vectored exceptions
|
||||
in_pc <= csr_tvec when PCintvec = '1' else branchTarget;
|
||||
|
||||
-- input data from the register file, or use immediate if the OP specifies it
|
||||
csru_dataIn <= dataIMM when csru_csrOp(CSR_OP_BITS_IMM) = '1' else dataA;
|
||||
|
||||
dbg_data_line <= registerWriteData when state(5) = '1' else memctl_address;
|
||||
--dbg_data_line can be used to aid debugging cpu issues using trace dumps.
|
||||
--dbg_data_line <= csr_tvec when memctl_execute = '1' else csru_dataIn when en_csru = '1' else registerWriteData when state(5) = '1' else X"000000" & "000" & selD when state(3) = '1' else instruction when state(1)='1' else memctl_address;
|
||||
--dbg_data_line <= memctl_address when memctl_execute = '1' else MEM_I_data;
|
||||
dbg_data_line <= X"ABCDEF01" when (decoder_int_data = EXCEPTION_INSTRUCTION_ILLEGAL and X"00000010" = csr_epc ) else csru_dataIn when en_csru = '1' else registerWriteData when state(5) = '1' else X"000000" & "000" & selD when state(3) = '1' else instruction when state(1)='1' else memctl_address;
|
||||
--dbg_data_line <= PC_at_int;--registerWriteData when state(5) = '1' else X"000000" & "000" & selD when state(3) = '1' else instruction when state(1)='1' else csr_epc when ( lint_reset = '1') else memctl_address;
|
||||
|
||||
is_illegal <= '1' when decoder_int_data = EXCEPTION_INSTRUCTION_ILLEGAL else '0';
|
||||
|
||||
-- The debug output just allows some internal state to be visible outside the core black box
|
||||
O_DBG <= "0000" & "00" & memctl_dataReady & MEM_I_dataReady & dataWriteReg & "0" & lint_reset & lint_int & "00" & decoder_int & csru_int & "000" & aluop(6 downto 2) & "0" & state & dbg_data_line;-- & registerWriteData(15 downto 0);
|
||||
-- byte 1 - memctrl&dataready
|
||||
-- byte 2 - dataWriteReg, lint_reset, lint_int, decoder and csru_int
|
||||
-- byte 2 - dataWriteReg, int_en, lint_reset, lint_int, interrupt_type_ decoder and csru_int
|
||||
-- byte 3 - aluop
|
||||
-- byte 4 - state
|
||||
-- uint32 - data
|
||||
O_DBG <= "0000" & "00" & memctl_dataReady & MEM_I_dataReady &
|
||||
-- dataWriteReg & int_enabled & lint_reset & lint_int & lint_int_data(31) & PCintvec & decoder_int & decoder_int_ack &--&csru_int & --I_int & --
|
||||
dataWriteReg & int_enabled & lint_reset & lint_int & I_int & external_int_ack & decoder_int & decoder_int_ack &--&csru_int & --I_int & --
|
||||
is_illegal & "00" & aluop(6 downto 2) &
|
||||
"0" & state &
|
||||
dbg_data_line;
|
||||
|
||||
-- Below statements are for memory interface use.
|
||||
memctl_address <= dataResult when en_memory = '1' else PC;
|
||||
|
@ -510,12 +603,14 @@ begin
|
|||
memctl_in_data <= dataB;
|
||||
memctl_dataWe <= '1' when en_memory = '1' and memOp(4 downto 3) = "11" else '0';
|
||||
memctl_size <= memOp(1 downto 0);
|
||||
memctl_signExtend <= memOp(2);
|
||||
memctl_signExtend <= not memOp(2);
|
||||
|
||||
-- This chooses to write registers with memory data or ALU/csr data
|
||||
registerWriteData <= memctl_out_data when memOp(4 downto 3) = "10" else csru_dataOut when aluop(6 downto 2) = OPCODE_SYSTEM else dataResult;
|
||||
registerWriteData <= memctl_out_data when memOp(4 downto 3) = "10" else dataB when (aluop(6 downto 2) = OPCODE_STORE ) else csru_dataOut when (aluop(6 downto 2) = OPCODE_SYSTEM and aluFunc(2 downto 0) /= "000") else dataResult;
|
||||
|
||||
-- The instructions are delivered from memctl
|
||||
-- FIXME: The instruction needs LATCHED. Any change to data input at a certain time
|
||||
-- can confuse the pipeline and get it into an inconsistent state.
|
||||
instruction <= memctl_out_data;
|
||||
|
||||
end Behavioral;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
-- Description: CSR unit RV32I
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2018 Colin Riley
|
||||
-- Copyright 2018,2019,2020 Colin Riley
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
|
@ -34,9 +34,16 @@ entity csr_unit is
|
|||
O_int : out STD_LOGIC;
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_instRetTick : in STD_LOGIC;
|
||||
|
||||
-- interrupt handling causes many data dependencies
|
||||
-- mcause has a fast path in from other units
|
||||
I_int_cause: in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
I_int_pc: in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
-- We need to know when an interrupt occurs as to perform the
|
||||
-- relevant csr modifications. Same with exit.
|
||||
I_int_entry: IN STD_LOGIC;
|
||||
I_int_exit: IN STD_LOGIC;
|
||||
|
||||
-- Currently just feeds machine level CSR values
|
||||
O_csr_status : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
O_csr_cause : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
|
@ -95,17 +102,24 @@ constant CSR_ADDR_MARCHID: STD_LOGIC_VECTOR (11 downto 0) := X"F12";
|
|||
constant CSR_ADDR_MIMPID: STD_LOGIC_VECTOR (11 downto 0) := X"F13";
|
||||
constant CSR_ADDR_MHARDID: STD_LOGIC_VECTOR (11 downto 0) := X"F14";
|
||||
|
||||
-- Will allow some other CSRS to make for easier running of third party sw
|
||||
constant CSR_ADDR_VEXRISC_IRQ_MASK: STD_LOGIC_VECTOR (11 downto 0) := X"bc0";
|
||||
constant CSR_ADDR_VEXRISC_IRQ_PENDING: STD_LOGIC_VECTOR (11 downto 0) := X"fc0";
|
||||
|
||||
signal csr_cycles: STD_LOGIC_VECTOR(63 downto 0) := (others => '0');
|
||||
signal csr_instret: STD_LOGIC_VECTOR(63 downto 0) := (others => '0');
|
||||
|
||||
signal csr_mstatus : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mstatus : STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000000";-- X"00001800"; -- MIE default 1
|
||||
signal csr_mie : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mtvec : STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000010";
|
||||
signal csr_mtvec : STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000004";-- X"00000010";
|
||||
signal csr_mscratch : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mepc : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mcause : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mtval : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_mip : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
|
||||
signal csr_vexrisc_irq_mask : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
signal csr_vexrisc_irq_pending : STD_LOGIC_VECTOR (XLENM1 downto 0) := (others => '0');
|
||||
|
||||
signal curr_csr_value: STD_LOGIC_VECTOR(XLENM1 downto 0) := (others=> '0');
|
||||
signal next_csr_value: STD_LOGIC_VECTOR(XLENM1 downto 0) := (others=> '0');
|
||||
|
@ -165,15 +179,28 @@ begin
|
|||
datamain: process (I_clk, I_en)
|
||||
begin
|
||||
if rising_edge(I_clk) then
|
||||
-- fastpath mcause write
|
||||
if (I_int_cause /= csr_mcause) then
|
||||
csr_mcause <= I_int_cause;
|
||||
end if;
|
||||
if (I_int_pc /= csr_mepc) then
|
||||
csr_mepc <= I_int_pc;
|
||||
end if;
|
||||
|
||||
if I_en = '1' and opState = 0 then
|
||||
if I_int_entry = '1' then
|
||||
-- on entry:
|
||||
-- mstatus.mpie = mstatus.mie
|
||||
csr_mstatus(7) <= csr_mstatus(3);
|
||||
-- mstatus.mie = 0
|
||||
csr_mstatus(3) <= '0';
|
||||
-- mstatus.mpp = current privilege mode
|
||||
csr_mstatus(12 downto 11) <= "11";
|
||||
|
||||
csr_mcause <= I_int_cause;
|
||||
csr_mepc <= I_int_pc;
|
||||
|
||||
elsif I_int_exit = '1' then
|
||||
-- privilege set to mstatus.mpp
|
||||
-- mstatus.mie = mstatus.mpie
|
||||
csr_mstatus(3) <= csr_mstatus(7);
|
||||
csr_mstatus(7) <= '1';
|
||||
csr_mstatus(12 downto 11) <= "00";
|
||||
|
||||
-- interrupt data changes take all priority
|
||||
elsif I_en = '1' and opState = 0 then
|
||||
csr_op <= I_csrOp;
|
||||
case I_csrAddr is
|
||||
when CSR_ADDR_MVENDORID =>
|
||||
|
@ -193,9 +220,18 @@ begin
|
|||
curr_csr_value <= csr_mtvec;
|
||||
when CSR_ADDR_MIE =>
|
||||
curr_csr_value <= csr_mie;
|
||||
when CSR_ADDR_MIP =>
|
||||
curr_csr_value <= csr_mip;
|
||||
when CSR_ADDR_MCAUSE =>
|
||||
curr_csr_value <= csr_mcause;
|
||||
|
||||
curr_csr_value <= csr_mcause;
|
||||
when CSR_ADDR_MEPC =>
|
||||
curr_csr_value <= csr_mepc;
|
||||
|
||||
when CSR_ADDR_VEXRISC_IRQ_PENDING =>
|
||||
curr_csr_value <= csr_vexrisc_irq_pending;
|
||||
when CSR_ADDR_VEXRISC_IRQ_MASK =>
|
||||
curr_csr_value <= csr_vexrisc_irq_mask;
|
||||
|
||||
when CSR_ADDR_CYCLE =>
|
||||
curr_csr_value <= csr_cycles(31 downto 0);
|
||||
when CSR_ADDR_CYCLEH =>
|
||||
|
@ -258,7 +294,17 @@ begin
|
|||
when CSR_ADDR_MTVEC =>
|
||||
csr_mtvec <= next_csr_value;
|
||||
when CSR_ADDR_MIE =>
|
||||
csr_mie <= next_csr_value;
|
||||
csr_mie <= next_csr_value;
|
||||
when CSR_ADDR_MIP =>
|
||||
csr_mip <= next_csr_value;
|
||||
when CSR_ADDR_MEPC =>
|
||||
csr_mepc <= next_csr_value;
|
||||
|
||||
|
||||
when CSR_ADDR_VEXRISC_IRQ_PENDING =>
|
||||
csr_vexrisc_irq_pending <= next_csr_value;
|
||||
when CSR_ADDR_VEXRISC_IRQ_MASK =>
|
||||
csr_vexrisc_irq_mask <= next_csr_value;
|
||||
when others =>
|
||||
end case;
|
||||
end if;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
-- Description: Local Interrupt unit
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2018 Colin Riley
|
||||
-- Copyright 2018,2019,2020 Colin Riley
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
|
@ -27,7 +27,9 @@ use work.constants.all;
|
|||
entity lint_unit is
|
||||
Port ( I_clk : in STD_LOGIC;
|
||||
I_reset : in STD_LOGIC;
|
||||
I_nextPc : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_pc : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
I_enMask : in STD_LOGIC_VECTOR (3 downto 0);
|
||||
I_int0 : in STD_LOGIC;
|
||||
I_int_data0 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int0_ack: out STD_LOGIC;
|
||||
|
@ -36,8 +38,10 @@ entity lint_unit is
|
|||
O_int1_ack: out STD_LOGIC;
|
||||
I_int2 : in STD_LOGIC;
|
||||
I_int_data2 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int2_ack: out STD_LOGIC;
|
||||
I_int3 : in STD_LOGIC;
|
||||
I_int_data3 : in STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int3_ack: out STD_LOGIC;
|
||||
O_int : out STD_LOGIC;
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0);
|
||||
O_int_epc : out STD_LOGIC_VECTOR (31 downto 0)
|
||||
|
@ -54,6 +58,9 @@ signal int0_ack: std_logic := '0';
|
|||
signal int1_ack: std_logic := '0';
|
||||
signal int2_ack: std_logic := '0';
|
||||
signal int3_ack: std_logic := '0';
|
||||
|
||||
signal reset_counter: integer := 0;
|
||||
|
||||
begin
|
||||
|
||||
O_int <= actual_int;
|
||||
|
@ -62,6 +69,8 @@ begin
|
|||
|
||||
O_int0_ack <= int0_ack;
|
||||
O_int1_ack <= int1_ack;
|
||||
O_int2_ack <= int2_ack;
|
||||
O_int3_ack <= int3_ack;
|
||||
|
||||
-- This simply filters one of the 4 int sources to a single one in
|
||||
-- decreasing priority, latching the data until a reset.
|
||||
|
@ -69,49 +78,40 @@ begin
|
|||
begin
|
||||
if rising_edge(I_clk) then
|
||||
if I_reset = '1' then
|
||||
actual_int <= '0';
|
||||
reset_counter <= 1;
|
||||
int0_ack <= '0';
|
||||
int1_ack <= '0';
|
||||
int2_ack <= '0';
|
||||
int3_ack <= '0';
|
||||
elsif I_int0 = '1' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data0;
|
||||
int0_ack <= '1';
|
||||
if (I_int_data0(31) = '1') then
|
||||
actual_int_epc <= std_logic_vector(signed( I_PC) + 4);
|
||||
else
|
||||
actual_int_epc <= I_PC;
|
||||
elsif reset_counter = 1 then
|
||||
reset_counter <= 2;
|
||||
elsif reset_counter = 2 then
|
||||
reset_counter <= 3;
|
||||
elsif reset_counter = 3 then
|
||||
actual_int <= '0';
|
||||
reset_counter <= 0;
|
||||
elsif reset_counter = 0 and actual_int = '0' then
|
||||
|
||||
if I_enMask(0) = '1' and I_int0 = '1' and int0_ack = '0' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data0;
|
||||
int0_ack <= '1';
|
||||
elsif I_enMask(1) = '1' and I_int1 = '1' and int1_ack = '0'then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data1;
|
||||
int1_ack <= '1';
|
||||
elsif I_enMask(2) = '1' and I_int2 = '1' and int2_ack = '0' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data2;
|
||||
int2_ack <= '1';
|
||||
elsif I_enMask(3) = '1' and I_int3 = '1' and int3_ack = '0'then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data3;
|
||||
int3_ack <= '1';
|
||||
end if;
|
||||
end if;
|
||||
elsif I_int1 = '1' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data1;
|
||||
int1_ack <= '1';
|
||||
if (I_int_data1(31) = '1') then
|
||||
actual_int_epc <= std_logic_vector(signed( I_PC) + 4);
|
||||
else
|
||||
actual_int_epc <= I_PC;
|
||||
end if;
|
||||
elsif I_int2 = '1' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data2;
|
||||
int2_ack <= '1';
|
||||
if (I_int_data2(31) = '1') then
|
||||
actual_int_epc <= std_logic_vector(signed( I_PC) + 4);
|
||||
else
|
||||
actual_int_epc <= I_PC;
|
||||
end if;
|
||||
elsif I_int3 = '1' then
|
||||
actual_int <= '1';
|
||||
actual_int_data <= I_int_data3;
|
||||
int3_ack <= '1';
|
||||
if (I_int_data3(31) = '1') then
|
||||
actual_int_epc <= std_logic_vector(signed( I_PC) + 4);
|
||||
else
|
||||
actual_int_epc <= I_PC;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
|
||||
end Behavioral;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
-- MEM_ signals are expected to be exposted to any SoC fabric.
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2016 Colin Riley
|
||||
-- Copyright 2016,2018,2019,2020 Colin Riley
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
|
@ -23,6 +23,8 @@
|
|||
library IEEE;
|
||||
use IEEE.STD_LOGIC_1164.ALL;
|
||||
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.constants.all;
|
||||
|
||||
|
@ -38,6 +40,7 @@ entity mem_controller is
|
|||
I_address : in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
I_data : in STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
I_dataByteEn : in STD_LOGIC_VECTOR(1 downto 0);
|
||||
I_signExtend : in STD_LOGIC;
|
||||
O_data : out STD_LOGIC_VECTOR (XLENM1 downto 0);
|
||||
O_dataReady: out STD_LOGIC;
|
||||
|
||||
|
@ -57,6 +60,8 @@ architecture Behavioral of mem_controller is
|
|||
signal we : std_logic := '0';
|
||||
signal addr : STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000000";
|
||||
signal indata: STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000000";
|
||||
signal outdata: STD_LOGIC_VECTOR (XLENM1 downto 0) := X"00000000";
|
||||
|
||||
signal byteEnable: STD_LOGIC_VECTOR ( 1 downto 0) := "11";
|
||||
signal cmd : STD_LOGIC := '0';
|
||||
signal state: integer := 0;
|
||||
|
@ -80,6 +85,7 @@ begin
|
|||
byteEnable <= I_dataByteEn;
|
||||
cmd <= '1';
|
||||
O_dataReady <= '0';
|
||||
outdata <= X"ABCDEFEE";
|
||||
if I_dataWe = '0' then
|
||||
state <= 3;-- read
|
||||
else
|
||||
|
@ -92,7 +98,18 @@ begin
|
|||
cmd <= '0';
|
||||
if MEM_I_dataReady = '1' then
|
||||
O_dataReady <= '1';
|
||||
O_data <= MEM_I_data;
|
||||
-- sign extend, if required
|
||||
if I_signExtend = '1' then
|
||||
if I_dataByteEn = F2_MEM_LS_SIZE_W then
|
||||
outdata <= MEM_I_data;
|
||||
elsif I_dataByteEn = F2_MEM_LS_SIZE_H then
|
||||
outdata <= std_logic_vector(resize(signed(MEM_I_data(15 downto 0)), XLEN));
|
||||
elsif I_dataByteEn = F2_MEM_LS_SIZE_B then
|
||||
outdata <= std_logic_vector(resize(signed(MEM_I_data(7 downto 0)), XLEN));
|
||||
end if;
|
||||
else
|
||||
outdata <= MEM_I_data;
|
||||
end if;
|
||||
state <= 2;
|
||||
end if;
|
||||
elsif state = 2 then
|
||||
|
@ -103,6 +120,7 @@ begin
|
|||
end if;
|
||||
end process;
|
||||
|
||||
O_data <= outdata;
|
||||
O_ready <= ( MEM_I_ready and not I_execute ) when state = 0 else '0';
|
||||
|
||||
MEM_O_cmd <= cmd;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
-- Simple black box for holding and manipulating the PC
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2016 Colin Riley
|
||||
-- Copyright 2016,2018,2019,2020 Colin Riley
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
|
@ -46,9 +46,6 @@ begin
|
|||
if rising_edge(I_clk) then
|
||||
case I_nPCop is
|
||||
when PCU_OP_NOP => -- NOP, keep PC the same/halt
|
||||
-- if I_intVec = '1' then -- in a NOP, you can get intterupts. check.
|
||||
-- current_pc <= ADDR_INTVEC;-- set PC to interrupt vector;
|
||||
-- end if;
|
||||
when PCU_OP_INC => -- increment
|
||||
current_pc <= std_logic_vector(unsigned(current_pc) + 4); -- 32bit byte addressing
|
||||
when PCU_OP_ASSIGN => -- set from external input
|
||||
|
|
|
@ -40,7 +40,8 @@ end register_set;
|
|||
|
||||
architecture Behavioral of register_set is
|
||||
type store_t is array (0 to 31) of std_logic_vector(XLENM1 downto 0);
|
||||
signal regs: store_t := (others => X"00000000");
|
||||
signal regsA: store_t := (others => X"00000000");
|
||||
signal regsB: store_t := (others => X"00000000");
|
||||
signal dataAout: STD_LOGIC_VECTOR (XLENM1 downto 0) := (others=>'0');
|
||||
signal dataBout: STD_LOGIC_VECTOR (XLENM1 downto 0) := (others=>'0');
|
||||
begin
|
||||
|
@ -48,16 +49,17 @@ begin
|
|||
process(I_clk, I_en)
|
||||
begin
|
||||
if rising_edge(I_clk) and I_en='1' then
|
||||
dataAout <= regs(to_integer(unsigned(I_selRS1)));
|
||||
dataBout <= regs(to_integer(unsigned(I_selRS2)));
|
||||
dataAout <= regsA(to_integer(unsigned(I_selRS1)));
|
||||
dataBout <= regsB(to_integer(unsigned(I_selRS2)));
|
||||
if (I_we = '1') then
|
||||
regs(to_integer(unsigned(I_selD))) <= I_dataD;
|
||||
regsA(to_integer(unsigned(I_selD))) <= I_dataD;
|
||||
regsB(to_integer(unsigned(I_selD))) <= I_dataD;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
O_dataA <= dataAout;
|
||||
O_dataB <= dataBout;
|
||||
O_dataA <= dataAout when I_selRS1 /= "00000" else X"00000000";
|
||||
O_dataB <= dataBout when I_selRS2 /= "00000" else X"00000000";
|
||||
|
||||
end Behavioral;
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
-- Description: ALU unit suitable for RV32I operational use
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2016 Colin Riley
|
||||
-- Copyright 2016,2018,2019,2020 Colin Riley
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
|
@ -40,6 +40,7 @@ entity alu_RV32I is
|
|||
O_dataResult : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
O_branchTarget : out STD_LOGIC_VECTOR (XLEN32M1 downto 0);
|
||||
O_dataWriteReg : out STD_LOGIC;
|
||||
O_lastPC: out STD_LOGIC_VECTOR(XLEN32M1 downto 0);
|
||||
O_shouldBranch : out std_logic
|
||||
);
|
||||
end alu_RV32I;
|
||||
|
@ -51,11 +52,13 @@ architecture Behavioral of alu_RV32I is
|
|||
signal s_branchTarget : STD_LOGIC_VECTOR (XLEN32M1 downto 0) := (others => '0');
|
||||
signal s_result: STD_LOGIC_VECTOR(XLEN32M1+2 downto 0) := (others => '0');
|
||||
signal s_shouldBranch: STD_LOGIC := '0';
|
||||
signal s_lastPC: STD_LOGIC_VECTOR(XLEN32M1 downto 0) := (others => '0');
|
||||
begin
|
||||
|
||||
process (I_clk, I_en)
|
||||
begin
|
||||
if rising_edge(I_clk) and I_en = '1' then
|
||||
s_lastPC <= I_PC;
|
||||
O_dataWriteReg <= I_dataDwe;
|
||||
case I_aluop is
|
||||
when OPCODE_OPIMM =>
|
||||
|
@ -166,6 +169,9 @@ begin
|
|||
s_branchTarget <= I_epc;
|
||||
s_shouldBranch <= '1';
|
||||
s_result(31 downto 0) <= std_logic_vector(signed( I_PC) + 4);
|
||||
elsif I_aluFunc(2 downto 0) /= F3_PRIVOP then
|
||||
-- do not branch on CSR unit work
|
||||
s_shouldBranch <= '0';
|
||||
end if;
|
||||
when OPCODE_LUI =>
|
||||
s_shouldBranch <= '0';
|
||||
|
@ -232,5 +238,6 @@ begin
|
|||
O_dataResult <= s_result(XLEN32M1 downto 0);
|
||||
O_shouldBranch <= s_shouldBranch;
|
||||
O_branchTarget <= s_branchTarget;
|
||||
O_lastPC <= s_lastPC;
|
||||
|
||||
end Behavioral;
|
|
@ -3,7 +3,7 @@
|
|||
-- Description: decoder unit RV32I
|
||||
--
|
||||
----------------------------------------------------------------------------------
|
||||
-- Copyright 2016 Colin Riley
|
||||
-- Copyright 2016,2018,2019,2020 Colin Riley
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
|
@ -39,6 +39,7 @@ entity decoder_RV32 is
|
|||
O_memOp : out STD_LOGIC_VECTOR(4 downto 0); -- Memory operation
|
||||
O_csrOP : out STD_LOGIC_VECTOR(4 downto 0); -- CSR operations
|
||||
O_csrAddr : out STD_LOGIC_VECTOR(11 downto 0); -- CSR address
|
||||
O_trapExit: out STD_LOGIC; -- request to exit trap handler
|
||||
O_int : out STD_LOGIC; -- is there a trap?
|
||||
O_int_data : out STD_LOGIC_VECTOR (31 downto 0); -- trap descriptor
|
||||
I_int_ack: in STD_LOGIC -- our int is now being serviced
|
||||
|
@ -46,17 +47,27 @@ entity decoder_RV32 is
|
|||
end decoder_RV32;
|
||||
|
||||
architecture Behavioral of decoder_RV32 is
|
||||
signal s_trapExit: STD_LOGIC := '0';
|
||||
signal s_csrOP : STD_LOGIC_VECTOR(4 downto 0) := (others=> '0');
|
||||
signal s_csrAddr : STD_LOGIC_VECTOR(11 downto 0) := (others=> '0');
|
||||
signal s_int : STD_LOGIC := '0';
|
||||
signal s_intdata: STD_LOGIC_VECTOR(31 downto 0) := (others=> '0');
|
||||
begin
|
||||
-- Register selects for reads are async
|
||||
O_int <= s_int;
|
||||
O_int_data <= s_intdata;
|
||||
O_csrOP <= s_csrOP;
|
||||
O_csrAddr <= s_csrAddr;
|
||||
O_trapExit <= s_trapExit;
|
||||
|
||||
-- Register selects for reads are async
|
||||
O_selRS1 <= I_dataInst(R1_START downto R1_END);
|
||||
O_selRS2 <= I_dataInst(R2_START downto R2_END);
|
||||
|
||||
process (I_clk, I_en)
|
||||
begin
|
||||
if rising_edge(I_clk) and I_int_ack = '1' then
|
||||
O_int <= '0';
|
||||
end if;
|
||||
if rising_edge(I_clk) and I_en = '1' then
|
||||
|
||||
if rising_edge(I_clk) then
|
||||
if I_en = '1' then
|
||||
|
||||
O_selD <= I_dataInst(RD_START downto RD_END);
|
||||
|
||||
|
@ -67,19 +78,25 @@ begin
|
|||
|
||||
case I_dataInst(OPCODE_START downto OPCODE_END_2) is
|
||||
when OPCODE_LUI =>
|
||||
O_int <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "00000";
|
||||
O_dataIMM <= I_dataInst(IMM_U_START downto IMM_U_END)
|
||||
& "000000000000";
|
||||
when OPCODE_AUIPC =>
|
||||
O_int <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "00000";
|
||||
O_dataIMM <= I_dataInst(IMM_U_START downto IMM_U_END)
|
||||
& "000000000000";
|
||||
when OPCODE_JAL =>
|
||||
O_int <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
if I_dataInst(RD_START downto RD_END) = "00000" then
|
||||
O_regDwe <= '0';
|
||||
else
|
||||
|
@ -92,7 +109,9 @@ begin
|
|||
O_dataIMM <= "000000000000" & I_dataInst(19 downto 12) & I_dataInst(20) & I_dataInst(30 downto 21) & '0';
|
||||
end if;
|
||||
when OPCODE_JALR =>
|
||||
O_int <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
if I_dataInst(RD_START downto RD_END) = "00000" then
|
||||
O_regDwe <= '0';
|
||||
else
|
||||
|
@ -105,7 +124,9 @@ begin
|
|||
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
end if;
|
||||
when OPCODE_OPIMM =>
|
||||
O_int <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "00000";
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
|
@ -115,20 +136,50 @@ begin
|
|||
end if;
|
||||
|
||||
when OPCODE_OP =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "00000";
|
||||
if I_dataInst(FUNCT7_START downto FUNCT7_END) = "0000001" then
|
||||
-- RV M EXTENSION - NOT SUPPORTED!
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '1';
|
||||
s_intdata <= EXCEPTION_INSTRUCTION_ILLEGAL;
|
||||
O_regDwe <= '0';
|
||||
O_memOp <= "00000";
|
||||
else
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "00000";
|
||||
end if;
|
||||
when OPCODE_LOAD =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "10" & I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
-- Load's opcode is all 0s - but the first two bits of the word should be '11'
|
||||
-- we check this here, because if we do not, null instructions will be treated as loads...
|
||||
if I_dataInst(1 downto 0) = "11" then
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '1';
|
||||
O_memOp <= "10" & I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
O_dataIMM <= X"FFFF" & "1111" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
else
|
||||
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
end if;
|
||||
else
|
||||
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
-- likely a null instruction - fault!
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '1'; ---------------
|
||||
s_intdata <= EXCEPTION_INSTRUCTION_ILLEGAL;
|
||||
O_memOp <= "00000";
|
||||
O_regDwe <= '0';
|
||||
O_dataIMM <= I_dataInst(IMM_I_START downto IMM_S_B_END)
|
||||
& "0000000";
|
||||
end if;
|
||||
when OPCODE_STORE =>
|
||||
O_int <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
O_memOp <= "11" & I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
|
@ -137,7 +188,9 @@ begin
|
|||
O_dataIMM <= X"0000" & "0000" & I_dataInst(IMM_S_A_START downto IMM_S_A_END) & I_dataInst(IMM_S_B_START downto IMM_S_B_END);
|
||||
end if;
|
||||
when OPCODE_BRANCH =>
|
||||
O_int <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
O_memOp <= "00000";
|
||||
if I_dataInst(IMM_U_START) = '1' then
|
||||
|
@ -146,10 +199,12 @@ begin
|
|||
O_dataIMM <= X"0000" & "0000" & I_dataInst(7) & I_dataInst(30 downto 25) & I_dataInst(11 downto 8) & '0';
|
||||
end if;
|
||||
when OPCODE_MISCMEM =>
|
||||
O_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
O_memOp <= "01000";
|
||||
O_dataIMM <= I_dataInst;
|
||||
O_dataIMM <= I_dataInst;
|
||||
when OPCODE_SYSTEM =>
|
||||
O_memOp <= "00000";
|
||||
if I_dataInst(FUNCT3_START downto FUNCT3_END) = F3_PRIVOP then
|
||||
|
@ -157,56 +212,69 @@ begin
|
|||
case I_dataInst(IMM_I_START downto IMM_I_END) is
|
||||
when IMM_I_SYSTEM_ECALL =>
|
||||
-- raise trap, save pc, perform requiredCSR operations
|
||||
O_int <= '1';
|
||||
O_int_data <= EXCEPTION_INT_MACHINE_SOFTWARE;
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '1';
|
||||
O_regDwe <= '0';
|
||||
s_intdata <= EXCEPTION_ENVIRONMENT_CALL_FROM_MMODE;
|
||||
--todo: Priv level needs checked as to mask this to user/supervisor/machine level
|
||||
when IMM_I_SYSTEM_EBREAK =>
|
||||
O_int <= '1';
|
||||
O_int_data <= EXCEPTION_BREAKPOINT;
|
||||
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '1';
|
||||
s_intdata <= EXCEPTION_BREAKPOINT;
|
||||
O_regDwe <= '0';
|
||||
when F7_PRIVOP_MRET & R2_PRIV_RET =>
|
||||
O_int <= '0';
|
||||
s_trapExit <= '1';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '0';
|
||||
O_regDwe <= '0';
|
||||
-- return from interrupt. implement as a branch - alu will branch to epc.
|
||||
when others =>
|
||||
end case;
|
||||
else
|
||||
O_int <= '0';
|
||||
s_trapExit <= '0';
|
||||
s_int <= '0';
|
||||
-- CSR
|
||||
-- The immediate output is the zero-extended R1 value for Imm-form CSR ops
|
||||
O_dataIMM <= X"000000" & "000" & I_dataInst(R1_START downto R1_END);
|
||||
|
||||
-- The 12bit immediate in the instruction forms the csr address.
|
||||
O_csrAddr <= I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
s_csrAddr <= I_dataInst(IMM_I_START downto IMM_I_END);
|
||||
|
||||
-- is there a destination? if not, CSR is not read
|
||||
if I_dataInst(RD_START downto RD_END) = "00000" then
|
||||
O_csrOP(0) <= '0';
|
||||
s_csrOP(0) <= '0';
|
||||
O_regDwe <= '0';
|
||||
else
|
||||
O_regDwe <= '1';
|
||||
O_csrOP(0) <= '1';
|
||||
s_csrOP(0) <= '1';
|
||||
end if;
|
||||
|
||||
-- is there source data? if not, CSR value is not written
|
||||
if I_dataInst(R1_START downto R1_END) = "00000" then
|
||||
O_csrOP(1) <= '0';
|
||||
s_csrOP(1) <= '0';
|
||||
else
|
||||
O_csrOP(1) <= '1';
|
||||
s_csrOP(1) <= '1';
|
||||
end if;
|
||||
|
||||
O_csrOp(4 downto 2) <= I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
s_csrOp(4 downto 2) <= I_dataInst(FUNCT3_START downto FUNCT3_END);
|
||||
|
||||
end if;
|
||||
when others =>
|
||||
O_int <= '1';
|
||||
O_int_data <= EXCEPTION_INSTRUCTION_ILLEGAL;
|
||||
s_trapExit <= '0';
|
||||
s_csrOP <= "00000";
|
||||
s_int <= '1'; ---------------
|
||||
s_intdata <= EXCEPTION_INSTRUCTION_ILLEGAL;
|
||||
O_memOp <= "00000";
|
||||
O_regDwe <= '0';
|
||||
O_dataIMM <= I_dataInst(IMM_I_START downto IMM_S_B_END)
|
||||
& "0000000";
|
||||
end case;
|
||||
elsif I_int_ack = '1' then
|
||||
s_int <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end Behavioral;
|
||||
|
|
Loading…
Add table
Reference in a new issue