From b103d820a57859fc4aad48f50029e12cc1db7611 Mon Sep 17 00:00:00 2001 From: Bert Lange Date: Tue, 1 Mar 2011 17:36:01 +0100 Subject: beautify Signed-off-by: Bert Lange --- zpu/hdl/zpu4/core/zpu_config.vhd | 32 +- zpu/hdl/zpu4/core/zpu_core.vhd | 1820 ++++++++++++++++++---------------- zpu/hdl/zpu4/core/zpu_core_small.vhd | 1065 ++++++++++---------- zpu/hdl/zpu4/core/zpupkg.vhd | 338 ++++--- 4 files changed, 1679 insertions(+), 1576 deletions(-) diff --git a/zpu/hdl/zpu4/core/zpu_config.vhd b/zpu/hdl/zpu4/core/zpu_config.vhd index 4fecf01..112dd01 100644 --- a/zpu/hdl/zpu4/core/zpu_config.vhd +++ b/zpu/hdl/zpu4/core/zpu_config.vhd @@ -39,19 +39,21 @@ use ieee.std_logic_unsigned.all; use ieee.std_logic_arith.all; package zpu_config is - -- generate trace output or not. - constant Generate_Trace : boolean := false; - constant wordPower : integer := 5; - -- during simulation, set this to '0' to get matching trace.txt - constant DontCareValue : std_logic := 'X'; - -- Clock frequency in MHz. - constant ZPU_Frequency : std_logic_vector(7 downto 0) := x"64"; - -- This is the msb address bit. bytes=2^(maxAddrBitIncIO+1) - constant maxAddrBitIncIO : integer := 15; - constant maxAddrBitBRAM : integer := 14; - - -- start byte address of stack. - -- point to top of RAM - 2*words - constant spStart : std_logic_vector(maxAddrBitIncIO downto 0) := - conv_std_logic_vector((2**(maxAddrBitBRAM+1))-8, maxAddrBitIncIO+1); + + -- generate trace output or not. + constant Generate_Trace : boolean := false; + constant wordPower : integer := 5; + -- during simulation, set this to '0' to get matching trace.txt + constant DontCareValue : std_logic := 'X'; + -- Clock frequency in MHz. + constant ZPU_Frequency : std_logic_vector(7 downto 0) := x"64"; + -- This is the msb address bit. bytes=2^(maxAddrBitIncIO+1) + constant maxAddrBitIncIO : integer := 15; + constant maxAddrBitBRAM : integer := 14; + + -- start byte address of stack. + -- point to top of RAM - 2*words + constant spStart : std_logic_vector(maxAddrBitIncIO downto 0) := + conv_std_logic_vector((2**(maxAddrBitBRAM+1))-8, maxAddrBitIncIO+1); + end zpu_config; diff --git a/zpu/hdl/zpu4/core/zpu_core.vhd b/zpu/hdl/zpu4/core/zpu_core.vhd index 69da686..ff9449f 100644 --- a/zpu/hdl/zpu4/core/zpu_core.vhd +++ b/zpu/hdl/zpu4/core/zpu_core.vhd @@ -33,8 +33,8 @@ -- are those of the authors and should not be interpreted as representing -- official policies, either expressed or implied, of the ZPU Project. -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; +library ieee; +use ieee.std_logic_1164.all; use ieee.numeric_std.all; library work; @@ -58,899 +58,957 @@ use work.zpupkg.all; -- write request -- break - set to '1' when CPU hits break instruction -- interrupt - set to '1' until interrupts are cleared by CPU. - + entity zpu_core is - Port ( clk : in std_logic; - areset : in std_logic; - enable : in std_logic; - in_mem_busy : in std_logic; - mem_read : in std_logic_vector(wordSize-1 downto 0); - mem_write : out std_logic_vector(wordSize-1 downto 0); - out_mem_addr : out std_logic_vector(maxAddrBitIncIO downto 0); - out_mem_writeEnable : out std_logic; - out_mem_readEnable : out std_logic; - mem_writeMask: out std_logic_vector(wordBytes-1 downto 0); - interrupt : in std_logic; - break : out std_logic); + port ( + clk : in std_logic; + areset : in std_logic; + enable : in std_logic; + in_mem_busy : in std_logic; + mem_read : in std_logic_vector(wordSize-1 downto 0); + mem_write : out std_logic_vector(wordSize-1 downto 0); + out_mem_addr : out std_logic_vector(maxAddrBitIncIO downto 0); + out_mem_writeEnable : out std_logic; + out_mem_readEnable : out std_logic; + mem_writeMask : out std_logic_vector(wordBytes-1 downto 0); + interrupt : in std_logic; + break : out std_logic + ); end zpu_core; architecture behave of zpu_core is -type InsnType is -( -State_AddTop, -State_Dup, -State_DupStackB, -State_Pop, -State_Popdown, -State_Add, -State_Or, -State_And, -State_Store, -State_AddSP, -State_Shift, -State_Nop, -State_Im, -State_LoadSP, -State_StoreSP, -State_Emulate, -State_Load, -State_PushPC, -State_PushSP, -State_PopPC, -State_PopPCRel, -State_Not, -State_Flip, -State_PopSP, -State_Neqbranch, -State_Eq, -State_Loadb, -State_Mult, -State_Lessthan, -State_Lessthanorequal, -State_Ulessthanorequal, -State_Ulessthan, -State_Pushspadd, -State_Call, -State_Callpcrel, -State_Sub, -State_Break, -State_Storeb, -State_InsnFetch -); - -type StateType is -( -State_Load2, -State_Popped, -State_LoadSP2, -State_LoadSP3, -State_AddSP2, -State_Fetch, -State_Execute, -State_Decode, -State_Decode2, -State_Resync, - -State_StoreSP2, -State_Resync2, -State_Resync3, -State_Loadb2, -State_Storeb2, -State_Mult2, -State_Mult3, -State_Mult5, -State_Mult4, -State_BinaryOpResult2, -State_BinaryOpResult, -State_Idle, -State_Interrupt -); - - -signal pc : unsigned(maxAddrBitIncIO downto 0); -signal sp : unsigned(maxAddrBitIncIO downto minAddrBit); -signal incSp : unsigned(maxAddrBitIncIO downto minAddrBit); -signal incIncSp : unsigned(maxAddrBitIncIO downto minAddrBit); -signal decSp : unsigned(maxAddrBitIncIO downto minAddrBit); -signal stackA : unsigned(wordSize-1 downto 0); -signal binaryOpResult : unsigned(wordSize-1 downto 0); -signal binaryOpResult2 : unsigned(wordSize-1 downto 0); -signal multResult2 : unsigned(wordSize-1 downto 0); -signal multResult3 : unsigned(wordSize-1 downto 0); -signal multResult : unsigned(wordSize-1 downto 0); -signal multA : unsigned(wordSize-1 downto 0); -signal multB : unsigned(wordSize-1 downto 0); -signal stackB : unsigned(wordSize-1 downto 0); -signal idim_flag : std_logic; -signal busy : std_logic; -signal mem_writeEnable : std_logic; -signal mem_readEnable : std_logic; -signal mem_addr : std_logic_vector(maxAddrBitIncIO downto minAddrBit); -signal mem_delayAddr : std_logic_vector(maxAddrBitIncIO downto minAddrBit); -signal mem_delayReadEnable : std_logic; - -signal inInterrupt: std_logic; - -signal decodeWord : std_logic_vector(wordSize-1 downto 0); - - -signal state : StateType; -signal insn : InsnType; -type InsnArray is array(0 to wordBytes-1) of InsnType; -signal decodedOpcode : InsnArray; - -type OpcodeArray is array(0 to wordBytes-1) of std_logic_vector(7 downto 0); - -signal opcode : OpcodeArray; - - - - -signal begin_inst : std_logic; -signal trace_opcode : std_logic_vector(7 downto 0); -signal trace_pc : std_logic_vector(maxAddrBitIncIO downto 0); -signal trace_sp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); -signal trace_topOfStack : std_logic_vector(wordSize-1 downto 0); -signal trace_topOfStackB : std_logic_vector(wordSize-1 downto 0); + type InsnType is ( + State_AddTop, + State_Dup, + State_DupStackB, + State_Pop, + State_Popdown, + State_Add, + State_Or, + State_And, + State_Store, + State_AddSP, + State_Shift, + State_Nop, + State_Im, + State_LoadSP, + State_StoreSP, + State_Emulate, + State_Load, + State_PushPC, + State_PushSP, + State_PopPC, + State_PopPCRel, + State_Not, + State_Flip, + State_PopSP, + State_Neqbranch, + State_Eq, + State_Loadb, + State_Mult, + State_Lessthan, + State_Lessthanorequal, + State_Ulessthanorequal, + State_Ulessthan, + State_Pushspadd, + State_Call, + State_Callpcrel, + State_Sub, + State_Break, + State_Storeb, + State_InsnFetch + ); + + type StateType is ( + State_Load2, + State_Popped, + State_LoadSP2, + State_LoadSP3, + State_AddSP2, + State_Fetch, + State_Execute, + State_Decode, + State_Decode2, + State_Resync, + + State_StoreSP2, + State_Resync2, + State_Resync3, + State_Loadb2, + State_Storeb2, + State_Mult2, + State_Mult3, + State_Mult5, + State_Mult4, + State_BinaryOpResult2, + State_BinaryOpResult, + State_Idle, + State_Interrupt + ); + + + signal pc : unsigned(maxAddrBitIncIO downto 0); + signal sp : unsigned(maxAddrBitIncIO downto minAddrBit); + signal incSp : unsigned(maxAddrBitIncIO downto minAddrBit); + signal incIncSp : unsigned(maxAddrBitIncIO downto minAddrBit); + signal decSp : unsigned(maxAddrBitIncIO downto minAddrBit); + signal stackA : unsigned(wordSize-1 downto 0); + signal binaryOpResult : unsigned(wordSize-1 downto 0); + signal binaryOpResult2 : unsigned(wordSize-1 downto 0); + signal multResult2 : unsigned(wordSize-1 downto 0); + signal multResult3 : unsigned(wordSize-1 downto 0); + signal multResult : unsigned(wordSize-1 downto 0); + signal multA : unsigned(wordSize-1 downto 0); + signal multB : unsigned(wordSize-1 downto 0); + signal stackB : unsigned(wordSize-1 downto 0); + signal idim_flag : std_logic; + signal busy : std_logic; + signal mem_writeEnable : std_logic; + signal mem_readEnable : std_logic; + signal mem_addr : std_logic_vector(maxAddrBitIncIO downto minAddrBit); + signal mem_delayAddr : std_logic_vector(maxAddrBitIncIO downto minAddrBit); + signal mem_delayReadEnable : std_logic; + -- + signal inInterrupt : std_logic; + -- + signal decodeWord : std_logic_vector(wordSize-1 downto 0); + -- + -- + signal state : StateType; + signal insn : InsnType; + type InsnArray is array(0 to wordBytes-1) of InsnType; + signal decodedOpcode : InsnArray; + -- + type OpcodeArray is array(0 to wordBytes-1) of std_logic_vector(7 downto 0); + -- + signal opcode : OpcodeArray; + + + + + signal begin_inst : std_logic; + signal trace_opcode : std_logic_vector(7 downto 0); + signal trace_pc : std_logic_vector(maxAddrBitIncIO downto 0); + signal trace_sp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); + signal trace_topOfStack : std_logic_vector(wordSize-1 downto 0); + signal trace_topOfStackB : std_logic_vector(wordSize-1 downto 0); -- state machine. begin - traceFileGenerate: - if Generate_Trace generate - trace_file: trace port map ( - clk => clk, - begin_inst => begin_inst, - pc => trace_pc, - opcode => trace_opcode, - sp => trace_sp, - memA => trace_topOfStack, - memB => trace_topOfStackB, - busy => busy, - intsp => (others => 'U') - ); - end generate; - - - -- the memory subsystem will tell us one cycle later whether or - -- not it is busy - out_mem_writeEnable <= mem_writeEnable; - out_mem_readEnable <= mem_readEnable; - out_mem_addr(maxAddrBitIncIO downto minAddrBit) <= mem_addr; - out_mem_addr(minAddrBit-1 downto 0) <= (others => '0'); - - incSp <= sp + 1; - incIncSp <= sp + 2; - decSp <= sp - 1; - - - opcodeControl: - process(clk, areset) - variable tOpcode : std_logic_vector(OpCode_Size-1 downto 0); - variable spOffset : unsigned(4 downto 0); - variable tSpOffset : unsigned(4 downto 0); - variable nextPC : unsigned(maxAddrBitIncIO downto 0); - variable tNextState : InsnType; - variable tDecodedOpcode : InsnArray; - variable tMultResult : unsigned(wordSize*2-1 downto 0); - begin - if areset = '1' then - state <= State_Idle; - break <= '0'; - sp <= unsigned(spStart(maxAddrBitIncIO downto minAddrBit)); - - pc <= (others => '0'); - idim_flag <= '0'; - begin_inst <= '0'; - inInterrupt <= '0'; - mem_writeEnable <= '0'; - mem_readEnable <= '0'; - multA <= (others => '0'); - multB <= (others => '0'); - mem_writeMask <= (others => '1'); - elsif (clk'event and clk = '1') then - -- we must multiply unconditionally to get pipelined multiplication - tMultResult := multA * multB; - multResult3 <= multResult2; - multResult2 <= multResult; - multResult <= tMultResult(wordSize-1 downto 0); - - - binaryOpResult2 <= binaryOpResult; -- pipeline a bit. - - - multA <= (others => DontCareValue); - multB <= (others => DontCareValue); - - - mem_addr <= (others => DontCareValue); - mem_readEnable <='0'; - mem_writeEnable <='0'; - mem_write <= (others => DontCareValue); - - if (mem_writeEnable = '1') and (mem_readEnable = '1') then - report "read/write collision" severity failure; - end if; - - - - - spOffset(4):=not opcode(to_integer(pc(byteBits-1 downto 0)))(4); - spOffset(3 downto 0):=unsigned(opcode(to_integer(pc(byteBits-1 downto 0)))(3 downto 0)); - nextPC := pc + 1; - - -- prepare trace snapshot - trace_opcode <= opcode(to_integer(pc(byteBits-1 downto 0))); - trace_pc <= std_logic_vector(pc); - trace_sp <= std_logic_vector(sp); - trace_topOfStack <= std_logic_vector(stackA); - trace_topOfStackB <= std_logic_vector(stackB); - begin_inst <= '0'; - - if (interrupt='0') then - -- Interrupt ended, we can serve ISR again - inInterrupt <= '0'; - end if; - - case state is - when State_Idle => - if enable='1' then - state <= State_Resync; - end if; - -- Initial state of ZPU, fetch top of stack + first instruction - when State_Resync => - if in_mem_busy='0' then - mem_addr <= std_logic_vector(sp); - mem_readEnable <= '1'; - state <= State_Resync2; - end if; - when State_Resync2 => - if in_mem_busy='0' then - stackA <= unsigned(mem_read); - mem_addr <= std_logic_vector(incSp); - mem_readEnable <= '1'; - state <= State_Resync3; - end if; - when State_Resync3 => - if in_mem_busy='0' then - stackB <= unsigned(mem_read); - mem_addr <= std_logic_vector(pc(maxAddrBitIncIO downto minAddrBit)); - mem_readEnable <= '1'; - state <= State_Decode; - end if; - when State_Decode => - if in_mem_busy='0' then - decodeWord <= mem_read; - state <= State_Decode2; - -- Do not recurse into ISR while interrupt line is active - if interrupt='1' and inInterrupt='0' and idim_flag='0' then - -- We got an interrupt, execute interrupt instead of next instruction - inInterrupt <= '1'; - sp <= decSp; - mem_writeEnable <= '1'; - mem_addr <= std_logic_vector(incSp); - mem_write <= std_logic_vector(stackB); - stackA <= (others => DontCareValue); - stackA(maxAddrBitIncIO downto 0) <= pc; - stackB <= stackA; - pc <= to_unsigned(32, maxAddrBitIncIO+1); - state <= State_Interrupt; - end if; - end if; - when State_Interrupt => - if in_mem_busy='0' then - mem_addr <= std_logic_vector(pc(maxAddrBitIncIO downto minAddrBit)); - mem_readEnable <= '1'; - state <= State_Decode; - report "ZPU jumped to interrupt!" severity note; - end if; - when State_Decode2 => - -- decode 4 instructions in parallel - for i in 0 to wordBytes-1 loop - tOpcode := decodeWord((wordBytes-1-i+1)*8-1 downto (wordBytes-1-i)*8); - - tSpOffset(4):=not tOpcode(4); - tSpOffset(3 downto 0):=unsigned(tOpcode(3 downto 0)); - - opcode(i) <= tOpcode; - if (tOpcode(7 downto 7)=OpCode_Im) then - tNextState:=State_Im; - elsif (tOpcode(7 downto 5)=OpCode_StoreSP) then - if tSpOffset = 0 then - tNextState := State_Pop; - elsif tSpOffset=1 then - tNextState := State_PopDown; - else - tNextState :=State_StoreSP; - end if; - elsif (tOpcode(7 downto 5)=OpCode_LoadSP) then - if tSpOffset = 0 then - tNextState :=State_Dup; - elsif tSpOffset = 1 then - tNextState :=State_DupStackB; - else - tNextState :=State_LoadSP; - end if; - elsif (tOpcode(7 downto 5)=OpCode_Emulate) then - tNextState :=State_Emulate; - if tOpcode(5 downto 0)=OpCode_Neqbranch then - tNextState :=State_Neqbranch; - elsif tOpcode(5 downto 0)=OpCode_Eq then - tNextState :=State_Eq; - elsif tOpcode(5 downto 0)=OpCode_Lessthan then - tNextState :=State_Lessthan; - elsif tOpcode(5 downto 0)=OpCode_Lessthanorequal then - --tNextState :=State_Lessthanorequal; - elsif tOpcode(5 downto 0)=OpCode_Ulessthan then - tNextState :=State_Ulessthan; - elsif tOpcode(5 downto 0)=OpCode_Ulessthanorequal then - --tNextState :=State_Ulessthanorequal; - elsif tOpcode(5 downto 0)=OpCode_Loadb then - tNextState :=State_Loadb; - elsif tOpcode(5 downto 0)=OpCode_Mult then - tNextState :=State_Mult; - elsif tOpcode(5 downto 0)=OpCode_Storeb then - tNextState :=State_Storeb; - elsif tOpcode(5 downto 0)=OpCode_Pushspadd then - tNextState :=State_Pushspadd; - elsif tOpcode(5 downto 0)=OpCode_Callpcrel then - tNextState :=State_Callpcrel; - elsif tOpcode(5 downto 0)=OpCode_Call then - --tNextState :=State_Call; - elsif tOpcode(5 downto 0)=OpCode_Sub then - tNextState :=State_Sub; - elsif tOpcode(5 downto 0)=OpCode_PopPCRel then - --tNextState :=State_PopPCRel; - end if; - elsif (tOpcode(7 downto 4)=OpCode_AddSP) then - if tSpOffset = 0 then - tNextState := State_Shift; - elsif tSpOffset = 1 then - tNextState := State_AddTop; - else - tNextState :=State_AddSP; - end if; - else - case tOpcode(3 downto 0) is - when OpCode_Nop => - tNextState :=State_Nop; - when OpCode_PushSP => - tNextState :=State_PushSP; - when OpCode_PopPC => - tNextState :=State_PopPC; - when OpCode_Add => - tNextState :=State_Add; - when OpCode_Or => - tNextState :=State_Or; - when OpCode_And => - tNextState :=State_And; - when OpCode_Load => - tNextState :=State_Load; - when OpCode_Not => - tNextState :=State_Not; - when OpCode_Flip => - tNextState :=State_Flip; - when OpCode_Store => - tNextState :=State_Store; - when OpCode_PopSP => - tNextState :=State_PopSP; - when others => - tNextState := State_Break; - - end case; - end if; - tDecodedOpcode(i) := tNextState; - - end loop; - - insn <= tDecodedOpcode(to_integer(pc(byteBits-1 downto 0))); - - -- once we wrap, we need to fetch - tDecodedOpcode(0) := State_InsnFetch; - - decodedOpcode <= tDecodedOpcode; - state <= State_Execute; - - - - -- Each instruction must: - -- - -- 1. set idim_flag - -- 2. increase pc if applicable - -- 3. set next state if appliable - -- 4. do it's operation - - when State_Execute => - insn <= decodedOpcode(to_integer(nextPC(byteBits-1 downto 0))); - - case insn is - when State_InsnFetch => - state <= State_Fetch; - when State_Im => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '1'; - pc <= pc + 1; - - if idim_flag='1' then - stackA(wordSize-1 downto 7) <= stackA(wordSize-8 downto 0); - stackA(6 downto 0) <= unsigned(opcode(to_integer(pc(byteBits-1 downto 0)))(6 downto 0)); - else - mem_writeEnable <= '1'; - mem_addr <= std_logic_vector(incSp); - mem_write <= std_logic_vector(stackB); - stackB <= stackA; - sp <= decSp; - for i in wordSize-1 downto 7 loop - stackA(i) <= opcode(to_integer(pc(byteBits-1 downto 0)))(6); - end loop; - stackA(6 downto 0) <= unsigned(opcode(to_integer(pc(byteBits-1 downto 0)))(6 downto 0)); - end if; - end if; - when State_StoreSP => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_StoreSP2; - - mem_writeEnable <= '1'; - mem_addr <= std_logic_vector(sp+spOffset); - mem_write <= std_logic_vector(stackA); - stackA <= stackB; - sp <= incSp; - end if; - - - when State_LoadSP => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_LoadSP2; - - sp <= decSp; - mem_writeEnable <= '1'; - mem_addr <= std_logic_vector(incSp); - mem_write <= std_logic_vector(stackB); - end if; - when State_Emulate => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - sp <= decSp; - mem_writeEnable <= '1'; - mem_addr <= std_logic_vector(incSp); - mem_write <= std_logic_vector(stackB); - stackA <= (others => DontCareValue); - stackA(maxAddrBitIncIO downto 0) <= pc + 1; - stackB <= stackA; - - -- The emulate address is: - -- 98 7654 3210 - -- 0000 00aa aaa0 0000 - pc <= (others => '0'); - pc(9 downto 5) <= unsigned(opcode(to_integer(pc(byteBits-1 downto 0)))(4 downto 0)); - state <= State_Fetch; - end if; - when State_Callpcrel => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - stackA <= (others => DontCareValue); - stackA(maxAddrBitIncIO downto 0) <= pc + 1; - - pc <= pc + stackA(maxAddrBitIncIO downto 0); - state <= State_Fetch; - end if; - when State_Call => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - stackA <= (others => DontCareValue); - stackA(maxAddrBitIncIO downto 0) <= pc + 1; - pc <= stackA(maxAddrBitIncIO downto 0); - state <= State_Fetch; - end if; - when State_AddSP => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_AddSP2; - - mem_readEnable <= '1'; - mem_addr <= std_logic_vector(sp+spOffset); - end if; - when State_PushSP => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - sp <= decSp; - stackA <= (others => '0'); - stackA(maxAddrBitIncIO downto minAddrBit) <= sp; - stackB <= stackA; - mem_writeEnable <= '1'; - mem_addr <= std_logic_vector(incSp); - mem_write <= std_logic_vector(stackB); - end if; - when State_PopPC => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= stackA(maxAddrBitIncIO downto 0); - sp <= incSp; - - mem_writeEnable <= '1'; - mem_addr <= std_logic_vector(incSp); - mem_write <= std_logic_vector(stackB); - state <= State_Resync; - end if; - when State_PopPCRel => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= stackA(maxAddrBitIncIO downto 0) + pc; - sp <= incSp; - - mem_writeEnable <= '1'; - mem_addr <= std_logic_vector(incSp); - mem_write <= std_logic_vector(stackB); - state <= State_Resync; - end if; - when State_Add => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - stackA <= stackA + stackB; - - mem_readEnable <= '1'; - mem_addr <= std_logic_vector(incIncSp); - sp <= incSp; - state <= State_Popped; - end if; - when State_Sub => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - binaryOpResult <= stackB - stackA; - state <= State_BinaryOpResult; - end if; - when State_Pop => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - mem_addr <= std_logic_vector(incIncSp); - mem_readEnable <= '1'; - sp <= incSp; - stackA <= stackB; - state <= State_Popped; - end if; - when State_PopDown => - if in_mem_busy='0' then - -- PopDown leaves top of stack unchanged - begin_inst <= '1'; - idim_flag <= '0'; - mem_addr <= std_logic_vector(incIncSp); - mem_readEnable <= '1'; - sp <= incSp; - state <= State_Popped; - end if; - when State_Or => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - stackA <= stackA or stackB; - mem_readEnable <= '1'; - mem_addr <= std_logic_vector(incIncSp); - sp <= incSp; - state <= State_Popped; - end if; - when State_And => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - - stackA <= stackA and stackB; - mem_readEnable <= '1'; - mem_addr <= std_logic_vector(incIncSp); - sp <= incSp; - state <= State_Popped; - end if; - when State_Eq => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (stackA=stackB) then - binaryOpResult(0) <= '1'; - end if; - state <= State_BinaryOpResult; - end if; - when State_Ulessthan => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (stackA - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (stackA<=stackB) then - binaryOpResult(0) <= '1'; - end if; - state <= State_BinaryOpResult; - end if; - when State_Lessthan => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (signed(stackA) - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (signed(stackA)<=signed(stackB)) then - binaryOpResult(0) <= '1'; - end if; - state <= State_BinaryOpResult; - end if; - when State_Load => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_Load2; - - mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); - mem_readEnable <= '1'; - end if; - - when State_Dup => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - sp <= decSp; - stackB <= stackA; - mem_write <= std_logic_vector(stackB); - mem_addr <= std_logic_vector(incSp); - mem_writeEnable <= '1'; - end if; - when State_DupStackB => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - sp <= decSp; - stackA <= stackB; - stackB <= stackA; - mem_write <= std_logic_vector(stackB); - mem_addr <= std_logic_vector(incSp); - mem_writeEnable <= '1'; - end if; - when State_Store => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); - mem_write <= std_logic_vector(stackB); - mem_writeEnable <= '1'; - sp <= incIncSp; - state <= State_Resync; - end if; - when State_PopSP => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - mem_write <= std_logic_vector(stackB); - mem_addr <= std_logic_vector(incSp); - mem_writeEnable <= '1'; - sp <= stackA(maxAddrBitIncIO downto minAddrBit); - state <= State_Resync; - end if; - when State_Nop => - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - when State_Not => - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - stackA <= not stackA; - when State_Flip => - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - for i in 0 to wordSize-1 loop - stackA(i) <= stackA(wordSize-1-i); - end loop; - when State_AddTop => - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - stackA <= stackA + stackB; - when State_Shift => - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - stackA(wordSize-1 downto 1) <= stackA(wordSize-2 downto 0); - stackA(0) <= '0'; - when State_Pushspadd => - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - stackA <= (others => '0'); - stackA(maxAddrBitIncIO downto minAddrBit) <= stackA(maxAddrBitIncIO-minAddrBit downto 0)+sp; - when State_Neqbranch => - -- branches are almost always taken as they form loops - begin_inst <= '1'; - idim_flag <= '0'; - sp <= incIncSp; - if (stackB/=0) then - pc <= stackA(maxAddrBitIncIO downto 0) + pc; - else - pc <= pc + 1; - end if; - -- need to fetch stack again. - state <= State_Resync; - when State_Mult => - begin_inst <= '1'; - idim_flag <= '0'; - - multA <= stackA; - multB <= stackB; - state <= State_Mult2; - when State_Break => - report "Break instruction encountered" severity failure; - break <= '1'; - - when State_Loadb => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_Loadb2; - - mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); - mem_readEnable <= '1'; - end if; - when State_Storeb => - if in_mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_Storeb2; - - mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); - mem_readEnable <= '1'; - end if; - - when others => - sp <= (others => DontCareValue); - report "Illegal instruction" severity failure; - break <= '1'; - end case; - - - when State_StoreSP2 => - if in_mem_busy='0' then - mem_addr <= std_logic_vector(incSp); - mem_readEnable <= '1'; - state <= State_Popped; - end if; - when State_LoadSP2 => - if in_mem_busy='0' then - state <= State_LoadSP3; - mem_readEnable <= '1'; - mem_addr <= std_logic_vector(sp+spOffset+1); - end if; - when State_LoadSP3 => - if in_mem_busy='0' then - pc <= pc + 1; - state <= State_Execute; - stackB <= stackA; - stackA <= unsigned(mem_read); - end if; - when State_AddSP2 => - if in_mem_busy='0' then - pc <= pc + 1; - state <= State_Execute; - stackA <= stackA + unsigned(mem_read); - end if; - when State_Load2 => - if in_mem_busy='0' then - stackA <= unsigned(mem_read); - pc <= pc + 1; - state <= State_Execute; - end if; - when State_Loadb2 => - if in_mem_busy='0' then - stackA <= (others => '0'); - stackA(7 downto 0) <= unsigned(mem_read(((wordBytes-1-to_integer(stackA(byteBits-1 downto 0)))*8+7) downto (wordBytes-1-to_integer(stackA(byteBits-1 downto 0)))*8)); - pc <= pc + 1; - state <= State_Execute; - end if; - when State_Storeb2 => - if in_mem_busy='0' then - mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); - mem_write <= mem_read; - mem_write(((wordBytes-1-to_integer(stackA(byteBits-1 downto 0)))*8+7) downto (wordBytes-1-to_integer(stackA(byteBits-1 downto 0)))*8) <= std_logic_vector(stackB(7 downto 0)); - mem_writeEnable <= '1'; - pc <= pc + 1; - sp <= incIncSp; - state <= State_Resync; - end if; - when State_Fetch => - if in_mem_busy='0' then - mem_addr <= std_logic_vector(pc(maxAddrBitIncIO downto minAddrBit)); - mem_readEnable <= '1'; - state <= State_Decode; - end if; - when State_Mult2 => - state <= State_Mult3; - when State_Mult3 => - state <= State_Mult4; - when State_Mult4 => - state <= State_Mult5; - when State_Mult5 => - if in_mem_busy='0' then - stackA <= multResult3; - mem_readEnable <= '1'; - mem_addr <= std_logic_vector(incIncSp); - sp <= incSp; - state <= State_Popped; - end if; - when State_BinaryOpResult => - state <= State_BinaryOpResult2; - when State_BinaryOpResult2 => - mem_readEnable <= '1'; - mem_addr <= std_logic_vector(incIncSp); - sp <= incSp; - stackA <= binaryOpResult2; - state <= State_Popped; - when State_Popped => - if in_mem_busy='0' then - pc <= pc + 1; - stackB <= unsigned(mem_read); - state <= State_Execute; - end if; - when others => - sp <= (others => DontCareValue); - report "Illegal state" severity failure; - break <= '1'; - end case; - end if; - end process; + traceFileGenerate : + if Generate_Trace generate + trace_file : trace port map ( + clk => clk, + begin_inst => begin_inst, + pc => trace_pc, + opcode => trace_opcode, + sp => trace_sp, + memA => trace_topOfStack, + memB => trace_topOfStackB, + busy => busy, + intsp => (others => 'U') + ); + end generate; + + + -- the memory subsystem will tell us one cycle later whether or + -- not it is busy + out_mem_writeEnable <= mem_writeEnable; + out_mem_readEnable <= mem_readEnable; + out_mem_addr(maxAddrBitIncIO downto minAddrBit) <= mem_addr; + out_mem_addr(minAddrBit-1 downto 0) <= (others => '0'); + + incSp <= sp + 1; + incIncSp <= sp + 2; + decSp <= sp - 1; + + + opcodeControl : process(clk, areset) + variable tOpcode : std_logic_vector(OpCode_Size-1 downto 0); + variable spOffset : unsigned(4 downto 0); + variable tSpOffset : unsigned(4 downto 0); + variable nextPC : unsigned(maxAddrBitIncIO downto 0); + variable tNextState : InsnType; + variable tDecodedOpcode : InsnArray; + variable tMultResult : unsigned(wordSize*2-1 downto 0); + begin + if areset = '1' then + state <= State_Idle; + break <= '0'; + sp <= unsigned(spStart(maxAddrBitIncIO downto minAddrBit)); + + pc <= (others => '0'); + idim_flag <= '0'; + begin_inst <= '0'; + inInterrupt <= '0'; + mem_writeEnable <= '0'; + mem_readEnable <= '0'; + multA <= (others => '0'); + multB <= (others => '0'); + mem_writeMask <= (others => '1'); + elsif (clk'event and clk = '1') then + -- we must multiply unconditionally to get pipelined multiplication + tMultResult := multA * multB; + multResult3 <= multResult2; + multResult2 <= multResult; + multResult <= tMultResult(wordSize-1 downto 0); + + + binaryOpResult2 <= binaryOpResult; -- pipeline a bit. + + + multA <= (others => DontCareValue); + multB <= (others => DontCareValue); + + + mem_addr <= (others => DontCareValue); + mem_readEnable <= '0'; + mem_writeEnable <= '0'; + mem_write <= (others => DontCareValue); + + if (mem_writeEnable = '1') and (mem_readEnable = '1') then + report "read/write collision" severity failure; + end if; + + + + + spOffset(4) := not opcode(to_integer(pc(byteBits-1 downto 0)))(4); + spOffset(3 downto 0) := unsigned(opcode(to_integer(pc(byteBits-1 downto 0)))(3 downto 0)); + nextPC := pc + 1; + + -- prepare trace snapshot + trace_opcode <= opcode(to_integer(pc(byteBits-1 downto 0))); + trace_pc <= std_logic_vector(pc); + trace_sp <= std_logic_vector(sp); + trace_topOfStack <= std_logic_vector(stackA); + trace_topOfStackB <= std_logic_vector(stackB); + begin_inst <= '0'; + + if (interrupt = '0') then + -- Interrupt ended, we can serve ISR again + inInterrupt <= '0'; + end if; + + case state is + + when State_Idle => + if enable = '1' then + state <= State_Resync; + end if; + -- Initial state of ZPU, fetch top of stack + first instruction + + when State_Resync => + if in_mem_busy = '0' then + mem_addr <= std_logic_vector(sp); + mem_readEnable <= '1'; + state <= State_Resync2; + end if; + + when State_Resync2 => + if in_mem_busy = '0' then + stackA <= unsigned(mem_read); + mem_addr <= std_logic_vector(incSp); + mem_readEnable <= '1'; + state <= State_Resync3; + end if; + + when State_Resync3 => + if in_mem_busy = '0' then + stackB <= unsigned(mem_read); + mem_addr <= std_logic_vector(pc(maxAddrBitIncIO downto minAddrBit)); + mem_readEnable <= '1'; + state <= State_Decode; + end if; + + when State_Decode => + if in_mem_busy = '0' then + decodeWord <= mem_read; + state <= State_Decode2; + -- Do not recurse into ISR while interrupt line is active + if interrupt = '1' and inInterrupt = '0' and idim_flag = '0' then + -- We got an interrupt, execute interrupt instead of next instruction + inInterrupt <= '1'; + sp <= decSp; + mem_writeEnable <= '1'; + mem_addr <= std_logic_vector(incSp); + mem_write <= std_logic_vector(stackB); + stackA <= (others => DontCareValue); + stackA(maxAddrBitIncIO downto 0) <= pc; + stackB <= stackA; + pc <= to_unsigned(32, maxAddrBitIncIO+1); + state <= State_Interrupt; + end if; -- interrupt + end if; -- in_mem_busy + + when State_Interrupt => + if in_mem_busy = '0' then + mem_addr <= std_logic_vector(pc(maxAddrBitIncIO downto minAddrBit)); + mem_readEnable <= '1'; + state <= State_Decode; + report "ZPU jumped to interrupt!" severity note; + end if; + + when State_Decode2 => + -- decode 4 instructions in parallel + for i in 0 to wordBytes-1 loop + tOpcode := decodeWord((wordBytes-1-i+1)*8-1 downto (wordBytes-1-i)*8); + + tSpOffset(4) := not tOpcode(4); + tSpOffset(3 downto 0) := unsigned(tOpcode(3 downto 0)); + + opcode(i) <= tOpcode; + if (tOpcode(7 downto 7) = OpCode_Im) then + tNextState := State_Im; + elsif (tOpcode(7 downto 5) = OpCode_StoreSP) then + if tSpOffset = 0 then + tNextState := State_Pop; + elsif tSpOffset = 1 then + tNextState := State_PopDown; + else + tNextState := State_StoreSP; + end if; + elsif (tOpcode(7 downto 5) = OpCode_LoadSP) then + if tSpOffset = 0 then + tNextState := State_Dup; + elsif tSpOffset = 1 then + tNextState := State_DupStackB; + else + tNextState := State_LoadSP; + end if; + elsif (tOpcode(7 downto 5) = OpCode_Emulate) then + tNextState := State_Emulate; + if tOpcode(5 downto 0) = OpCode_Neqbranch then + tNextState := State_Neqbranch; + elsif tOpcode(5 downto 0) = OpCode_Eq then + tNextState := State_Eq; + elsif tOpcode(5 downto 0) = OpCode_Lessthan then + tNextState := State_Lessthan; + elsif tOpcode(5 downto 0) = OpCode_Lessthanorequal then + --tNextState :=State_Lessthanorequal; + elsif tOpcode(5 downto 0) = OpCode_Ulessthan then + tNextState := State_Ulessthan; + elsif tOpcode(5 downto 0) = OpCode_Ulessthanorequal then + --tNextState :=State_Ulessthanorequal; + elsif tOpcode(5 downto 0) = OpCode_Loadb then + tNextState := State_Loadb; + elsif tOpcode(5 downto 0) = OpCode_Mult then + tNextState := State_Mult; + elsif tOpcode(5 downto 0) = OpCode_Storeb then + tNextState := State_Storeb; + elsif tOpcode(5 downto 0) = OpCode_Pushspadd then + tNextState := State_Pushspadd; + elsif tOpcode(5 downto 0) = OpCode_Callpcrel then + tNextState := State_Callpcrel; + elsif tOpcode(5 downto 0) = OpCode_Call then + --tNextState :=State_Call; + elsif tOpcode(5 downto 0) = OpCode_Sub then + tNextState := State_Sub; + elsif tOpcode(5 downto 0) = OpCode_PopPCRel then + --tNextState :=State_PopPCRel; + end if; + elsif (tOpcode(7 downto 4) = OpCode_AddSP) then + if tSpOffset = 0 then + tNextState := State_Shift; + elsif tSpOffset = 1 then + tNextState := State_AddTop; + else + tNextState := State_AddSP; + end if; + else + case tOpcode(3 downto 0) is + when OpCode_Nop => + tNextState := State_Nop; + when OpCode_PushSP => + tNextState := State_PushSP; + when OpCode_PopPC => + tNextState := State_PopPC; + when OpCode_Add => + tNextState := State_Add; + when OpCode_Or => + tNextState := State_Or; + when OpCode_And => + tNextState := State_And; + when OpCode_Load => + tNextState := State_Load; + when OpCode_Not => + tNextState := State_Not; + when OpCode_Flip => + tNextState := State_Flip; + when OpCode_Store => + tNextState := State_Store; + when OpCode_PopSP => + tNextState := State_PopSP; + when others => + tNextState := State_Break; + + end case; -- tOpcode(3 downto 0) + end if; -- tOpcode + tDecodedOpcode(i) := tNextState; + + end loop; -- 0 to wordBytes-1 + + insn <= tDecodedOpcode(to_integer(pc(byteBits-1 downto 0))); + + -- once we wrap, we need to fetch + tDecodedOpcode(0) := State_InsnFetch; + + decodedOpcode <= tDecodedOpcode; + state <= State_Execute; + + + + -- Each instruction must: + -- + -- 1. set idim_flag + -- 2. increase pc if applicable + -- 3. set next state if appliable + -- 4. do it's operation + + when State_Execute => + insn <= decodedOpcode(to_integer(nextPC(byteBits-1 downto 0))); + + case insn is + + when State_InsnFetch => + state <= State_Fetch; + + when State_Im => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '1'; + pc <= pc + 1; + + if idim_flag = '1' then + stackA(wordSize-1 downto 7) <= stackA(wordSize-8 downto 0); + stackA(6 downto 0) <= unsigned(opcode(to_integer(pc(byteBits-1 downto 0)))(6 downto 0)); + else + mem_writeEnable <= '1'; + mem_addr <= std_logic_vector(incSp); + mem_write <= std_logic_vector(stackB); + stackB <= stackA; + sp <= decSp; + for i in wordSize-1 downto 7 loop + stackA(i) <= opcode(to_integer(pc(byteBits-1 downto 0)))(6); + end loop; + stackA(6 downto 0) <= unsigned(opcode(to_integer(pc(byteBits-1 downto 0)))(6 downto 0)); + end if; -- idim_flag + end if; -- in_mem_busy + + when State_StoreSP => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_StoreSP2; + + mem_writeEnable <= '1'; + mem_addr <= std_logic_vector(sp+spOffset); + mem_write <= std_logic_vector(stackA); + stackA <= stackB; + sp <= incSp; + end if; + + + when State_LoadSP => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_LoadSP2; + + sp <= decSp; + mem_writeEnable <= '1'; + mem_addr <= std_logic_vector(incSp); + mem_write <= std_logic_vector(stackB); + end if; + + when State_Emulate => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + sp <= decSp; + mem_writeEnable <= '1'; + mem_addr <= std_logic_vector(incSp); + mem_write <= std_logic_vector(stackB); + stackA <= (others => DontCareValue); + stackA(maxAddrBitIncIO downto 0) <= pc + 1; + stackB <= stackA; + + -- The emulate address is: + -- 98 7654 3210 + -- 0000 00aa aaa0 0000 + pc <= (others => '0'); + pc(9 downto 5) <= unsigned(opcode(to_integer(pc(byteBits-1 downto 0)))(4 downto 0)); + state <= State_Fetch; + end if; -- in_mem_busy + + when State_Callpcrel => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + stackA <= (others => DontCareValue); + stackA(maxAddrBitIncIO downto 0) <= pc + 1; + + pc <= pc + stackA(maxAddrBitIncIO downto 0); + state <= State_Fetch; + end if; + + when State_Call => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + stackA <= (others => DontCareValue); + stackA(maxAddrBitIncIO downto 0) <= pc + 1; + pc <= stackA(maxAddrBitIncIO downto 0); + state <= State_Fetch; + end if; + + when State_AddSP => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_AddSP2; + + mem_readEnable <= '1'; + mem_addr <= std_logic_vector(sp+spOffset); + end if; + + when State_PushSP => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + sp <= decSp; + stackA <= (others => '0'); + stackA(maxAddrBitIncIO downto minAddrBit) <= sp; + stackB <= stackA; + mem_writeEnable <= '1'; + mem_addr <= std_logic_vector(incSp); + mem_write <= std_logic_vector(stackB); + end if; + + when State_PopPC => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= stackA(maxAddrBitIncIO downto 0); + sp <= incSp; + + mem_writeEnable <= '1'; + mem_addr <= std_logic_vector(incSp); + mem_write <= std_logic_vector(stackB); + state <= State_Resync; + end if; + + when State_PopPCRel => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= stackA(maxAddrBitIncIO downto 0) + pc; + sp <= incSp; + + mem_writeEnable <= '1'; + mem_addr <= std_logic_vector(incSp); + mem_write <= std_logic_vector(stackB); + state <= State_Resync; + end if; + + when State_Add => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + stackA <= stackA + stackB; + + mem_readEnable <= '1'; + mem_addr <= std_logic_vector(incIncSp); + sp <= incSp; + state <= State_Popped; + end if; + + when State_Sub => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + binaryOpResult <= stackB - stackA; + state <= State_BinaryOpResult; + end if; + + when State_Pop => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + mem_addr <= std_logic_vector(incIncSp); + mem_readEnable <= '1'; + sp <= incSp; + stackA <= stackB; + state <= State_Popped; + end if; + + when State_PopDown => + if in_mem_busy = '0' then + -- PopDown leaves top of stack unchanged + begin_inst <= '1'; + idim_flag <= '0'; + mem_addr <= std_logic_vector(incIncSp); + mem_readEnable <= '1'; + sp <= incSp; + state <= State_Popped; + end if; + + when State_Or => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + stackA <= stackA or stackB; + mem_readEnable <= '1'; + mem_addr <= std_logic_vector(incIncSp); + sp <= incSp; + state <= State_Popped; + end if; + + when State_And => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + + stackA <= stackA and stackB; + mem_readEnable <= '1'; + mem_addr <= std_logic_vector(incIncSp); + sp <= incSp; + state <= State_Popped; + end if; + + when State_Eq => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (stackA = stackB) then + binaryOpResult(0) <= '1'; + end if; + state <= State_BinaryOpResult; + end if; + + when State_Ulessthan => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (stackA < stackB) then + binaryOpResult(0) <= '1'; + end if; + state <= State_BinaryOpResult; + end if; + + when State_Ulessthanorequal => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (stackA <= stackB) then + binaryOpResult(0) <= '1'; + end if; + state <= State_BinaryOpResult; + end if; + + when State_Lessthan => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (signed(stackA) < signed(stackB)) then + binaryOpResult(0) <= '1'; + end if; + state <= State_BinaryOpResult; + end if; + + when State_Lessthanorequal => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (signed(stackA) <= signed(stackB)) then + binaryOpResult(0) <= '1'; + end if; + state <= State_BinaryOpResult; + end if; + + when State_Load => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_Load2; + + mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); + mem_readEnable <= '1'; + end if; + + when State_Dup => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + sp <= decSp; + stackB <= stackA; + mem_write <= std_logic_vector(stackB); + mem_addr <= std_logic_vector(incSp); + mem_writeEnable <= '1'; + end if; + + when State_DupStackB => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + sp <= decSp; + stackA <= stackB; + stackB <= stackA; + mem_write <= std_logic_vector(stackB); + mem_addr <= std_logic_vector(incSp); + mem_writeEnable <= '1'; + end if; + + when State_Store => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); + mem_write <= std_logic_vector(stackB); + mem_writeEnable <= '1'; + sp <= incIncSp; + state <= State_Resync; + end if; + + when State_PopSP => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + mem_write <= std_logic_vector(stackB); + mem_addr <= std_logic_vector(incSp); + mem_writeEnable <= '1'; + sp <= stackA(maxAddrBitIncIO downto minAddrBit); + state <= State_Resync; + end if; + + when State_Nop => + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + when State_Not => + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + stackA <= not stackA; + + when State_Flip => + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + for i in 0 to wordSize-1 loop + stackA(i) <= stackA(wordSize-1-i); + end loop; + + when State_AddTop => + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + stackA <= stackA + stackB; + + when State_Shift => + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + stackA(wordSize-1 downto 1) <= stackA(wordSize-2 downto 0); + stackA(0) <= '0'; + + when State_Pushspadd => + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + stackA <= (others => '0'); + stackA(maxAddrBitIncIO downto minAddrBit) <= stackA(maxAddrBitIncIO-minAddrBit downto 0)+sp; + + when State_Neqbranch => + -- branches are almost always taken as they form loops + begin_inst <= '1'; + idim_flag <= '0'; + sp <= incIncSp; + if (stackB /= 0) then + pc <= stackA(maxAddrBitIncIO downto 0) + pc; + else + pc <= pc + 1; + end if; + -- need to fetch stack again. + state <= State_Resync; + + when State_Mult => + begin_inst <= '1'; + idim_flag <= '0'; + + multA <= stackA; + multB <= stackB; + state <= State_Mult2; + + when State_Break => + report "Break instruction encountered" severity failure; + break <= '1'; + + when State_Loadb => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_Loadb2; + + mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); + mem_readEnable <= '1'; + end if; + + when State_Storeb => + if in_mem_busy = '0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_Storeb2; + + mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); + mem_readEnable <= '1'; + end if; + + when others => + sp <= (others => DontCareValue); + report "Illegal instruction" severity failure; + break <= '1'; + + end case; -- insn/State_Execute + + + when State_StoreSP2 => + if in_mem_busy = '0' then + mem_addr <= std_logic_vector(incSp); + mem_readEnable <= '1'; + state <= State_Popped; + end if; + + when State_LoadSP2 => + if in_mem_busy = '0' then + state <= State_LoadSP3; + mem_readEnable <= '1'; + mem_addr <= std_logic_vector(sp+spOffset+1); + end if; + + when State_LoadSP3 => + if in_mem_busy = '0' then + pc <= pc + 1; + state <= State_Execute; + stackB <= stackA; + stackA <= unsigned(mem_read); + end if; + + when State_AddSP2 => + if in_mem_busy = '0' then + pc <= pc + 1; + state <= State_Execute; + stackA <= stackA + unsigned(mem_read); + end if; + + when State_Load2 => + if in_mem_busy = '0' then + stackA <= unsigned(mem_read); + pc <= pc + 1; + state <= State_Execute; + end if; + + when State_Loadb2 => + if in_mem_busy = '0' then + stackA <= (others => '0'); + stackA(7 downto 0) <= unsigned(mem_read(((wordBytes-1-to_integer(stackA(byteBits-1 downto 0)))*8+7) downto (wordBytes-1-to_integer(stackA(byteBits-1 downto 0)))*8)); + pc <= pc + 1; + state <= State_Execute; + end if; + + when State_Storeb2 => + if in_mem_busy = '0' then + mem_addr <= std_logic_vector(stackA(maxAddrBitIncIO downto minAddrBit)); + mem_write <= mem_read; + mem_write(((wordBytes-1-to_integer(stackA(byteBits-1 downto 0)))*8+7) downto (wordBytes-1-to_integer(stackA(byteBits-1 downto 0)))*8) <= std_logic_vector(stackB(7 downto 0)); + mem_writeEnable <= '1'; + pc <= pc + 1; + sp <= incIncSp; + state <= State_Resync; + end if; + + when State_Fetch => + if in_mem_busy = '0' then + mem_addr <= std_logic_vector(pc(maxAddrBitIncIO downto minAddrBit)); + mem_readEnable <= '1'; + state <= State_Decode; + end if; + + when State_Mult2 => + state <= State_Mult3; + + when State_Mult3 => + state <= State_Mult4; + + when State_Mult4 => + state <= State_Mult5; + + when State_Mult5 => + if in_mem_busy = '0' then + stackA <= multResult3; + mem_readEnable <= '1'; + mem_addr <= std_logic_vector(incIncSp); + sp <= incSp; + state <= State_Popped; + end if; + + when State_BinaryOpResult => + state <= State_BinaryOpResult2; + + when State_BinaryOpResult2 => + mem_readEnable <= '1'; + mem_addr <= std_logic_vector(incIncSp); + sp <= incSp; + stackA <= binaryOpResult2; + state <= State_Popped; + + when State_Popped => + if in_mem_busy = '0' then + pc <= pc + 1; + stackB <= unsigned(mem_read); + state <= State_Execute; + end if; + + when others => + sp <= (others => DontCareValue); + report "Illegal state" severity failure; + break <= '1'; + + end case; -- state + end if; -- clk'event + end process; diff --git a/zpu/hdl/zpu4/core/zpu_core_small.vhd b/zpu/hdl/zpu4/core/zpu_core_small.vhd index 681fb09..1df9546 100644 --- a/zpu/hdl/zpu4/core/zpu_core_small.vhd +++ b/zpu/hdl/zpu4/core/zpu_core_small.vhd @@ -32,8 +32,8 @@ -- are those of the authors and should not be interpreted as representing -- official policies, either expressed or implied, of the ZPU Project. -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; +library ieee; +use ieee.std_logic_1164.all; use ieee.numeric_std.all; library work; @@ -42,531 +42,560 @@ use work.zpupkg.all; entity zpu_core is - Port ( clk : in std_logic; - -- asynchronous reset signal - areset : in std_logic; - -- this particular implementation of the ZPU does not - -- have a clocked enable signal - enable : in std_logic; - in_mem_busy : in std_logic; - mem_read : in std_logic_vector(wordSize-1 downto 0); - mem_write : out std_logic_vector(wordSize-1 downto 0); - out_mem_addr : out std_logic_vector(maxAddrBitIncIO downto 0); - out_mem_writeEnable : out std_logic; - out_mem_readEnable : out std_logic; - -- this implementation of the ZPU *always* reads and writes entire - -- 32 bit words, so mem_writeMask is tied to (others => '1'). - mem_writeMask: out std_logic_vector(wordBytes-1 downto 0); - -- Set to one to jump to interrupt vector - -- The ZPU will communicate with the hardware that caused the - -- interrupt via memory mapped IO or the interrupt flag can - -- be cleared automatically - interrupt : in std_logic; - -- Signal that the break instruction is executed, normally only used - -- in simulation to stop simulation - break : out std_logic); + port ( + clk : in std_logic; + -- asynchronous reset signal + areset : in std_logic; + -- this particular implementation of the ZPU does not + -- have a clocked enable signal + enable : in std_logic; + in_mem_busy : in std_logic; + mem_read : in std_logic_vector(wordSize-1 downto 0); + mem_write : out std_logic_vector(wordSize-1 downto 0); + out_mem_addr : out std_logic_vector(maxAddrBitIncIO downto 0); + out_mem_writeEnable : out std_logic; + out_mem_readEnable : out std_logic; + -- this implementation of the ZPU *always* reads and writes entire + -- 32 bit words, so mem_writeMask is tied to (others => '1'). + mem_writeMask : out std_logic_vector(wordBytes-1 downto 0); + -- Set to one to jump to interrupt vector + -- The ZPU will communicate with the hardware that caused the + -- interrupt via memory mapped IO or the interrupt flag can + -- be cleared automatically + interrupt : in std_logic; + -- Signal that the break instruction is executed, normally only used + -- in simulation to stop simulation + break : out std_logic + ); end zpu_core; -architecture behave of zpu_core is -signal readIO : std_logic; - - -signal memAWriteEnable : std_logic; -signal memAAddr : unsigned(maxAddrBit downto minAddrBit); -signal memAWrite : unsigned(wordSize-1 downto 0); -signal memARead : unsigned(wordSize-1 downto 0); -signal memBWriteEnable : std_logic; -signal memBAddr : unsigned(maxAddrBit downto minAddrBit); -signal memBWrite : unsigned(wordSize-1 downto 0); -signal memBRead : unsigned(wordSize-1 downto 0); - - - -signal pc : unsigned(maxAddrBit downto 0); -signal sp : unsigned(maxAddrBit downto minAddrBit); - --- this signal is set upon executing an IM instruction --- the subsequence IM instruction will then behave differently. --- all other instructions will clear the idim_flag. --- this yields highly compact immediate instructions. -signal idim_flag : std_logic; - -signal busy : std_logic; - -signal begin_inst : std_logic; - - - -signal trace_opcode : std_logic_vector(7 downto 0); -signal trace_pc : std_logic_vector(maxAddrBitIncIO downto 0); -signal trace_sp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); -signal trace_topOfStack : std_logic_vector(wordSize-1 downto 0); -signal trace_topOfStackB : std_logic_vector(wordSize-1 downto 0); - --- state machine. -type State_Type is -( -State_Fetch, -State_WriteIODone, -State_Execute, -State_StoreToStack, -State_Add, -State_Or, -State_And, -State_Store, -State_ReadIO, -State_WriteIO, -State_Load, -State_FetchNext, -State_AddSP, -State_ReadIODone, -State_Decode, -State_Resync, -State_Interrupt - -); - -type DecodedOpcodeType is -( -Decoded_Nop, -Decoded_Im, -Decoded_ImShift, -Decoded_LoadSP, -Decoded_StoreSP , -Decoded_AddSP, -Decoded_Emulate, -Decoded_Break, -Decoded_PushSP, -Decoded_PopPC, -Decoded_Add, -Decoded_Or, -Decoded_And, -Decoded_Load, -Decoded_Not, -Decoded_Flip, -Decoded_Store, -Decoded_PopSP, -Decoded_Interrupt -); - - - -signal sampledOpcode : std_logic_vector(OpCode_Size-1 downto 0); -signal opcode : std_logic_vector(OpCode_Size-1 downto 0); - -signal decodedOpcode : DecodedOpcodeType; -signal sampledDecodedOpcode : DecodedOpcodeType; - - -signal state : State_Type; - -subtype AddrBitBRAM_range is natural range maxAddrBitBRAM downto minAddrBit; -signal memAAddr_stdlogic : std_logic_vector(AddrBitBRAM_range); -signal memAWrite_stdlogic : std_logic_vector(memAWrite'range); -signal memARead_stdlogic : std_logic_vector(memARead'range); -signal memBAddr_stdlogic : std_logic_vector(AddrBitBRAM_range); -signal memBWrite_stdlogic : std_logic_vector(memBWrite'range); -signal memBRead_stdlogic : std_logic_vector(memBRead'range); - -subtype index is integer range 0 to 3; - -signal tOpcode_sel : index; - - -signal inInterrupt : std_logic; +architecture behave of zpu_core is + + signal memAWriteEnable : std_logic; + signal memAAddr : unsigned(maxAddrBit downto minAddrBit); + signal memAWrite : unsigned(wordSize-1 downto 0); + signal memARead : unsigned(wordSize-1 downto 0); + signal memBWriteEnable : std_logic; + signal memBAddr : unsigned(maxAddrBit downto minAddrBit); + signal memBWrite : unsigned(wordSize-1 downto 0); + signal memBRead : unsigned(wordSize-1 downto 0); + + + + signal pc : unsigned(maxAddrBit downto 0); + signal sp : unsigned(maxAddrBit downto minAddrBit); + + -- this signal is set upon executing an IM instruction + -- the subsequence IM instruction will then behave differently. + -- all other instructions will clear the idim_flag. + -- this yields highly compact immediate instructions. + signal idim_flag : std_logic; + -- + signal busy : std_logic; + -- + signal begin_inst : std_logic; + + + signal trace_opcode : std_logic_vector(7 downto 0); + signal trace_pc : std_logic_vector(maxAddrBitIncIO downto 0); + signal trace_sp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); + signal trace_topOfStack : std_logic_vector(wordSize-1 downto 0); + signal trace_topOfStackB : std_logic_vector(wordSize-1 downto 0); + + -- state machine. + type State_Type is ( + State_Fetch, + State_WriteIODone, + State_Execute, + State_StoreToStack, + State_Add, + State_Or, + State_And, + State_Store, + State_ReadIO, + State_WriteIO, + State_Load, + State_FetchNext, + State_AddSP, + State_ReadIODone, + State_Decode, + State_Resync, + State_Interrupt + ); + + type DecodedOpcodeType is ( + Decoded_Nop, + Decoded_Im, + Decoded_ImShift, + Decoded_LoadSP, + Decoded_StoreSP , + Decoded_AddSP, + Decoded_Emulate, + Decoded_Break, + Decoded_PushSP, + Decoded_PopPC, + Decoded_Add, + Decoded_Or, + Decoded_And, + Decoded_Load, + Decoded_Not, + Decoded_Flip, + Decoded_Store, + Decoded_PopSP, + Decoded_Interrupt + ); + + + + signal sampledOpcode : std_logic_vector(OpCode_Size-1 downto 0); + signal opcode : std_logic_vector(OpCode_Size-1 downto 0); + -- + signal decodedOpcode : DecodedOpcodeType; + signal sampledDecodedOpcode : DecodedOpcodeType; + + + signal state : State_Type; + -- + subtype AddrBitBRAM_range is natural range maxAddrBitBRAM downto minAddrBit; + signal memAAddr_stdlogic : std_logic_vector(AddrBitBRAM_range); + signal memAWrite_stdlogic : std_logic_vector(memAWrite'range); + signal memARead_stdlogic : std_logic_vector(memARead'range); + signal memBAddr_stdlogic : std_logic_vector(AddrBitBRAM_range); + signal memBWrite_stdlogic : std_logic_vector(memBWrite'range); + signal memBRead_stdlogic : std_logic_vector(memBRead'range); + -- + subtype index is integer range 0 to 3; + -- + signal tOpcode_sel : index; + -- + signal inInterrupt : std_logic; begin - -- generate a trace file. - -- - -- This is only used in simulation to see what instructions are - -- executed. - -- - -- a quick & dirty regression test is then to commit trace files - -- to CVS and compare the latest trace file against the last known - -- good trace file - traceFileGenerate: - if Generate_Trace generate - trace_file: trace port map ( - clk => clk, - begin_inst => begin_inst, - pc => trace_pc, - opcode => trace_opcode, - sp => trace_sp, - memA => trace_topOfStack, - memB => trace_topOfStackB, - busy => busy, - intsp => (others => 'U') - ); - end generate; - - - - -- mem_writeMask is not used in this design, tie it to 1 - mem_writeMask <= (others => '1'); - - - - memAAddr_stdlogic <= std_logic_vector(memAAddr(AddrBitBRAM_range)); - memAWrite_stdlogic <= std_logic_vector(memAWrite); - memBAddr_stdlogic <= std_logic_vector(memBAddr(AddrBitBRAM_range)); - memBWrite_stdlogic <= std_logic_vector(memBWrite); - - - -- dualport_ram must be defined by the application. - -- - -- How this can be implemented is highly dependent on the FPGA - -- and synthesis technology used. - -- - -- sometimes it can be instantiated as in the - -- zpu/example/helloworld.vhd, using inference, - -- but oftentimes it must be instantiated directly - -- portmapping to part specific FPGA resources - -- - -- - -- DANGER!!!!!! If inference fails, then synthesis will try - -- to implement the memory using basic logic resources. This - -- will almost certainly cause the compiler to get "stuck" - -- since synthesising such a huge number of basic logic resources - -- will take more or less forever. - -- - -- So: if your compiler gets "stuck" then inference is not - -- the way to go. - memory: dualport_ram port map ( - clk => clk, - memAWriteEnable => memAWriteEnable, - memAAddr => memAAddr_stdlogic, - memAWrite => memAWrite_stdlogic, - memARead => memARead_stdlogic, - memBWriteEnable => memBWriteEnable, - memBAddr => memBAddr_stdlogic, - memBWrite => memBWrite_stdlogic, - memBRead => memBRead_stdlogic - ); - memARead <= unsigned(memARead_stdlogic); - memBRead <= unsigned(memBRead_stdlogic); - - - - tOpcode_sel <= to_integer(pc(minAddrBit-1 downto 0)); - - - - -- move out calculation of the opcode to a seperate process - -- to make things a bit easier to read - decodeControl: - process(memBRead, pc,tOpcode_sel) - variable tOpcode : std_logic_vector(OpCode_Size-1 downto 0); - begin - - -- simplify opcode selection a bit so it passes more synthesizers - case (tOpcode_sel) is - - when 0 => tOpcode := std_logic_vector(memBRead(31 downto 24)); - - when 1 => tOpcode := std_logic_vector(memBRead(23 downto 16)); - - when 2 => tOpcode := std_logic_vector(memBRead(15 downto 8)); - - when 3 => tOpcode := std_logic_vector(memBRead(7 downto 0)); - - when others => tOpcode := std_logic_vector(memBRead(7 downto 0)); - end case; - - sampledOpcode <= tOpcode; - - if (tOpcode(7 downto 7)=OpCode_Im) then - sampledDecodedOpcode<=Decoded_Im; - elsif (tOpcode(7 downto 5)=OpCode_StoreSP) then - sampledDecodedOpcode<=Decoded_StoreSP; - elsif (tOpcode(7 downto 5)=OpCode_LoadSP) then - sampledDecodedOpcode<=Decoded_LoadSP; - elsif (tOpcode(7 downto 5)=OpCode_Emulate) then - sampledDecodedOpcode<=Decoded_Emulate; - elsif (tOpcode(7 downto 4)=OpCode_AddSP) then - sampledDecodedOpcode<=Decoded_AddSP; - else - case tOpcode(3 downto 0) is - when OpCode_Break => - sampledDecodedOpcode<=Decoded_Break; - when OpCode_PushSP => - sampledDecodedOpcode<=Decoded_PushSP; - when OpCode_PopPC => - sampledDecodedOpcode<=Decoded_PopPC; - when OpCode_Add => - sampledDecodedOpcode<=Decoded_Add; - when OpCode_Or => - sampledDecodedOpcode<=Decoded_Or; - when OpCode_And => - sampledDecodedOpcode<=Decoded_And; - when OpCode_Load => - sampledDecodedOpcode<=Decoded_Load; - when OpCode_Not => - sampledDecodedOpcode<=Decoded_Not; - when OpCode_Flip => - sampledDecodedOpcode<=Decoded_Flip; - when OpCode_Store => - sampledDecodedOpcode<=Decoded_Store; - when OpCode_PopSP => - sampledDecodedOpcode<=Decoded_PopSP; - when others => - sampledDecodedOpcode<=Decoded_Nop; - end case; - end if; - end process; - - - opcodeControl: - process(clk, areset) - variable spOffset : unsigned(4 downto 0); - begin - if areset = '1' then - state <= State_Resync; - break <= '0'; - sp <= unsigned(spStart(maxAddrBit downto minAddrBit)); - pc <= (others => '0'); - idim_flag <= '0'; - begin_inst <= '0'; - memAAddr <= (others => '0'); - memBAddr <= (others => '0'); - memAWriteEnable <= '0'; - memBWriteEnable <= '0'; - out_mem_writeEnable <= '0'; - out_mem_readEnable <= '0'; - memAWrite <= (others => '0'); - memBWrite <= (others => '0'); - inInterrupt <= '0'; - elsif (clk'event and clk = '1') then - memAWriteEnable <= '0'; - memBWriteEnable <= '0'; - -- This saves ca. 100 LUT's, by explicitly declaring that the - -- memAWrite can be left at whatever value if memAWriteEnable is - -- not set. - memAWrite <= (others => DontCareValue); - memBWrite <= (others => DontCareValue); --- out_mem_addr <= (others => DontCareValue); --- mem_write <= (others => DontCareValue); - spOffset := (others => DontCareValue); - memAAddr <= (others => DontCareValue); - memBAddr <= (others => DontCareValue); - - out_mem_writeEnable <= '0'; - out_mem_readEnable <= '0'; - begin_inst <= '0'; - out_mem_addr <= std_logic_vector(memARead(maxAddrBitIncIO downto 0)); - mem_write <= std_logic_vector(memBRead); - - decodedOpcode <= sampledDecodedOpcode; - opcode <= sampledOpcode; - if interrupt='0' then - inInterrupt <= '0'; -- no longer in an interrupt - end if; - - case state is - when State_Execute => - state <= State_Fetch; - -- at this point: - -- memBRead contains opcode word - -- memARead contains top of stack - pc <= pc + 1; - - -- trace - begin_inst <= '1'; - trace_pc <= (others => '0'); - trace_pc(maxAddrBit downto 0) <= std_logic_vector(pc); - trace_opcode <= opcode; - trace_sp <= (others => '0'); - trace_sp(maxAddrBit downto minAddrBit) <= std_logic_vector(sp); - trace_topOfStack <= std_logic_vector(memARead); - trace_topOfStackB <= std_logic_vector(memBRead); - - -- during the next cycle we'll be reading the next opcode - spOffset(4):=not opcode(4); - spOffset(3 downto 0) := unsigned(opcode(3 downto 0)); - - idim_flag <= '0'; - case decodedOpcode is - when Decoded_Interrupt => - sp <= sp - 1; - memAAddr <= sp - 1; - memAWriteEnable <= '1'; - memAWrite <= (others => DontCareValue); - memAWrite(maxAddrBit downto 0) <= pc; - pc <= to_unsigned(32, maxAddrBit+1); -- interrupt address - report "ZPU jumped to interrupt!" severity note; - when Decoded_Im => - idim_flag <= '1'; - memAWriteEnable <= '1'; - if (idim_flag='0') then - sp <= sp - 1; - memAAddr <= sp-1; - for i in wordSize-1 downto 7 loop - memAWrite(i) <= opcode(6); - end loop; - memAWrite(6 downto 0) <= unsigned(opcode(6 downto 0)); - else - memAAddr <= sp; - memAWrite(wordSize-1 downto 7) <= memARead(wordSize-8 downto 0); - memAWrite(6 downto 0) <= unsigned(opcode(6 downto 0)); - end if; - when Decoded_StoreSP => - memBWriteEnable <= '1'; - memBAddr <= sp+spOffset; - memBWrite <= memARead; - sp <= sp + 1; - state <= State_Resync; - when Decoded_LoadSP => - sp <= sp - 1; - memAAddr <= sp+spOffset; - when Decoded_Emulate => - sp <= sp - 1; - memAWriteEnable <= '1'; - memAAddr <= sp - 1; - memAWrite <= (others => DontCareValue); - memAWrite(maxAddrBit downto 0) <= pc + 1; - -- The emulate address is: - -- 98 7654 3210 - -- 0000 00aa aaa0 0000 - pc <= (others => '0'); - pc(9 downto 5) <= unsigned(opcode(4 downto 0)); - when Decoded_AddSP => - memAAddr <= sp; - memBAddr <= sp+spOffset; - state <= State_AddSP; - when Decoded_Break => - report "Break instruction encountered" severity failure; - break <= '1'; - when Decoded_PushSP => - memAWriteEnable <= '1'; - memAAddr <= sp - 1; - sp <= sp - 1; - memAWrite <= (others => DontCareValue); - memAWrite(maxAddrBit downto minAddrBit) <= sp; - when Decoded_PopPC => - pc <= memARead(maxAddrBit downto 0); - sp <= sp + 1; - state <= State_Resync; - when Decoded_Add => - sp <= sp + 1; - state <= State_Add; - when Decoded_Or => - sp <= sp + 1; - state <= State_Or; - when Decoded_And => - sp <= sp + 1; - state <= State_And; - when Decoded_Load => - if (memARead(ioBit)='1') then - out_mem_addr <= std_logic_vector(memARead(maxAddrBitIncIO downto 0)); - out_mem_readEnable <= '1'; - state <= State_ReadIO; - else - memAAddr <= memARead(maxAddrBit downto minAddrBit); - end if; - when Decoded_Not => - memAAddr <= sp(maxAddrBit downto minAddrBit); - memAWriteEnable <= '1'; - memAWrite <= not memARead; - when Decoded_Flip => - memAAddr <= sp(maxAddrBit downto minAddrBit); - memAWriteEnable <= '1'; - for i in 0 to wordSize-1 loop - memAWrite(i) <= memARead(wordSize-1-i); - end loop; - when Decoded_Store => - memBAddr <= sp + 1; - sp <= sp + 1; - if (memARead(ioBit)='1') then - state <= State_WriteIO; - else - state <= State_Store; - end if; - when Decoded_PopSP => - sp <= memARead(maxAddrBit downto minAddrBit); - state <= State_Resync; - when Decoded_Nop => - memAAddr <= sp; - when others => - null; - end case; - when State_ReadIO => - memAAddr <= sp; - if (in_mem_busy = '0') then - state <= State_Fetch; - memAWriteEnable <= '1'; - memAWrite <= unsigned(mem_read); - end if; - when State_WriteIO => - sp <= sp + 1; - out_mem_writeEnable <= '1'; - out_mem_addr <= std_logic_vector(memARead(maxAddrBitIncIO downto 0)); - mem_write <= std_logic_vector(memBRead); - state <= State_WriteIODone; - when State_WriteIODone => - if (in_mem_busy = '0') then - state <= State_Resync; - end if; - when State_Fetch => - -- We need to resync. During the *next* cycle - -- we'll fetch the opcode @ pc and thus it will - -- be available for State_Execute the cycle after - -- next - memBAddr <= pc(maxAddrBit downto minAddrBit); - state <= State_FetchNext; - when State_FetchNext => - -- at this point memARead contains the value that is either - -- from the top of stack or should be copied to the top of the stack - memAWriteEnable <= '1'; - memAWrite <= memARead; - memAAddr <= sp; - memBAddr <= sp + 1; - state <= State_Decode; - when State_Decode => - if interrupt='1' and inInterrupt='0' and idim_flag='0' then - -- We got an interrupt, execute interrupt instead of next instruction - inInterrupt <= '1'; - decodedOpcode <= Decoded_Interrupt; - end if; - -- during the State_Execute cycle we'll be fetching SP+1 - memAAddr <= sp; - memBAddr <= sp + 1; - state <= State_Execute; - when State_Store => - sp <= sp + 1; - memAWriteEnable <= '1'; - memAAddr <= memARead(maxAddrBit downto minAddrBit); - memAWrite <= memBRead; - state <= State_Resync; - when State_AddSP => - state <= State_Add; - when State_Add => - memAAddr <= sp; - memAWriteEnable <= '1'; - memAWrite <= memARead + memBRead; - state <= State_Fetch; - when State_Or => - memAAddr <= sp; - memAWriteEnable <= '1'; - memAWrite <= memARead or memBRead; - state <= State_Fetch; - when State_Resync => - memAAddr <= sp; - state <= State_Fetch; - when State_And => - memAAddr <= sp; - memAWriteEnable <= '1'; - memAWrite <= memARead and memBRead; - state <= State_Fetch; - when others => - null; - end case; - - end if; - end process; + -- generate a trace file. + -- + -- This is only used in simulation to see what instructions are + -- executed. + -- + -- a quick & dirty regression test is then to commit trace files + -- to CVS and compare the latest trace file against the last known + -- good trace file + traceFileGenerate : if Generate_Trace generate + trace_file : trace port map ( + clk => clk, + begin_inst => begin_inst, + pc => trace_pc, + opcode => trace_opcode, + sp => trace_sp, + memA => trace_topOfStack, + memB => trace_topOfStackB, + busy => busy, + intsp => (others => 'U') + ); + end generate; + + + -- mem_writeMask is not used in this design, tie it to 1 + mem_writeMask <= (others => '1'); + + + + memAAddr_stdlogic <= std_logic_vector(memAAddr(AddrBitBRAM_range)); + memAWrite_stdlogic <= std_logic_vector(memAWrite); + memBAddr_stdlogic <= std_logic_vector(memBAddr(AddrBitBRAM_range)); + memBWrite_stdlogic <= std_logic_vector(memBWrite); + + + -- dualport_ram must be defined by the application. + -- + -- How this can be implemented is highly dependent on the FPGA + -- and synthesis technology used. + -- + -- sometimes it can be instantiated as in the + -- zpu/example/helloworld.vhd, using inference, + -- but oftentimes it must be instantiated directly + -- portmapping to part specific FPGA resources + -- + -- + -- DANGER!!!!!! If inference fails, then synthesis will try + -- to implement the memory using basic logic resources. This + -- will almost certainly cause the compiler to get "stuck" + -- since synthesising such a huge number of basic logic resources + -- will take more or less forever. + -- + -- So: if your compiler gets "stuck" then inference is not + -- the way to go. + memory : dualport_ram port map ( + clk => clk, + memAWriteEnable => memAWriteEnable, + memAAddr => memAAddr_stdlogic, + memAWrite => memAWrite_stdlogic, + memARead => memARead_stdlogic, + memBWriteEnable => memBWriteEnable, + memBAddr => memBAddr_stdlogic, + memBWrite => memBWrite_stdlogic, + memBRead => memBRead_stdlogic + ); + memARead <= unsigned(memARead_stdlogic); + memBRead <= unsigned(memBRead_stdlogic); + + + + tOpcode_sel <= to_integer(pc(minAddrBit-1 downto 0)); + + + + -- move out calculation of the opcode to a seperate process + -- to make things a bit easier to read + decodeControl : process(memBRead, pc, tOpcode_sel) + variable tOpcode : std_logic_vector(OpCode_Size-1 downto 0); + begin + + -- simplify opcode selection a bit so it passes more synthesizers + case (tOpcode_sel) is + + when 0 => tOpcode := std_logic_vector(memBRead(31 downto 24)); + + when 1 => tOpcode := std_logic_vector(memBRead(23 downto 16)); + + when 2 => tOpcode := std_logic_vector(memBRead(15 downto 8)); + + when 3 => tOpcode := std_logic_vector(memBRead(7 downto 0)); + + when others => tOpcode := std_logic_vector(memBRead(7 downto 0)); + end case; + + sampledOpcode <= tOpcode; + + if (tOpcode(7 downto 7) = OpCode_Im) then + sampledDecodedOpcode <= Decoded_Im; + elsif (tOpcode(7 downto 5) = OpCode_StoreSP) then + sampledDecodedOpcode <= Decoded_StoreSP; + elsif (tOpcode(7 downto 5) = OpCode_LoadSP) then + sampledDecodedOpcode <= Decoded_LoadSP; + elsif (tOpcode(7 downto 5) = OpCode_Emulate) then + sampledDecodedOpcode <= Decoded_Emulate; + elsif (tOpcode(7 downto 4) = OpCode_AddSP) then + sampledDecodedOpcode <= Decoded_AddSP; + else + case tOpcode(3 downto 0) is + when OpCode_Break => + sampledDecodedOpcode <= Decoded_Break; + when OpCode_PushSP => + sampledDecodedOpcode <= Decoded_PushSP; + when OpCode_PopPC => + sampledDecodedOpcode <= Decoded_PopPC; + when OpCode_Add => + sampledDecodedOpcode <= Decoded_Add; + when OpCode_Or => + sampledDecodedOpcode <= Decoded_Or; + when OpCode_And => + sampledDecodedOpcode <= Decoded_And; + when OpCode_Load => + sampledDecodedOpcode <= Decoded_Load; + when OpCode_Not => + sampledDecodedOpcode <= Decoded_Not; + when OpCode_Flip => + sampledDecodedOpcode <= Decoded_Flip; + when OpCode_Store => + sampledDecodedOpcode <= Decoded_Store; + when OpCode_PopSP => + sampledDecodedOpcode <= Decoded_PopSP; + when others => + sampledDecodedOpcode <= Decoded_Nop; + end case; -- tOpcode(3 downto 0) + end if; tOpcode + end process; + + + opcodeControl: process(clk, areset) + variable spOffset : unsigned(4 downto 0); + begin + + if areset = '1' then + state <= State_Resync; + break <= '0'; + sp <= unsigned(spStart(maxAddrBit downto minAddrBit)); + pc <= (others => '0'); + idim_flag <= '0'; + begin_inst <= '0'; + memAAddr <= (others => '0'); + memBAddr <= (others => '0'); + memAWriteEnable <= '0'; + memBWriteEnable <= '0'; + out_mem_writeEnable <= '0'; + out_mem_readEnable <= '0'; + memAWrite <= (others => '0'); + memBWrite <= (others => '0'); + inInterrupt <= '0'; + + elsif (clk'event and clk = '1') then + memAWriteEnable <= '0'; + memBWriteEnable <= '0'; + -- This saves ca. 100 LUT's, by explicitly declaring that the + -- memAWrite can be left at whatever value if memAWriteEnable is + -- not set. + memAWrite <= (others => DontCareValue); + memBWrite <= (others => DontCareValue); +-- out_mem_addr <= (others => DontCareValue); +-- mem_write <= (others => DontCareValue); + spOffset := (others => DontCareValue); + memAAddr <= (others => DontCareValue); + memBAddr <= (others => DontCareValue); + + out_mem_writeEnable <= '0'; + out_mem_readEnable <= '0'; + begin_inst <= '0'; + out_mem_addr <= std_logic_vector(memARead(maxAddrBitIncIO downto 0)); + mem_write <= std_logic_vector(memBRead); + + decodedOpcode <= sampledDecodedOpcode; + opcode <= sampledOpcode; + if interrupt = '0' then + inInterrupt <= '0'; -- no longer in an interrupt + end if; + + case state is + + when State_Execute => + state <= State_Fetch; + -- at this point: + -- memBRead contains opcode word + -- memARead contains top of stack + pc <= pc + 1; + + -- trace + begin_inst <= '1'; + trace_pc <= (others => '0'); + trace_pc(maxAddrBit downto 0) <= std_logic_vector(pc); + trace_opcode <= opcode; + trace_sp <= (others => '0'); + trace_sp(maxAddrBit downto minAddrBit) <= std_logic_vector(sp); + trace_topOfStack <= std_logic_vector(memARead); + trace_topOfStackB <= std_logic_vector(memBRead); + + -- during the next cycle we'll be reading the next opcode + spOffset(4) := not opcode(4); + spOffset(3 downto 0) := unsigned(opcode(3 downto 0)); + + idim_flag <= '0'; + + case decodedOpcode is + + when Decoded_Interrupt => + sp <= sp - 1; + memAAddr <= sp - 1; + memAWriteEnable <= '1'; + memAWrite <= (others => DontCareValue); + memAWrite(maxAddrBit downto 0) <= pc; + pc <= to_unsigned(32, maxAddrBit+1); -- interrupt address + report "ZPU jumped to interrupt!" severity note; + + when Decoded_Im => + idim_flag <= '1'; + memAWriteEnable <= '1'; + if (idim_flag = '0') then + sp <= sp - 1; + memAAddr <= sp-1; + for i in wordSize-1 downto 7 loop + memAWrite(i) <= opcode(6); + end loop; + memAWrite(6 downto 0) <= unsigned(opcode(6 downto 0)); + else + memAAddr <= sp; + memAWrite(wordSize-1 downto 7) <= memARead(wordSize-8 downto 0); + memAWrite(6 downto 0) <= unsigned(opcode(6 downto 0)); + end if; -- idim_flag + + when Decoded_StoreSP => + memBWriteEnable <= '1'; + memBAddr <= sp+spOffset; + memBWrite <= memARead; + sp <= sp + 1; + state <= State_Resync; + + when Decoded_LoadSP => + sp <= sp - 1; + memAAddr <= sp+spOffset; + + when Decoded_Emulate => + sp <= sp - 1; + memAWriteEnable <= '1'; + memAAddr <= sp - 1; + memAWrite <= (others => DontCareValue); + memAWrite(maxAddrBit downto 0) <= pc + 1; + -- The emulate address is: + -- 98 7654 3210 + -- 0000 00aa aaa0 0000 + pc <= (others => '0'); + pc(9 downto 5) <= unsigned(opcode(4 downto 0)); + + when Decoded_AddSP => + memAAddr <= sp; + memBAddr <= sp+spOffset; + state <= State_AddSP; + + when Decoded_Break => + report "Break instruction encountered" severity failure; + break <= '1'; + + when Decoded_PushSP => + memAWriteEnable <= '1'; + memAAddr <= sp - 1; + sp <= sp - 1; + memAWrite <= (others => DontCareValue); + memAWrite(maxAddrBit downto minAddrBit) <= sp; + + when Decoded_PopPC => + pc <= memARead(maxAddrBit downto 0); + sp <= sp + 1; + state <= State_Resync; + + when Decoded_Add => + sp <= sp + 1; + state <= State_Add; + + when Decoded_Or => + sp <= sp + 1; + state <= State_Or; + + when Decoded_And => + sp <= sp + 1; + state <= State_And; + + when Decoded_Load => + if (memARead(ioBit) = '1') then + out_mem_addr <= std_logic_vector(memARead(maxAddrBitIncIO downto 0)); + out_mem_readEnable <= '1'; + state <= State_ReadIO; + else + memAAddr <= memARead(maxAddrBit downto minAddrBit); + end if; + + when Decoded_Not => + memAAddr <= sp(maxAddrBit downto minAddrBit); + memAWriteEnable <= '1'; + memAWrite <= not memARead; + + when Decoded_Flip => + memAAddr <= sp(maxAddrBit downto minAddrBit); + memAWriteEnable <= '1'; + for i in 0 to wordSize-1 loop + memAWrite(i) <= memARead(wordSize-1-i); + end loop; + + when Decoded_Store => + memBAddr <= sp + 1; + sp <= sp + 1; + if (memARead(ioBit) = '1') then + state <= State_WriteIO; + else + state <= State_Store; + end if; + + when Decoded_PopSP => + sp <= memARead(maxAddrBit downto minAddrBit); + state <= State_Resync; + + when Decoded_Nop => + memAAddr <= sp; + + when others => + null; + + end case; -- decodedOpcode + + when State_ReadIO => + memAAddr <= sp; + if (in_mem_busy = '0') then + state <= State_Fetch; + memAWriteEnable <= '1'; + memAWrite <= unsigned(mem_read); + end if; + + when State_WriteIO => + sp <= sp + 1; + out_mem_writeEnable <= '1'; + out_mem_addr <= std_logic_vector(memARead(maxAddrBitIncIO downto 0)); + mem_write <= std_logic_vector(memBRead); + state <= State_WriteIODone; + + when State_WriteIODone => + if (in_mem_busy = '0') then + state <= State_Resync; + end if; + + when State_Fetch => + -- We need to resync. During the *next* cycle + -- we'll fetch the opcode @ pc and thus it will + -- be available for State_Execute the cycle after + -- next + memBAddr <= pc(maxAddrBit downto minAddrBit); + state <= State_FetchNext; + + when State_FetchNext => + -- at this point memARead contains the value that is either + -- from the top of stack or should be copied to the top of the stack + memAWriteEnable <= '1'; + memAWrite <= memARead; + memAAddr <= sp; + memBAddr <= sp + 1; + state <= State_Decode; + + when State_Decode => + if interrupt = '1' and inInterrupt = '0' and idim_flag = '0' then + -- We got an interrupt, execute interrupt instead of next instruction + inInterrupt <= '1'; + decodedOpcode <= Decoded_Interrupt; + end if; + -- during the State_Execute cycle we'll be fetching SP+1 + memAAddr <= sp; + memBAddr <= sp + 1; + state <= State_Execute; + + when State_Store => + sp <= sp + 1; + memAWriteEnable <= '1'; + memAAddr <= memARead(maxAddrBit downto minAddrBit); + memAWrite <= memBRead; + state <= State_Resync; + + when State_AddSP => + state <= State_Add; + + when State_Add => + memAAddr <= sp; + memAWriteEnable <= '1'; + memAWrite <= memARead + memBRead; + state <= State_Fetch; + + when State_Or => + memAAddr <= sp; + memAWriteEnable <= '1'; + memAWrite <= memARead or memBRead; + state <= State_Fetch; + + when State_Resync => + memAAddr <= sp; + state <= State_Fetch; + + when State_And => + memAAddr <= sp; + memAWriteEnable <= '1'; + memAWrite <= memARead and memBRead; + state <= State_Fetch; + + when others => + null; + + end case; -- state + + end if; -- reset, enable + end process; diff --git a/zpu/hdl/zpu4/core/zpupkg.vhd b/zpu/hdl/zpu4/core/zpupkg.vhd index 59d26e5..f6823f5 100644 --- a/zpu/hdl/zpu4/core/zpupkg.vhd +++ b/zpu/hdl/zpu4/core/zpupkg.vhd @@ -32,173 +32,187 @@ -- are those of the authors and should not be interpreted as representing -- official policies, either expressed or implied, of the ZPU Project. -library IEEE; -use IEEE.STD_LOGIC_1164.all; +library ieee; +use ieee.std_logic_1164.all; use ieee.numeric_std.all; library work; use work.zpu_config.all; + package zpupkg is - -- This bit is set for read/writes to IO - -- FIX!!! eventually this should be set to wordSize-1 so as to - -- to make the address of IO independent of amount of memory - -- reserved for CPU. Requires trivial tweaks in toolchain/runtime - -- libraries. - - constant byteBits : integer := wordPower-3; -- # of bits in a word that addresses bytes - constant maxAddrBit : integer := maxAddrBitIncIO-1; - constant ioBit : integer := maxAddrBit+1; - constant wordSize : integer := 2**wordPower; - constant wordBytes : integer := wordSize/8; - constant minAddrBit : integer := byteBits; - -- configurable internal stack size. Probably going to be 16 after toolchain is done - constant stack_bits : integer := 5; - constant stack_size : integer := 2**stack_bits; - - - component dualport_ram is - port (clk : in std_logic; - memAWriteEnable : in std_logic; - memAAddr : in std_logic_vector(maxAddrBitBRAM downto minAddrBit); - memAWrite : in std_logic_vector(wordSize-1 downto 0); - memARead : out std_logic_vector(wordSize-1 downto 0); - memBWriteEnable : in std_logic; - memBAddr : in std_logic_vector(maxAddrBitBRAM downto minAddrBit); - memBWrite : in std_logic_vector(wordSize-1 downto 0); - memBRead : out std_logic_vector(wordSize-1 downto 0)); - end component; - - - component dram is - port (clk : in std_logic; - areset : in std_logic; - mem_writeEnable : in std_logic; - mem_readEnable : in std_logic; - mem_addr : in std_logic_vector(maxAddrBit downto 0); - mem_write : in std_logic_vector(wordSize-1 downto 0); - mem_read : out std_logic_vector(wordSize-1 downto 0); - mem_busy : out std_logic; - mem_writeMask : in std_logic_vector(wordBytes-1 downto 0)); - end component; - - - component trace is - port( - clk : in std_logic; - begin_inst : in std_logic; - pc : in std_logic_vector(maxAddrBitIncIO downto 0); - opcode : in std_logic_vector(7 downto 0); - sp : in std_logic_vector(maxAddrBitIncIO downto minAddrBit); - memA : in std_logic_vector(wordSize-1 downto 0); - memB : in std_logic_vector(wordSize-1 downto 0); - busy : in std_logic; - intSp : in std_logic_vector(stack_bits-1 downto 0) - ); - end component; - - component zpu_core is - port ( clk : in std_logic; - areset : in std_logic; - enable : in std_logic; - in_mem_busy : in std_logic; - mem_read : in std_logic_vector(wordSize-1 downto 0); - mem_write : out std_logic_vector(wordSize-1 downto 0); - out_mem_addr : out std_logic_vector(maxAddrBitIncIO downto 0); - out_mem_writeEnable : out std_logic; - out_mem_readEnable : out std_logic; - mem_writeMask: out std_logic_vector(wordBytes-1 downto 0); - interrupt : in std_logic; - break : out std_logic); - end component; - - - - component timer is - port( - clk : in std_logic; - areset : in std_logic; - we : in std_logic; - din : in std_logic_vector(7 downto 0); - adr : in std_logic_vector(2 downto 0); - dout : out std_logic_vector(7 downto 0)); - end component; - - component zpuio is - port ( areset : in std_logic; - cpu_clk : in std_logic; - clk_status : in std_logic_vector(2 downto 0); - cpu_din : in std_logic_vector(15 downto 0); - cpu_a : in std_logic_vector(20 downto 0); - cpu_we : in std_logic_vector(1 downto 0); - cpu_re : in std_logic; - cpu_dout : inout std_logic_vector(15 downto 0)); - end component; - - - - - -- opcode decode constants - constant OpCode_Im : std_logic_vector(7 downto 7) := "1"; - constant OpCode_StoreSP : std_logic_vector(7 downto 5) := "010"; - constant OpCode_LoadSP : std_logic_vector(7 downto 5) := "011"; - constant OpCode_Emulate : std_logic_vector(7 downto 5) := "001"; - constant OpCode_AddSP : std_logic_vector(7 downto 4) := "0001"; - constant OpCode_Short : std_logic_vector(7 downto 4) := "0000"; - - constant OpCode_Break : std_logic_vector(3 downto 0) := "0000"; - constant OpCode_NA4 : std_logic_vector(3 downto 0) := "0001"; - constant OpCode_PushSP : std_logic_vector(3 downto 0) := "0010"; - constant OpCode_NA3 : std_logic_vector(3 downto 0) := "0011"; - - constant OpCode_PopPC : std_logic_vector(3 downto 0) := "0100"; - constant OpCode_Add : std_logic_vector(3 downto 0) := "0101"; - constant OpCode_And : std_logic_vector(3 downto 0) := "0110"; - constant OpCode_Or : std_logic_vector(3 downto 0) := "0111"; - - constant OpCode_Load : std_logic_vector(3 downto 0) := "1000"; - constant OpCode_Not : std_logic_vector(3 downto 0) := "1001"; - constant OpCode_Flip : std_logic_vector(3 downto 0) := "1010"; - constant OpCode_Nop : std_logic_vector(3 downto 0) := "1011"; - - constant OpCode_Store : std_logic_vector(3 downto 0) := "1100"; - constant OpCode_PopSP : std_logic_vector(3 downto 0) := "1101"; - constant OpCode_NA2 : std_logic_vector(3 downto 0) := "1110"; - constant OpCode_NA : std_logic_vector(3 downto 0) := "1111"; - - constant OpCode_Lessthan : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(36, 6)); - constant OpCode_Lessthanorequal : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(37, 6)); - constant OpCode_Ulessthan : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(38, 6)); - constant OpCode_Ulessthanorequal : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(39, 6)); - - constant OpCode_Swap : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(40, 6)); - constant OpCode_Mult : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(41, 6)); - - constant OpCode_Lshiftright : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(42, 6)); - constant OpCode_Ashiftleft : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(43, 6)); - constant OpCode_Ashiftright : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(44, 6)); - constant OpCode_Call : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(45, 6)); - - constant OpCode_Eq : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(46, 6)); - constant OpCode_Neq : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(47, 6)); - - constant OpCode_Sub : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(49, 6)); - constant OpCode_Loadb : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(51, 6)); - constant OpCode_Storeb : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(52, 6)); - - constant OpCode_Eqbranch : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(55, 6)); - constant OpCode_Neqbranch : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(56, 6)); - constant OpCode_Poppcrel : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(57, 6)); - - constant OpCode_Pushspadd : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(61, 6)); - constant OpCode_Mult16x16 : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(62, 6)); - constant OpCode_Callpcrel : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(63, 6)); - - - - constant OpCode_Size : integer := 8; - - - + -- This bit is set for read/writes to IO + -- FIX!!! eventually this should be set to wordSize-1 so as to + -- to make the address of IO independent of amount of memory + -- reserved for CPU. Requires trivial tweaks in toolchain/runtime + -- libraries. + + constant byteBits : integer := wordPower-3; -- # of bits in a word that addresses bytes + constant maxAddrBit : integer := maxAddrBitIncIO-1; + constant ioBit : integer := maxAddrBit+1; + constant wordSize : integer := 2**wordPower; + constant wordBytes : integer := wordSize/8; + constant minAddrBit : integer := byteBits; + -- configurable internal stack size. Probably going to be 16 after toolchain is done + constant stack_bits : integer := 5; + constant stack_size : integer := 2**stack_bits; + + + ------------------------------------------------------------ + -- components + + component dualport_ram is + port ( + clk : in std_logic; + memAWriteEnable : in std_logic; + memAAddr : in std_logic_vector(maxAddrBitBRAM downto minAddrBit); + memAWrite : in std_logic_vector(wordSize-1 downto 0); + memARead : out std_logic_vector(wordSize-1 downto 0); + memBWriteEnable : in std_logic; + memBAddr : in std_logic_vector(maxAddrBitBRAM downto minAddrBit); + memBWrite : in std_logic_vector(wordSize-1 downto 0); + memBRead : out std_logic_vector(wordSize-1 downto 0) + ); + end component dualport_ram; + + + component dram is + port ( + clk : in std_logic; + areset : in std_logic; + mem_writeEnable : in std_logic; + mem_readEnable : in std_logic; + mem_addr : in std_logic_vector(maxAddrBit downto 0); + mem_write : in std_logic_vector(wordSize-1 downto 0); + mem_read : out std_logic_vector(wordSize-1 downto 0); + mem_busy : out std_logic; + mem_writeMask : in std_logic_vector(wordBytes-1 downto 0) + ); + end component dram; + + + component trace is + port ( + clk : in std_logic; + begin_inst : in std_logic; + pc : in std_logic_vector(maxAddrBitIncIO downto 0); + opcode : in std_logic_vector(7 downto 0); + sp : in std_logic_vector(maxAddrBitIncIO downto minAddrBit); + memA : in std_logic_vector(wordSize-1 downto 0); + memB : in std_logic_vector(wordSize-1 downto 0); + busy : in std_logic; + intSp : in std_logic_vector(stack_bits-1 downto 0) + ); + end component trace; + + + component zpu_core is + port ( + clk : in std_logic; + areset : in std_logic; + enable : in std_logic; + in_mem_busy : in std_logic; + mem_read : in std_logic_vector(wordSize-1 downto 0); + mem_write : out std_logic_vector(wordSize-1 downto 0); + out_mem_addr : out std_logic_vector(maxAddrBitIncIO downto 0); + out_mem_writeEnable : out std_logic; + out_mem_readEnable : out std_logic; + mem_writeMask : out std_logic_vector(wordBytes-1 downto 0); + interrupt : in std_logic; + break : out std_logic + ); + end component zpu_core; + + + component timer is + port ( + clk : in std_logic; + areset : in std_logic; + we : in std_logic; + din : in std_logic_vector(7 downto 0); + adr : in std_logic_vector(2 downto 0); + dout : out std_logic_vector(7 downto 0) + ); + end component timer; + + + component zpuio is + port ( + areset : in std_logic; + cpu_clk : in std_logic; + clk_status : in std_logic_vector(2 downto 0); + cpu_din : in std_logic_vector(15 downto 0); + cpu_a : in std_logic_vector(20 downto 0); + cpu_we : in std_logic_vector(1 downto 0); + cpu_re : in std_logic; + cpu_dout : inout std_logic_vector(15 downto 0) + ); + end component zpuio; + + + ------------------------------------------------------------ + -- constants + + -- opcode decode constants + constant OpCode_Im : std_logic_vector(7 downto 7) := "1"; + constant OpCode_StoreSP : std_logic_vector(7 downto 5) := "010"; + constant OpCode_LoadSP : std_logic_vector(7 downto 5) := "011"; + constant OpCode_Emulate : std_logic_vector(7 downto 5) := "001"; + constant OpCode_AddSP : std_logic_vector(7 downto 4) := "0001"; + constant OpCode_Short : std_logic_vector(7 downto 4) := "0000"; + -- + constant OpCode_Break : std_logic_vector(3 downto 0) := "0000"; + constant OpCode_NA4 : std_logic_vector(3 downto 0) := "0001"; + constant OpCode_PushSP : std_logic_vector(3 downto 0) := "0010"; + constant OpCode_NA3 : std_logic_vector(3 downto 0) := "0011"; + -- + constant OpCode_PopPC : std_logic_vector(3 downto 0) := "0100"; + constant OpCode_Add : std_logic_vector(3 downto 0) := "0101"; + constant OpCode_And : std_logic_vector(3 downto 0) := "0110"; + constant OpCode_Or : std_logic_vector(3 downto 0) := "0111"; + -- + constant OpCode_Load : std_logic_vector(3 downto 0) := "1000"; + constant OpCode_Not : std_logic_vector(3 downto 0) := "1001"; + constant OpCode_Flip : std_logic_vector(3 downto 0) := "1010"; + constant OpCode_Nop : std_logic_vector(3 downto 0) := "1011"; + -- + constant OpCode_Store : std_logic_vector(3 downto 0) := "1100"; + constant OpCode_PopSP : std_logic_vector(3 downto 0) := "1101"; + constant OpCode_NA2 : std_logic_vector(3 downto 0) := "1110"; + constant OpCode_NA : std_logic_vector(3 downto 0) := "1111"; + -- + constant OpCode_Lessthan : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(36, 6)); + constant OpCode_Lessthanorequal : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(37, 6)); + constant OpCode_Ulessthan : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(38, 6)); + constant OpCode_Ulessthanorequal : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(39, 6)); + -- + constant OpCode_Swap : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(40, 6)); + constant OpCode_Mult : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(41, 6)); + -- + constant OpCode_Lshiftright : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(42, 6)); + constant OpCode_Ashiftleft : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(43, 6)); + constant OpCode_Ashiftright : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(44, 6)); + constant OpCode_Call : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(45, 6)); + -- + constant OpCode_Eq : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(46, 6)); + constant OpCode_Neq : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(47, 6)); + -- + constant OpCode_Sub : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(49, 6)); + constant OpCode_Loadb : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(51, 6)); + constant OpCode_Storeb : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(52, 6)); + -- + constant OpCode_Eqbranch : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(55, 6)); + constant OpCode_Neqbranch : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(56, 6)); + constant OpCode_Poppcrel : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(57, 6)); + -- + constant OpCode_Pushspadd : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(61, 6)); + constant OpCode_Mult16x16 : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(62, 6)); + constant OpCode_Callpcrel : std_logic_vector(5 downto 0) := std_logic_vector(to_unsigned(63, 6)); + -- + -- + constant OpCode_Size : integer := 8; + + + end zpupkg; -- cgit v1.1