From 9505af346774e83275e57898a128e2d766d41a6d Mon Sep 17 00:00:00 2001 From: yannickreiss Date: Tue, 30 Jan 2024 21:50:57 +0100 Subject: [PATCH] RISCV V1 --- Makefile | 26 ++++++++ src/Decoder.vhd | 42 +++++++++++++ src/Immediate.vhd | 19 ++++++ src/ProgramCounter.vhd | 40 ++++++++++++ src/ProgramMemory.vhd | 33 ++++++++++ src/alu.vhd | 53 ++++++++++++++++ src/cpu16.vhd | 134 +++++++++++++++++++++++++++++++++++++++++ src/ram.vhd | 107 ++++++++++++++++++++++++++++++++ src/ram_block.vhd | 48 +++++++++++++++ src/register.vhd | 41 +++++++++++++ 10 files changed, 543 insertions(+) create mode 100644 src/Decoder.vhd create mode 100644 src/Immediate.vhd create mode 100644 src/ProgramCounter.vhd create mode 100644 src/ProgramMemory.vhd create mode 100644 src/alu.vhd create mode 100644 src/cpu16.vhd create mode 100644 src/ram.vhd create mode 100644 src/ram_block.vhd create mode 100644 src/register.vhd diff --git a/Makefile b/Makefile index e69de29..f0e44ff 100644 --- a/Makefile +++ b/Makefile @@ -0,0 +1,26 @@ +PARTS = alu ram +CP = ghdl +FLAGS = --std=08 +ALUSRC = src/alu.vhd tb/tb_alu.vhd +RAMSRC = src/ram_block.vhd src/ram.vhd tb/rb_ram.vhd +STOP = 6000ns + +all: $(PARTS) + +alu: $(ALUSRC) + $(CP) -a $(FLAGS) $(ALUSRC) + $(CP) -e $(FLAGS) tb_$@ + $(CP) -r $(FLAGS) tb_$@ --wave=$@.ghw --stop-time=$(STOP) + +ram: $(RAMSRC) + $(CP) -a $(FLAGS) $(RAMSRC) + $(CP) -e $(FLAGS) tb_$@ + $(CP) -r $(FLAGS) tb_$@ --wave=$@.ghw --stop-time=$(STOP) + +clean: + find . -name '*.o' -exec rm -r {} \; + find . -name '*.cf' -exec rm -r {} \; + find . -name '*.ghw' -exec rm -r {} \; + find . -name '*_tb' -exec rm -r {} \; + +.PHONY: all alu clean diff --git a/src/Decoder.vhd b/src/Decoder.vhd new file mode 100644 index 0000000..6daab93 --- /dev/null +++ b/src/Decoder.vhd @@ -0,0 +1,42 @@ +-- Decoder.vhd +-- Date: Tue Jan 30 17:10:48 2024 +-- Author: Yannick Reiß +-- E-Mail: schnick@nickr.eu +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +-- Entity decode: Decoder currently supporting read operations +entity Decoder is + port( + Instruction : in std_logic_vector(15 downto 0); -- Instruction from instruction memory + AluOpcd : out std_logic_vector(3 downto 0); -- alu opcode + RegOp1 : out std_logic_vector(3 downto 0); -- Rj: first register to read + RegOp2 : out std_logic_vector(3 downto 0); -- Rk: second register to read + RegWrite : out std_logic_vector(3 downto 0) -- Ri: the register to write to + ); +end Decoder; + +architecture Implementation of Decoder is + +begin + + Decode : process(Instruction(11 downto 8), Instruction(15 downto 12), + Instruction(3 downto 0), Instruction(7 downto 4)) + begin + + -- assign the alway same positions + RegOp1 <= Instruction(11 downto 8); + RegOp2 <= Instruction(7 downto 4); + RegWrite <= Instruction(15 downto 12); + + -- Alu opcodes + case Instruction(3 downto 0) is + when "0000" | "0010" | "0011" | "0100" | "0101" | "0110" | "0111" | "1000" | "1010" => AluOpcd <= Instruction(3 downto 0); -- R-Types + when "0001" | "1001" => AluOpcd <= Instruction(7 downto 4); -- S-Types + when "1110" => AluOpcd <= Instruction(7 downto 4); -- B-Types (to be debated) + when others => AluOpcd <= "1111"; -- if unsure, do nothing + end case; + end process Decode; + +end Implementation; diff --git a/src/Immediate.vhd b/src/Immediate.vhd new file mode 100644 index 0000000..04ab1b5 --- /dev/null +++ b/src/Immediate.vhd @@ -0,0 +1,19 @@ +-- Immediate.vhd +-- Date: Tue Jan 30 20:04:49 2024 +-- Author: Yannick Reiß +-- E-Mail: schnick@nickr.eu +library IEEE; +use IEEE.std_logic_1164.all; + +entity Immediate is + port ( + ImmIn : in std_logic_vector(15 downto 0); + ImmOut : out std_logic_vector(15 downto 0) + ); +end Immediate; + +architecture Implementation of Immediate is + +begin + ImmOut <= ImmIn; +end Implementation; diff --git a/src/ProgramCounter.vhd b/src/ProgramCounter.vhd new file mode 100644 index 0000000..0cda430 --- /dev/null +++ b/src/ProgramCounter.vhd @@ -0,0 +1,40 @@ +-- ProgramCounter.vhd +-- Date: Tue Jan 30 20:54:56 2024 +-- Author: Yannick Reiß +-- E-Mail: schnick@nickr.eu +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity ProgramCounter is + port( + Clk : in std_logic; + PcEnable : in std_logic; + AddrCalc : in std_logic_vector(15 downto 0); + Jump : in std_logic; + Addr : out std_logic_vector(15 downto 0) + ); +end ProgramCounter; + +architecture Implementation of ProgramCounter is + signal Address : std_logic_vector(15 downto 0) := (others => '0'); + signal AddressPlus : std_logic_vector(15 downto 0) := (others => '0'); +begin + + UpdatePc : process(Clk) + begin + if rising_edge(Clk) then + if PcEnable = '1' then + if Jump = '1' then + Address <= AddrCalc; + else + Address <= AddressPlus; + end if; + end if; + end if; + end process UpdatePc; + + AddressPlus <= (std_logic_vector(to_unsigned(to_integer(unsigned(Address)) + 1, 16))); + Addr <= Address; + +end Implementation; diff --git a/src/ProgramMemory.vhd b/src/ProgramMemory.vhd new file mode 100644 index 0000000..adc2c11 --- /dev/null +++ b/src/ProgramMemory.vhd @@ -0,0 +1,33 @@ +-- ProgramMemory.vhd +-- Date: Tue Jan 30 17:01:12 2024 +-- Author: Yannick Reiß +-- E-Mail: schnick@nickr.eu +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity ProgramMemory is + port( + Clk : in std_logic; + InstrAddr : in std_logic_vector(15 downto 0); + Instruction : out std_logic_vector(15 downto 0); + Immediate : out std_logic_vector(15 downto 0) + ); +end ProgramMemory; + +architecture Implementation of ProgramMemory is + type MemoryType is array(0 to 65536) of std_logic_vector(15 downto 0); + signal Memory : MemoryType := (others => (others => '0')); +begin + + SynchronRead : process(Clk) + begin + + if rising_edge(Clk) then + Instruction <= Memory(to_integer(unsigned(InstrAddr))); + Immediate <= Memory(to_integer(unsigned(InstrAddr) + 1)); + end if; + + end process SynchronRead; + +end Implementation; diff --git a/src/alu.vhd b/src/alu.vhd new file mode 100644 index 0000000..0baa53b --- /dev/null +++ b/src/alu.vhd @@ -0,0 +1,53 @@ +-- alu.vhd +-- Date: Tue Jan 30 10:02:24 2024 +-- Author: Yannick Reiß +-- E-Mail: yannick.reiss@protonmail.ch +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity Alu is + port ( + alu_op : in std_logic_vector(3 downto 0); + input1 : in std_logic_vector(15 downto 0); + input2 : in std_logic_vector(15 downto 0); + result : out std_logic_vector(15 downto 0) + ); +end Alu; + +architecture Implementation of Alu is + +begin + Alu_logic : process(alu_op, input1, input2) + begin + case alu_op is + when "0000" => result <= std_logic_vector(unsigned(input1) + unsigned(input2)); +-- ADD + when "0010" => result <= std_logic_vector(signed(input1) - signed(input2)); +-- SUB + when "0011" => result <= std_logic_vector(unsigned(input1) sll to_integer(unsigned(input2))); +-- SLL + when "0100" => + if (signed(input1) < signed(input2)) then + result <= std_logic_vector(to_unsigned(1, 16)); + else + result <= std_logic_vector(to_unsigned(0, 16)); + end if; -- SLT + when "0101" => + if (unsigned(input1) < unsigned(input2)) then + result <= std_logic_vector(to_unsigned(1, 16)); + else + result <= std_logic_vector(to_unsigned(0, 16)); + end if; -- SLTU + when "0110" => result <= input1 xor input2; -- XOR + when "0111" => result <= std_logic_vector(unsigned(input1) srl to_integer(unsigned(input2))); +-- SRL + when "1000" => result <= std_logic_vector(signed(input1) sra to_integer(unsigned(input2))); +-- SRA + when "1010" => result <= input1 or input2; -- OR + when "1011" => result <= input1 and input2; -- AND + when others => result <= std_logic_vector(to_unsigned(0, 16)); + end case; + end process Alu_logic; + +end Implementation; diff --git a/src/cpu16.vhd b/src/cpu16.vhd new file mode 100644 index 0000000..ad7b7e7 --- /dev/null +++ b/src/cpu16.vhd @@ -0,0 +1,134 @@ +-- cpu16.vhd +-- Date: Tue Jan 30 15:19:09 2024 +-- Author: Yannick Reiß +-- E-Mail: schnick@nickr.eu +library IEEE; +use IEEE.std_logic_1164.all; + +entity Cpu16 is + port ( + Clk : in std_logic; + Switches : in std_logic_vector(15 downto 0); + SDA : inout std_logic; + SDL : inout std_logic; + LED : out std_logic_vector(15 downto 0); + RGB : out std_logic_vector(7 downto 0) + ); +end Cpu16; + +architecture Implementation of Cpu16 is + + signal RamAddrA : std_logic_vector(15 downto 0) := (others => '0'); + signal RamAddrB : std_logic_vector(15 downto 0) := (others => '0'); + signal RamWriteEnable : std_logic := '0'; + signal RamDataWrite : std_logic_vector(15 downto 0) := (others => '0'); + signal RamReadA : std_logic_vector(15 downto 0) := (others => '0'); + signal RamReadB : std_logic_vector(15 downto 0) := (others => '0'); + signal AluOpcode : std_logic_vector(3 downto 0) := "1111"; -- Some nop operation + signal AluIn1 : std_logic_vector(15 downto 0) := (others => '0'); + signal AluIn2 : std_logic_vector(15 downto 0) := (others => '0'); + signal AluResult : std_logic_vector(15 downto 0) := (others => '0'); + signal RegisterWriteEnable : std_logic := '0'; + signal RegisterRegister1 : std_logic_vector(3 downto 0) := (others => '0'); + signal RegisterRegister2 : std_logic_vector(3 downto 0) := (others => '0'); + signal RegisterRegisterW : std_logic_vector(3 downto 0) := (others => '0'); + signal RegisterDataIn : std_logic_vector(15 downto 0) := (others => '0'); + signal RegisterDataOut1 : std_logic_vector(15 downto 0) := (others => '0'); + signal RegisterDataOut2 : std_logic_vector(15 downto 0) := (others => '0'); + signal InstructionCounter : std_logic_vector(15 downto 0) := (others => '0'); + signal RawInstruction : std_logic_vector(15 downto 0) := (others => '0'); + signal DecoderRegOp1 : std_logic_vector(3 downto 0) := (others => '0'); + signal DecoderRegOp2 : std_logic_vector(3 downto 0) := (others => '0'); + signal DecoderRegWrite : std_logic_vector(3 downto 0) := (others => '0'); + signal NextInstruction : std_logic_vector(15 downto 0) := (others => '0'); + signal ImmediateValue : std_logic_vector(15 downto 0) := (others => '0'); + signal PcEnable : std_logic := '0'; + signal Jump : std_logic := '0'; +begin + + -- Include Entities + Ramblock : entity work.Ram(Behavioral) + port map( + Clk => Clk, + AddrA => RamAddrA, + AddrB => RamAddrB, + WriteEnable => RamWriteEnable, + DataIn => RamDataWrite, + ReadA => RamReadA, + ReadB => RamReadB, + DirectIn => Switches, + DirectOut => LED + ); + + Alu : entity work.Alu(Implementation) + port map( + alu_op => AluOpcode, + input1 => AluIn1, + input2 => AluIn2, + result => AluResult + ); + + Regs : entity work.Registerset(Implementation) + port map( + Clk => Clk, + WriteEnable => RegisterWriteEnable, + Register1 => RegisterRegister1, + Register2 => RegisterRegister2, + RegisterW => RegisterRegisterW, + DataIn => RegisterDataIn, + DataOut1 => RegisterDataOut1, + DataOut2 => RegisterDataOut2 + ); + + Instructions : entity work.ProgramMemory(Implementation) + port map( + Clk => Clk, + InstrAddr => InstructionCounter, + Instruction => RawInstruction, + Immediate => NextInstruction + ); + + Decoder : entity work.Decoder(Implementation) + port map( + Instruction => RawInstruction, + AluOpcd => AluOpcode, + RegOp1 => RegisterRegister1, + RegOp2 => RegisterRegister2, + RegWrite => RegisterRegisterW + ); + + ImmUseless : entity work.Immediate(Implementation) + port map( + ImmIn => NextInstruction, + ImmOut => ImmediateValue + ); + + PC : entity work.ProgramCounter(Implementation) + port map( + Clk => Clk, + PcEnable => PcEnable, + AddrCalc => AluResult, + Jump => Jump, + Addr => InstructionCounter + ); + + AluSetInput : process(ImmediateValue, InstructionCounter, RegisterDataOut1, + RegisterDataOut2) + begin + + case RawInstruction(3 downto 0) is + when "0000" | "0010" | "0011" | "0100" | "0101" | "0110" | "0111" | "1000" | "1010" | "1110" => AluIn1 <= RegisterDataOut1; + AluIn2 <= RegisterDataOut2; + when "0001" | "1001" => AluIn1 <= RegisterDataOut1; + AluIn2 <= ImmediateValue; + when others => AluIn1 <= InstructionCounter; + AluIn2 <= RegisterDataOut2; + + + end case; + end process AluSetInput; + + + RGB <= Switches(7 downto 0); + +end Implementation; diff --git a/src/ram.vhd b/src/ram.vhd new file mode 100644 index 0000000..91702db --- /dev/null +++ b/src/ram.vhd @@ -0,0 +1,107 @@ +-- ram.vhd +-- Date: Tue Jan 30 12:26:41 2024 +-- Author: Yannick Reiß +-- E-Mail: yannick.reiss@protonmail.ch +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity Ram is + port( + Clk : in std_logic; + AddrA : in std_logic_vector(15 downto 0); + AddrB : in std_logic_vector(15 downto 0); + WriteEnable : in std_logic; + DataIn : in std_logic_vector(15 downto 0); + ReadA : out std_logic_vector(15 downto 0); + ReadB : out std_logic_vector(15 downto 0); + DirectIn : in std_logic_vector(15 downto 0); + DirectOut : out std_logic_vector(15 downto 0) + ); +end Ram; + +architecture Behavioral of Ram is + + signal we1 : std_logic := '0'; + signal we2 : std_logic := '0'; + + signal SReadA1 : std_logic_vector(15 downto 0) := (others => '0'); + signal SReadB1 : std_logic_vector(15 downto 0) := (others => '0'); + + signal SReadA2 : std_logic_vector(15 downto 0) := (others => '0'); + signal SReadB2 : std_logic_vector(15 downto 0) := (others => '0'); + + signal Mode1 : std_logic := '1'; + signal Mode2 : std_logic := '0'; + signal ZeroWord : std_logic_vector(15 downto 0) := (others => '0'); + + signal BoardInput : std_logic_vector(15 downto 0) := (others => '0'); + signal BoardOutput : std_logic_vector(15 downto 0) := (others => '0'); +begin + + block1 : entity work.Ram_Block(Memory) + port map( + Clk => Clk, + WriteEnable => we1, + AddrA => AddrA(14 downto 0), + AddrB => AddrB(14 downto 0), + Input => DataIn, + ReadA => SReadA1, + ReadB => SReadB1 + ); + + block2 : entity work.Ram_Block(Memory) + port map( + Clk => Clk, + WriteEnable => we2, + AddrA => AddrA(14 downto 0), + AddrB => AddrB(14 downto 0), + Input => DataIn, + ReadA => SReadA2, + ReadB => SReadB2 + ); + + -- Set write enable + we1 <= WriteEnable and not AddrA(15); + we2 <= WriteEnable and AddrA(15); + + DirectIO : process(clk) + begin + + if rising_edge(clk) then + -- must be treated as register + BoardInput <= DirectIn; + + -- handle Directin + if unsigned(AddrA) = 1 then + ReadA <= BoardInput; + else + case AddrA(15) is + when '1' => + ReadA <= SReadA2; + when others => ReadA <= SReadA1; + end case; + end if; + + if unsigned(AddrB) = 1 then + ReadB <= BoardInput; + else + case AddrB(15) is + when '1' => + ReadB <= SReadB2; + + when others => ReadB <= SReadB1; + end case; + end if; + + -- handle Directout + if unsigned(AddrB) = 2 and WriteEnable = '1' then + BoardOutput <= DataIn; + end if; + + end if; + end process DirectIO; + + DirectOut <= BoardOutput; + +end Behavioral; diff --git a/src/ram_block.vhd b/src/ram_block.vhd new file mode 100644 index 0000000..39dbde6 --- /dev/null +++ b/src/ram_block.vhd @@ -0,0 +1,48 @@ +-- ram_block.vhd +-- Date: Tue Jan 30 11:18:02 2024 +-- Author: Yannick Reiß +-- E-Mail: yannick.reiss@protonmail.ch +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity Ram_Block is + port ( + Clk : in std_logic; + WriteEnable : in std_logic; + AddrA : in std_logic_vector(14 downto 0); + AddrB : in std_logic_vector(14 downto 0); + Input : in std_logic_vector(15 downto 0); + ReadA : out std_logic_vector(15 downto 0); + ReadB : out std_logic_vector(15 downto 0) + ); +end Ram_Block; + +architecture Memory of Ram_Block is + + type MemBlock is array(0 to 32768) of std_logic_vector(15 downto 0); + + signal Store : MemBlock := (others => (others => '0')); + signal RegA : std_logic_vector(15 downto 0) := (others => '0'); + signal RegB : std_logic_vector(15 downto 0) := (others => '0'); +begin + + ReadWrite : process(Clk) + begin + + if rising_edge(Clk) then + + if WriteEnable = '1' then + Store(to_integer(unsigned(AddrB))) <= Input; + end if; + + RegA <= Store(to_integer(unsigned(AddrA))); + RegB <= Store(to_integer(unsigned(AddrB))); + + end if; + end process ReadWrite; + + ReadA <= RegA; + ReadB <= RegB; + +end Memory; diff --git a/src/register.vhd b/src/register.vhd new file mode 100644 index 0000000..97eec15 --- /dev/null +++ b/src/register.vhd @@ -0,0 +1,41 @@ +-- register.vhd +-- Date: Tue Jan 30 14:47:16 2024 +-- Author: Yannick Reiß +-- E-Mail: schnick@nickr.eu +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +entity Registerset is + port( + Clk : in std_logic; + WriteEnable : in std_logic; + Register1 : in std_logic_vector(3 downto 0); + Register2 : in std_logic_vector(3 downto 0); + RegisterW : in std_logic_vector(3 downto 0); + DataIn : in std_logic_vector(15 downto 0); + DataOut1 : out std_logic_vector(15 downto 0); + DataOut2 : out std_logic_vector(15 downto 0) + ); +end Registerset; + +architecture Implementation of Registerset is + type RegisterBlock is array(0 to 15) of std_logic_vector(15 downto 0); + signal Registers : RegisterBlock := (others => (others => '0')); + +begin + + WriteRegister : process(Clk) + begin + + if rising_edge(Clk) then + if WriteEnable = '1' and unsigned(RegisterW) > 0 then + Registers (to_integer(unsigned(RegisterW))) <= DataIn; + end if; + end if; + end process WriteRegister; + + DataOut1 <= Registers(to_integer(unsigned(Register1))); + DataOut2 <= Registers(to_integer(unsigned(Register2))); + +end Implementation;