Merge branch 'main' of ssh://git.blizzard.systems:25/blizzardfinnegan/riscv32

This commit is contained in:
Blizzard Finnegan 2025-02-06 10:00:10 -05:00
commit ec65e86ba0
Signed by: blizzardfinnegan
GPG key ID: 61C1E13067E0018E
5 changed files with 88 additions and 42 deletions

View file

@ -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;

View file

@ -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) &

View file

@ -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";

View file

@ -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

View file

@ -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