Merge branch 'main' of ssh://git.blizzard.systems:25/blizzardfinnegan/riscv32
This commit is contained in:
commit
ec65e86ba0
5 changed files with 88 additions and 42 deletions
48
src/alu.vhd
48
src/alu.vhd
|
@ -6,24 +6,27 @@ USE ieee.numeric_std.ALL;
|
|||
library work;
|
||||
USE work.constants.ALL;
|
||||
|
||||
|
||||
-- Arithmetic Logic Unit
|
||||
-- Does not know how to deal with immediates, only raw values
|
||||
ENTITY alu IS
|
||||
PORT(
|
||||
-- Inputs
|
||||
-------------
|
||||
clk : IN STD_LOGIC;
|
||||
--opimm_op is converted to opcode outside
|
||||
op_flag : IN STD_LOGIC;
|
||||
op_enable : IN STD_LOGIC;
|
||||
opcode : IN STD_LOGIC_VECTOR(OPCODE_LEN DOWNTO 0);
|
||||
reg1_val : IN STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
--opimm_imm is converted to reg2_val
|
||||
reg2_val : IN STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
reg1_val : IN STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
reg2_val : IN STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
|
||||
-- Outputs
|
||||
-------------
|
||||
dest_val : OUT STD_LOGIC_VECTOR(XLENM1 DOWNTO 0)
|
||||
);
|
||||
END alu;
|
||||
|
||||
ARCHITECTURE rtl OF alu IS
|
||||
|
||||
-- Internal signals, representing each calculation
|
||||
SIGNAL add_out : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
SIGNAL sub_out : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
SIGNAL sll_out : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
|
@ -47,6 +50,7 @@ SIGNAL rem_out : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
|||
SIGNAL remu_out : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
SIGNAL shift_amt : STD_LOGIC_VECTOR(5 DOWNTO 0);
|
||||
|
||||
-- Useful constants; 1, Unsigned and Signed max and min
|
||||
CONSTANT VAL_ONE : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0) := x"00000001";
|
||||
CONSTANT VAL_UMAX : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0) := (OTHERS => '1');
|
||||
CONSTANT VAL_UMIN : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0) := (OTHERS => '0');
|
||||
|
@ -56,9 +60,12 @@ CONSTANT VAL_SMIN : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0) := (XLENM1 => '1',OTHERS =
|
|||
|
||||
BEGIN
|
||||
|
||||
--Mask away extra shift values, since our inputs are register values rather than register addresses
|
||||
shift_amt <= reg2_val(5 DOWNTO 0);
|
||||
|
||||
--RV32I base
|
||||
--RV32I base; +, -, ||, &&, XOR, Logical Shift Left (SLL), Logical shift right (SRL),
|
||||
-- arithmetic shift right (SRA), Set Less Than unsigned (SLTU), Set Less Than (SLT)
|
||||
-----------------------------
|
||||
add_out <= reg1_val + reg2_val;
|
||||
sub_out <= reg1_val - reg2_val;
|
||||
or_out <= reg1_val OR reg2_val;
|
||||
|
@ -70,19 +77,22 @@ sra_out <= std_logic_vector(shift_right(signed(reg1_val), to_integer(unsigned(sh
|
|||
sltu_out <= VAL_ONE when unsigned(reg1_val) < unsigned(reg2_val) else VAL_ZERO;
|
||||
slt_out <= VAL_ONE when signed(reg1_val) < signed(reg2_val) else VAL_ZERO;
|
||||
|
||||
|
||||
--M extension
|
||||
-----------------------------
|
||||
-- Pre-calculate for all sign variants
|
||||
raw_mul_uu <= std_logic_vector(unsigned(reg1_val) * unsigned(reg2_val));
|
||||
raw_mul_su <= std_logic_vector(signed(reg1_val) * unsigned(reg2_val));
|
||||
raw_mul_ss <= std_logic_vector(signed(reg1_val) * signed(reg2_val));
|
||||
--MUL
|
||||
--MUL (multiply)
|
||||
mul_out <= raw_mul_ss(XLENM1 DOWNTO 0);
|
||||
--MULH
|
||||
--MULH (Multiply High)
|
||||
mulh_out <= raw_mul_ss(XLENM1+XLEN DOWNTO XLEN);
|
||||
--MULHSU
|
||||
--MULHSU (Multiply High; Signed by unsigned)
|
||||
mulh_out <= raw_mul_su(XLENM1+XLEN DOWNTO XLEN);
|
||||
--MULHU
|
||||
--MULHU (Multiply High; unsigned)
|
||||
mulh_out <= raw_mul_uu(XLENM1+XLEN DOWNTO XLEN);
|
||||
--DIV
|
||||
--DIV (Divide)
|
||||
div : PROCESS(clk) BEGIN
|
||||
IF(VAL_UMIN = reg2_val) THEN
|
||||
div_out <= VAL_UMAX;
|
||||
|
@ -92,7 +102,7 @@ ELSE
|
|||
div_out <= std_logic_vector(signed(reg1_val) / signed(reg2_val));
|
||||
END IF;
|
||||
END PROCESS;
|
||||
--DIVU
|
||||
--DIVU (Divide unsigned)
|
||||
divu : PROCESS(clk) BEGIN
|
||||
IF(VAL_UMIN = reg2_val) THEN
|
||||
divu_out <= VAL_UMAX;
|
||||
|
@ -100,7 +110,7 @@ ELSE
|
|||
div_out <= std_logic_vector(unsigned(reg1_val) / unsigned(reg2_val));
|
||||
END IF;
|
||||
END PROCESS;
|
||||
--REM
|
||||
--REM (Remainder)
|
||||
rem_inst : PROCESS(clk) BEGIN
|
||||
IF(VAL_UMIN = reg2_val) THEN
|
||||
rem_out <= reg1_val;
|
||||
|
@ -109,7 +119,7 @@ ELSIF (VAL_SMAX = reg1_val AND VAL_UMAX = reg2_val) THEN
|
|||
ELSE
|
||||
rem_out <= std_logic_vector(signed(reg1_val) rem signed(reg2_val));
|
||||
END PROCESS;
|
||||
--REMU
|
||||
--REMU (Remainder unsigned)
|
||||
remu_inst : PROCESS(clk) BEGIN
|
||||
IF(VAL_UMIN = reg2_val) THEN
|
||||
remu_out <= VAL_UMIN;
|
||||
|
@ -118,11 +128,17 @@ ELSE
|
|||
END PROCESS;
|
||||
|
||||
|
||||
-- Output Implementation
|
||||
-----------------------------
|
||||
mux : PROCESS(clk) BEGIN
|
||||
IF (rising_edge(clk)) THEN
|
||||
IF '0' = op_flag THEN
|
||||
-- If we aren't supposed to be outputting a value, then don't
|
||||
IF '0' = op_enable THEN
|
||||
dest_val <= (OTHERS => '0');
|
||||
ELSE
|
||||
-- Check against internal opcode which calculation to output
|
||||
-- Not ideal, since multiplication/division is expensive compared
|
||||
-- to everything else, but this is a Proof of Concept
|
||||
CASE opcode IS
|
||||
WHEN OP_ADD => dest_val <= add_out;
|
||||
WHEN OP_SUB => dest_val <= sub_out;
|
||||
|
|
|
@ -8,24 +8,34 @@ USE riscv32.constants.ALL;
|
|||
|
||||
-- TODO: Output should be 32-bit instruction fed into the inst. decoder
|
||||
|
||||
-- Decoder of compressed instructions, as part of RVC (RISC-V Compressed instructions)
|
||||
-- All RCV instructions expand out to the base ISA, or the F/D extension's instructions
|
||||
-- This entity provides this expansion
|
||||
ENTITY compressed_decoder IS
|
||||
PORT(
|
||||
-- Inputs
|
||||
-------------
|
||||
instruction : IN STD_LOGIC_VECTOR(15 DOWNTO 0);
|
||||
clk : IN STD_LOGIC;
|
||||
|
||||
reg_dest : OUT STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
reg1 : OUT STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
reg2 : OUT STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
-- Outputs
|
||||
-------------
|
||||
reg_dest : OUT STD_LOGIC_VECTOR(ADDR_WIDTHM1 DOWNTO 0);
|
||||
reg1 : OUT STD_LOGIC_VECTOR(ADDR_WIDTHM1 DOWNTO 0);
|
||||
reg2 : OUT STD_LOGIC_VECTOR(ADDR_WIDTHM1 DOWNTO 0);
|
||||
);
|
||||
END compressed_decoder;
|
||||
|
||||
ARCHITECTURE behavioural OF compressed_decoder IS
|
||||
|
||||
-- Compressed Instructions sometimes use a register width of 3 bits,
|
||||
-- Referred to in the official documentation as rs1', rs2', rd';
|
||||
-- Common notation translates this into the word "prime"
|
||||
CONSTANT REG_PRIME_LEN : integer := 3;
|
||||
CONSTANT ILLEGAL_INST : STD_LOGIC_VECTOR(15 DOWNTO 0) := (OTHERS => '0');
|
||||
CONSTANT REG_PRIME_LENM1 : integer := REG_PRIME_LEN - 1;
|
||||
|
||||
|
||||
-- Fields defined by the RVC spec
|
||||
SIGNAL major_op : STD_LOGIC_VECTOR(1 DOWNTO 0);
|
||||
SIGNAL r2_prime : STD_LOGIC_VECTOR(REG_PRIME_LENM1 DOWNTO 0);
|
||||
SIGNAL r1_prime : STD_LOGIC_VECTOR(REG_PRIME_LENM1 DOWNTO 0);
|
||||
|
@ -34,23 +44,25 @@ SIGNAL funct4 : STD_LOGIC_VECTOR(3 DOWNTO 0);
|
|||
SIGNAL funct3 : STD_LOGIC_VECTOR(2 DOWNTO 0);
|
||||
SIGNAL funct2 : STD_LOGIC_VECTOR(1 DOWNTO 0);
|
||||
SIGNAL reg_prime : STD_LOGIC_VECTOR(REG_PRIME_LENM1 DOWNTO 0);
|
||||
SIGNAL reg_decomp : STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
SIGNAL reg_decomp : STD_LOGIC_VECTOR(ADDR_WIDTHM1 DOWNTO 0);
|
||||
|
||||
CONSTANT REG_CONVERT : STD_LOGIC_VECTOR(12 DOWNTO 0) := "000" & x"001";
|
||||
|
||||
BEGIN
|
||||
|
||||
-- See RISC-V Unprivileged ISA doc, Table 33 for definitions
|
||||
major_op <= instruction(1 DOWNTO 0);
|
||||
r2_prime <= instruction(4 DOWNTO 2);
|
||||
r1_prime <= instruction(9 DOWNTO 7);
|
||||
funct6 <= instruction(15 DOWNTO 10);
|
||||
funct4 <= instruction(15 DOWNTO 12);
|
||||
funct3 <= instruction(15 DOWNTO 13);
|
||||
funct2 <= instruciton(6 DOWNTO 5);
|
||||
funct2 <= instruction(6 DOWNTO 5);
|
||||
|
||||
|
||||
--Convert compressed register to standard:
|
||||
-- OR with x"0008"
|
||||
-- Convert compressed register to standard:
|
||||
-- Prepend the compressed register value with REG_CONVERT
|
||||
-- This corresponds 000 to Register x8/f8, 001 to x9/f9, etc
|
||||
|
||||
compressed_inst : PROCESS(clk) BEGIN
|
||||
IF(rising_edge(clk)) THEN
|
||||
|
@ -61,9 +73,10 @@ IF(rising_edge(clk)) THEN
|
|||
END IF;
|
||||
CASE funct3 IS =>
|
||||
WHEN "000" =>
|
||||
--ADDI4SPN
|
||||
--ADDI4SPN (Add Immediate [multiplied by 4] to the x2, save to rd prime)
|
||||
addi_flag <= '1';
|
||||
reg_dest <= REG_CONVERT & r2_prime;
|
||||
reg1 <= x"002";
|
||||
addi_uimm <= instruction(10 DOWNTO 7) &
|
||||
instruction(12 DOWNTO 11) &
|
||||
instruction(5) &
|
||||
|
|
|
@ -17,6 +17,10 @@ constant XLENM1: integer := XLEN - 1;
|
|||
constant FLEN : integer := 32;
|
||||
constant FLENM1 : integer := FLEN - 1;
|
||||
|
||||
-- Address width; used for defining an address vector
|
||||
CONSTANT ADDR_WIDTH : integer := 5;
|
||||
CONSTANT ADDR_WIDTHM1 : integer := ADDR_WIDTH - 1;
|
||||
|
||||
constant ADDR_RESET: std_logic_vector(XLENM1 downto 0) := X"00000000";
|
||||
constant ADDR_INTVEC: std_logic_vector(XLENM1 downto 0) := X"00000100";
|
||||
|
||||
|
|
|
@ -6,15 +6,16 @@ USE ieee.numeric_std.ALL;
|
|||
library riscv32;
|
||||
USE riscv32.constants.ALL;
|
||||
|
||||
-- RV32G Instruction decoder
|
||||
ENTITY inst_decoder IS
|
||||
PORT(
|
||||
--**********************************************************
|
||||
--Inputs
|
||||
--**********************************************************
|
||||
instruction : IN STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
clk : IN STD_LOGIC;
|
||||
--**********************************************************
|
||||
|
||||
--Outputs
|
||||
--
|
||||
--**********************************************************
|
||||
-- General use
|
||||
--These are wired to all outputs
|
||||
destination : OUT STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
|
@ -84,6 +85,7 @@ END inst_decoder;
|
|||
|
||||
ARCHITECTURE behavioural OF inst_decoder IS
|
||||
|
||||
-- See RISC-V Unprivileged ISA Documentation, section 2.3 for definitions
|
||||
SIGNAL op_code : STD_LOGIC_VECTOR(OPCODE_LEN DOWNTO 0);
|
||||
SIGNAL r_dest : STD_LOGIC_VECTOR(RD_LEN DOWNTO 0);
|
||||
SIGNAL funct3 : STD_LOGIC_VECTOR(FUNCT3_LEN DOWNTO 0);
|
||||
|
@ -98,11 +100,13 @@ SIGNAL imm_s : STD_LOGIC_VECTOR(IMM_S_LEN DOWNTO 0);
|
|||
SIGNAL imm_j : STD_LOGIC_VECTOR(IMM_J_LEN DOWNTO 0);
|
||||
SIGNAL imm_b : STD_LOGIC_VECTOR(IMM_B_LEN DOWNTO 0);
|
||||
SIGNAL funct4 : STD_LOGIC_VECTOR(FUNCT4_LEN DOWNTO 0);
|
||||
-- See definition in Unprivileged ISA doc, section 2.7
|
||||
SIGNAL fence_pred_sig: STD_LOGIC_VECTOR(FENCE_PRED_LEN DOWNTO 0);
|
||||
SIGNAL fence_succ_sig: STD_LOGIC_VECTOR(FENCE_SUCC_LEN DOWNTO 0);
|
||||
|
||||
BEGIN
|
||||
|
||||
--See Unpriv ISA doc, section 2.3
|
||||
op_code <= instruction(OPCODE_START DOWNTO OPCODE_END_2);
|
||||
r_dest <= instruction(RD_START DOWNTO RD_END);
|
||||
funct3 <= instruction(FUNCT3_START DOWNTO FUNCT3_END);
|
||||
|
@ -117,15 +121,15 @@ r3 <= instruction(R3_START DOWNTO R3_END);
|
|||
imm_i <= instruction(IMM_I_START DOWNTO IMM_I_END);
|
||||
imm_u <= instruction(IMM_U_START DOWNTO IMM_U_END);
|
||||
imm_s <= instruction(IMM_S_A_START DOWNTO IMM_S_A_END) & instruction(IMM_S_B_START DOWNTO IMM_S_B_END);
|
||||
--See Unpriv ISA doc, section 2.3
|
||||
imm_j <= instruction(31) & instruction(19 DOWNTO 12) & instruction(20) & instruction(30 DOWNTO 21);
|
||||
imm_b <= instruction(31) & instruction(7) & instruction(30 DOWNTO 25) & instruction(11 DOWNTO 8);
|
||||
|
||||
--Export internal signals
|
||||
destination <= r_dest;
|
||||
reg1 <= r1;
|
||||
reg2 <= r2;
|
||||
|
||||
|
||||
-- Main behavioural block
|
||||
op_code_inst : PROCESS(clk) BEGIN
|
||||
IF (rising_edge(clk)) THEN
|
||||
--Set all flags to 0
|
||||
|
@ -141,11 +145,13 @@ op_code_inst : PROCESS(clk) BEGIN
|
|||
op_flag <= '0';
|
||||
flop_flag <= '0';
|
||||
hflop_flag<= '0';
|
||||
IF ("11" = instruction(1 downto 0)) THEN
|
||||
-- Opcodes must have the lowest 2 bits be '11'
|
||||
IF (NOT("11" = instruction(1 downto 0))) THEN
|
||||
invalid_inst <= '1';
|
||||
exit;
|
||||
END IF;
|
||||
|
||||
-- Match to the correct op-code
|
||||
CASE op_code IS
|
||||
WHEN OPCODE_LOAD =>
|
||||
--Load to x reg
|
||||
|
|
|
@ -2,38 +2,45 @@ LIBRARY ieee;
|
|||
USE ieee.std_logic_1164.ALL;
|
||||
USE ieee.std_logic_unsigned.ALL;
|
||||
USE ieee.numeric_std.ALL;
|
||||
USE ieee.math_real.all;
|
||||
|
||||
library riscv32;
|
||||
USE riscv32.constants.ALL;
|
||||
|
||||
-- Register file that reads from 2 addresses and writes to
|
||||
-- up to 1 address every clock; register 0 always returns 0
|
||||
-- Same implementation for both float and int, Length determines
|
||||
-- Which
|
||||
-- Same implementation for both float and int; REG_ADDR_WIDTH
|
||||
-- determines the address width, REG_DATA_WIDTH determines data width
|
||||
-- REG_COUNT;
|
||||
--
|
||||
-- This register file in it's current state is not efficiently compatible with any Bitmanip extensions
|
||||
ENTITY register_file IS
|
||||
GENERIC(
|
||||
LENGTH : INTEGER
|
||||
REG_ADDR_WIDTH : INTEGER := 5;
|
||||
REG_DATA_WIDTH : INTEGER := XLENM1;
|
||||
);
|
||||
PORT(
|
||||
-- INPUTS
|
||||
clk: IN STD_LOGIC;
|
||||
write_enable: IN STD_LOGIC;
|
||||
register_addr_a: IN STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
register_addr_b: IN STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
register_write_addr: IN STD_LOGIC_VECTOR(REGLENM1 DOWNTO 0);
|
||||
write_val: IN STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
--Read addresses
|
||||
register_addr_a: IN STD_LOGIC_VECTOR(REG_ADDR_WIDTH DOWNTO 0);
|
||||
register_addr_b: IN STD_LOGIC_VECTOR(REG_ADDR_WIDTH DOWNTO 0);
|
||||
--Write address and value to write
|
||||
write_val: IN STD_LOGIC_VECTOR(REG_DATA_WIDTH DOWNTO 0);
|
||||
register_write_addr: IN STD_LOGIC_VECTOR(REG_ADDR_WIDTH DOWNTO 0);
|
||||
-- OUTPUTS
|
||||
register_a: OUT STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
register_b: OUT STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
register_a: OUT STD_LOGIC_VECTOR(REG_DATA_WIDTH DOWNTO 0);
|
||||
register_b: OUT STD_LOGIC_VECTOR(REG_DATA_WIDTH DOWNTO 0)
|
||||
);
|
||||
END integer_register_file;
|
||||
|
||||
ARCHITECTURE behavioural OF integer_register_file IS
|
||||
|
||||
TYPE register_t IS ARRAY(0 TO REGLENM1) OF STD_LOGIC_VECTOR(XLENM1 DOWNTO 0);
|
||||
TYPE register_t IS ARRAY(1 TO (2 ** REG_ADDR_WIDTH)) OF STD_LOGIC_VECTOR(REG_DATA_WIDTH DOWNTO 0);
|
||||
signal registers : register_t;
|
||||
|
||||
CONSTANT reg_zero : STD_LOGIC_VECTOR(XLENM1 DOWNTO 0) := (OTHERS => '0');
|
||||
CONSTANT reg_zero : STD_LOGIC_VECTOR(REG_ADDR_WIDTH DOWNTO 0) := (OTHERS => '0');
|
||||
|
||||
BEGIN
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue