This commit is contained in:
Yannick Reiß 2024-01-30 21:50:57 +01:00
parent 683ac9a8d4
commit 9505af3467
No known key found for this signature in database
GPG Key ID: 5A3AF456F0A0338C
10 changed files with 543 additions and 0 deletions

View File

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

42
src/Decoder.vhd Normal file
View File

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

19
src/Immediate.vhd Normal file
View File

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

40
src/ProgramCounter.vhd Normal file
View File

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

33
src/ProgramMemory.vhd Normal file
View File

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

53
src/alu.vhd Normal file
View File

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

134
src/cpu16.vhd Normal file
View File

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

107
src/ram.vhd Normal file
View File

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

48
src/ram_block.vhd Normal file
View File

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

41
src/register.vhd Normal file
View File

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