diff --git a/Makefile b/Makefile index 0f0645b..b3e3553 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ FMT_SRC := $(patsubst %, fmt-%,$(VHDL_SRC) $(VHDL_TEST_SRC)) export GHDL_FLAGS := compile --std=08 # GHDL_FLAGS += -frelaxed +export RUN_FLAGS := --ieee-asserts=disable # If you wanna silence annoying errors # export RUN_FLAGS := --assert-level=warning # If you wanna be super strict test: $(VHDL_TEST_BENCHES) @@ -31,6 +32,14 @@ rtl/core/rom_pkg.vhd: scripts/asm/main.go \ %_tb: $(TEST_DIR)/%_tb.vhd $(SRC_DIR)/%.vhd @TB="$@" ./scripts/run_test.sh $^ +_CONTROLLER := control_fsm \ + fysh_fyve_pkg \ + +CONTROLLER := $(patsubst %, $(SRC_DIR)/%.vhd, $(_CONTROLLER)) + +control_fsm_tb: $(TEST_DIR)/control_fsm_tb.vhd $(CONTROLLER) + @TB="$@" ./scripts/run_test.sh $^ + _ALU := alu \ fysh_fyve_pkg \ diff --git a/docs/controller.md b/docs/controller.md index 76363cc..869ef7c 100644 --- a/docs/controller.md +++ b/docs/controller.md @@ -20,5 +20,12 @@ done_o : out std_logic | ----------- | ------- | ------- | ---- | ----- | ----- | ------------ | ------ | ------ | ------ | ------ | ------- | ---- | | lui | 01 | 0 | 1 | [1] | 1 | 0 | dr | dr | dr | 1 | 0 | 0 | | auipc | 01 | 0 | 1 | 1 | 1 | 0 | dr | dr | dr | 0 | 0 | 0 | +| addi | 01 | 0 | 1 | 0 | 1 | 0 | dr | dr | dr | 1 | 0 | 0 | + +| A | B | A ^ B | +| ----- | ------------------ | -------- | +| lui | auipc | bit 5 | -- LUI is just immediate +| auipc | register-immediate | bit 2 | +| lui | register-immediate | bit 2, 5 | [^1] This somehow has to be pointing to 0! how? and the op bits should be add! diff --git a/docs/rv32i-timing.pdf b/docs/rv32i-timing.pdf new file mode 100644 index 0000000..0972407 Binary files /dev/null and b/docs/rv32i-timing.pdf differ diff --git a/rtl/core/alu_control.vhd b/rtl/core/alu_control.vhd index 1f8bee5..d35c4f7 100644 --- a/rtl/core/alu_control.vhd +++ b/rtl/core/alu_control.vhd @@ -47,10 +47,13 @@ architecture rtl of alu_control is signal lt : std_ulogic := '0'; signal ltu : std_ulogic := '0'; + signal rs1_or_zero : std_ulogic_vector (31 downto 0) := (others => '0'); + signal alu_a_sel : std_ulogic := '0'; signal alu_b_sel : std_ulogic := '0'; signal addr_sel : std_ulogic := '0'; + signal rd_clk : std_ulogic := '0'; signal rd_sel : std_ulogic_vector (1 downto 0) := (others => '0'); signal alu : std_ulogic_vector (31 downto 0) := (others => '0'); signal pc : std_ulogic_vector (31 downto 0) := (others => '0'); @@ -63,8 +66,20 @@ begin if rising_edge(clk_i) then write(l, string'("pc_clk: ")); write(l, pc_clk); + write(l, string'(" rd_clk: ")); + write(l, rd_clk); write(l, string'(" pc: ")); write(l, to_hstring(pc)); + write(l, string'(" instruction_i: ")); + write(l, to_hstring(instruction_i)); + write(l, string'(" func3: ")); + write(l, instruction_i(14 downto 12)); + write(l, string'(" alu_a_op: ")); + write(l, to_hstring(alu_a_op)); + write(l, string'(" alu_b_op: ")); + write(l, to_hstring(alu_b_op)); + write(l, string'(" alu_o: ")); + write(l, to_hstring(alu_o)); writeline(output, l); end if; end process print; @@ -73,6 +88,11 @@ begin instruction_i => instruction_i, imm_val_o => imm_ex); + -- Hacky way to make rs1_val hardwire to 0 + with instruction_i(6 downto 0) select rs1_or_zero <= + (others => '0') when "0110111", + reg_val_1_i when others; + program_counter_inst : entity work.program_counter(rtl) port map ( pc_clk_i => pc_clk, reset_i => reset_i, @@ -111,19 +131,20 @@ begin alu_b_sel_o => alu_b_sel, rd_sel_o => rd_sel, mem_write_en_o => mem_write_en_o, - rd_clk_o => rd_clk_o, + rd_clk_o => rd_clk, pc_clk_o => pc_clk, ir_clk_o => ir_clk_o, pc_alu_sel_o => pc_alu_sel, pc_next_sel_o => pc_next_sel); addr_sel_o <= addr_sel; + rd_clk_o <= rd_clk; rd_sel_o <= rd_sel; alu_o <= alu; pc_o <= pc; with alu_a_sel select alu_a_op <= - reg_val_1_i when '0', + rs1_or_zero when '0', pc when '1', (others => 'X') when others; diff --git a/rtl/core/control_fsm.vhd b/rtl/core/control_fsm.vhd index 6758420..5c0c103 100644 --- a/rtl/core/control_fsm.vhd +++ b/rtl/core/control_fsm.vhd @@ -3,6 +3,7 @@ --! @cond Doxygen_Suppress library ieee; use ieee.std_logic_1164.all; +use work.fysh_fyve.all; --! @endcond --! The Big Brain of the CPU.\n @@ -37,52 +38,79 @@ entity control_fsm is end control_fsm; architecture rtl of control_fsm is - type state_t is (decode, drive, done); + type state_t is (init, decode, drive, done); signal pc_clk : std_ulogic := '0'; signal ir_clk : std_ulogic := '0'; + signal rd_clk : std_ulogic := '0'; signal mem_write_en : std_ulogic := '0'; - signal state : state_t := decode; + signal write_mem : std_ulogic := '0'; + signal write_reg : std_ulogic := '0'; + + signal state : state_t := init; begin + alu_a_sel_o <= opcode_i(2) and not opcode_i(5); + alu_b_sel_o <= opcode_i(2) or not opcode_i(5); + addr_sel_o <= '1'; + + with opcode_i(2) select op_bits_o <= + OP_OR when '1', + op_bits_i(2 downto 0) when others; + sub_sra_o <= sub_sra_i and not opcode_i(2); drive_clock : process(clk_i, halt_i, opcode_i, pc_clk, ir_clk, mem_write_en) use std.textio.all; variable l : line; begin if falling_edge(reset_i) then - state <= decode; + state <= init; done_o <= '0'; elsif rising_edge(halt_i) then state <= done; - elsif clk_i'event then + elsif rising_edge(clk_i) then --! TODO: Decode kinda like 410 case state is + when init => + state <= decode; when decode => - alu_b_sel_o <= not opcode_i(5); -- immediate value ('1') or rs2 ('0') - -- TODO: Figure this out - alu_a_sel_o <= opcode_i(0); -- pc ('1') or rs1 ('0') - addr_sel_o <= opcode_i(0); -- alu ('1') or pc ('0') - pc_alu_sel_o <= '1'; -- 4 ('1') or immediate value ('0') - pc_next_sel_o <= opcode_i(0); -- alu ('1') or pc alu ('0') - rd_sel_o <= opcode_i(1 downto 0); -- mem_sx ("11"), alu ("01"), or pc alu ("00") - - sub_sra_o <= sub_sra_i; - op_bits_o <= op_bits_i(2 downto 0); - - -- TODO!! - rd_clk_o <= opcode_i(0); - state <= drive; + case opcode_i(2) is + when '1' => -- LUI/AUIPC (for now!) + -- TODO: Handle the case where it's not! + rd_sel_o <= "01"; + write_reg <= '1'; + pc_alu_sel_o <= '1'; + pc_next_sel_o <= '0'; + when others => -- The typical ALU stuff + rd_sel_o <= "01"; -- mem_sx ("11"), alu ("01"), or pc alu ("00") + write_reg <= '1'; + pc_alu_sel_o <= '1'; -- 4 ('1') or immediate value ('0') + pc_next_sel_o <= '0'; -- alu ('1') or pc alu ('0') + end case; + mem_write_en <= '0'; + rd_clk <= '0'; + ir_clk <= '1'; + pc_clk <= '0'; + state <= drive; when drive => - pc_clk <= not pc_clk; - ir_clk <= not ir_clk; - mem_write_en <= not mem_write_en; - state <= decode; + if (write_mem = '1') then + mem_write_en <= '1'; + write_mem <= '0'; + end if; + if (write_reg = '1') then + rd_clk <= '1'; + write_reg <= '0'; + end if; + ir_clk <= '0'; + pc_clk <= '1'; + state <= decode; when done => done_o <= '1'; end case; end if; - pc_clk_o <= pc_clk; - ir_clk_o <= ir_clk; - mem_write_en_o <= mem_write_en; end process drive_clock; + + rd_clk_o <= rd_clk; + pc_clk_o <= pc_clk; + ir_clk_o <= ir_clk; + mem_write_en_o <= mem_write_en; end rtl; diff --git a/rtl/core/memory.vhd b/rtl/core/memory.vhd index 4ad6f22..1ed2875 100644 --- a/rtl/core/memory.vhd +++ b/rtl/core/memory.vhd @@ -32,14 +32,14 @@ architecture rtl of memory is signal addr, mem_out, mem_sx : std_ulogic_vector (31 downto 0); signal reg_val_1, reg_val_2 : std_ulogic_vector (31 downto 0); begin - wtf : process(insn_o) - use std.textio.all; - variable l : line; - begin - write(l, string'("insn_o: ")); - write(l, insn_o); - writeline(output, l); - end process wtf; + -- wtf : process(insn_o) + -- use std.textio.all; + -- variable l : line; + -- begin + -- write(l, string'("insn_o: ")); + -- write(l, insn_o); + -- writeline(output, l); + -- end process wtf; mem_inst : entity work.phy_map(rtl) port map ( clk_i => clk_i, @@ -66,7 +66,8 @@ begin reg_val_2_o <= reg_val_2; reg_val_1_o <= reg_val_1; - insn_o <= insn; + + insn_o <= insn; with addr_sel_i select addr <= pc_out_i when '1', diff --git a/rtl/core/program_counter.vhd b/rtl/core/program_counter.vhd index 7812614..0e393d7 100644 --- a/rtl/core/program_counter.vhd +++ b/rtl/core/program_counter.vhd @@ -51,12 +51,12 @@ begin use std.textio.all; variable l : line; begin - write(l, string'("next_ins: ")); - write(l, to_hstring(next_ins)); - writeline(output, l); if falling_edge(reset_i) then pc <= (others => '0'); - elsif pc_clk_i'event then + elsif rising_edge(pc_clk_i) then + write(l, string'("next_ins: ")); + write(l, to_hstring(next_ins)); + writeline(output, l); pc <= next_ins; end if; end process; diff --git a/rtl/core/register_file.vhd b/rtl/core/register_file.vhd index f710498..8f5a328 100644 --- a/rtl/core/register_file.vhd +++ b/rtl/core/register_file.vhd @@ -31,11 +31,18 @@ begin registers_g : for i in 1 to 31 generate register_write : process(reset_i, rd_clk_i) + use std.textio.all; + variable l : line; begin if falling_edge(reset_i) then reg_file(i) <= (others => '0'); elsif rising_edge(rd_clk_i) then if (i = to_integer(unsigned(dest_reg_i))) then + write(l, string'("wrote value ")); + write(l, to_hstring(dest_reg_val_i)); + write(l, string'(" to register")); + write(l, i); + writeline(output, l); reg_file(i) <= dest_reg_val_i; end if; end if; diff --git a/rtl/test/alu_control_tb.vhd b/rtl/test/alu_control_tb.vhd index e58b02d..caab915 100644 --- a/rtl/test/alu_control_tb.vhd +++ b/rtl/test/alu_control_tb.vhd @@ -27,6 +27,8 @@ architecture test_bench of alu_control_tb is signal rd_sel : std_ulogic_vector (1 downto 0) := (others => '0'); signal reset : std_ulogic := '0'; signal addr_sel : std_ulogic := '0'; + + signal rs1_or_zero : std_ulogic_vector (31 downto 0); begin clock : process begin @@ -34,11 +36,12 @@ begin wait for 1 ns; end process clock; + alu_control_inst : entity work.alu_control(rtl) port map ( clk_i => clk, reset_i => reset, instruction_i => insn, - reg_val_1_i => rs1_val, + reg_val_1_i => rs1_or_zero, reg_val_2_i => rs2_val, alu_o => alu, pc_o => pc, diff --git a/rtl/test/topmodule_tb.vhd b/rtl/test/topmodule_tb.vhd index dde6326..0c0d0e1 100644 --- a/rtl/test/topmodule_tb.vhd +++ b/rtl/test/topmodule_tb.vhd @@ -31,7 +31,11 @@ begin reset <= '0'; wait for 1 ns; reset <= '1'; - wait for 10 ns; + wait for 1 ns; + reset <= '0'; + wait for 1 ns; + reset <= '1'; + wait for 30 ns; stop; end process; end test_bench;