772 lines
44 KiB
VHDL
772 lines
44 KiB
VHDL
-- ZPU
|
|
--
|
|
-- Copyright 2004-2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
|
|
--
|
|
-- The FreeBSD license
|
|
--
|
|
-- Redistribution and use in source and binary forms, with or without
|
|
-- modification, are permitted provided that the following conditions
|
|
-- are met:
|
|
--
|
|
-- 1. Redistributions of source code must retain the above copyright
|
|
-- notice, this list of conditions and the following disclaimer.
|
|
-- 2. Redistributions in binary form must reproduce the above
|
|
-- copyright notice, this list of conditions and the following
|
|
-- disclaimer in the documentation and/or other materials
|
|
-- provided with the distribution.
|
|
--
|
|
-- THIS SOFTWARE IS PROVIDED BY THE ZPU PROJECT ``AS IS'' AND ANY
|
|
-- EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
-- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
-- ZPU PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
-- INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
-- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
-- STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
-- ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
--
|
|
-- The views and conclusions contained in the software and documentation
|
|
-- 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;
|
|
use ieee.numeric_std.all;
|
|
|
|
library work;
|
|
use work.zpu_pkg.all;
|
|
|
|
entity zpu_core_small is
|
|
generic (
|
|
CLK_FREQ : integer := 100000000; -- Frequency of the input clock.
|
|
STACK_ADDR : integer := 0 -- Initial stack address on CPU start.
|
|
);
|
|
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(WORD_32BIT_RANGE);
|
|
mem_write : out std_logic_vector(WORD_32BIT_RANGE);
|
|
out_mem_addr : out std_logic_vector(ADDR_BIT_RANGE);
|
|
out_mem_writeEnable : out std_logic;
|
|
out_mem_bEnable : out std_logic; -- Enable byte write
|
|
out_mem_hEnable : out std_logic; -- Enable halfword write
|
|
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(WORD_4BYTE_RANGE);
|
|
-- 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_request : in std_logic;
|
|
interrupt_ack : out std_logic; -- Interrupt acknowledge, ZPU has entered Interrupt Service Routine.
|
|
interrupt_done : out std_logic; -- Interrupt service routine completed/done.
|
|
-- Signal that the break instruction is executed, normally only used
|
|
-- in simulation to stop simulation
|
|
break : out std_logic;
|
|
debug_txd : out std_logic; -- Debug serial output.
|
|
--
|
|
MEM_A_WRITE_ENABLE : out std_logic;
|
|
MEM_A_ADDR : out std_logic_vector(ADDR_32BIT_RANGE);
|
|
MEM_A_WRITE : out std_logic_vector(WORD_32BIT_RANGE);
|
|
MEM_B_WRITE_ENABLE : out std_logic;
|
|
MEM_B_ADDR : out std_logic_vector(ADDR_32BIT_RANGE);
|
|
MEM_B_WRITE : out std_logic_vector(WORD_32BIT_RANGE);
|
|
MEM_A_READ : in std_logic_vector(WORD_32BIT_RANGE);
|
|
MEM_B_READ : in std_logic_vector(WORD_32BIT_RANGE)
|
|
);
|
|
end zpu_core_small;
|
|
|
|
architecture behave of zpu_core_small is
|
|
|
|
-- 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,
|
|
State_Debug
|
|
);
|
|
|
|
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
|
|
);
|
|
|
|
--
|
|
type DebugType is
|
|
(
|
|
Debug_Start,
|
|
Debug_DumpFifo,
|
|
Debug_DumpFifo_1,
|
|
Debug_End
|
|
);
|
|
|
|
signal readIO : std_logic;
|
|
|
|
signal memAWriteEnable : std_logic;
|
|
signal memAAddr : unsigned(ADDR_32BIT_RANGE);
|
|
signal memAWrite : unsigned(WORD_32BIT_RANGE);
|
|
signal memARead : unsigned(WORD_32BIT_RANGE);
|
|
signal memBWriteEnable : std_logic;
|
|
signal memBAddr : unsigned(ADDR_32BIT_RANGE);
|
|
signal memBWrite : unsigned(WORD_32BIT_RANGE);
|
|
signal memBRead : unsigned(WORD_32BIT_RANGE);
|
|
|
|
signal pc : unsigned(ADDR_BIT_RANGE);
|
|
signal sp : unsigned(ADDR_32BIT_RANGE);
|
|
signal interrupt_suspended_addr : unsigned(ADDR_BIT_RANGE);
|
|
|
|
-- 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(ADDR_BIT_RANGE);
|
|
signal trace_sp : std_logic_vector(ADDR_32BIT_RANGE);
|
|
signal trace_topOfStack : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal trace_topOfStackB : std_logic_vector(WORD_32BIT_RANGE);
|
|
signal debugState : DebugType;
|
|
signal debugCnt : integer;
|
|
signal debugRec : zpu_dbg_t;
|
|
signal debugLoad : std_logic;
|
|
signal debugReady : std_logic;
|
|
|
|
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 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;
|
|
|
|
|
|
-- Not yet implemented.
|
|
out_mem_bEnable <= '0'; -- Enable byte write
|
|
out_mem_hEnable <= '0'; -- Enable halfword write
|
|
|
|
-- Wire up the RAM/ROM
|
|
MEM_A_ADDR <= std_logic_vector(memAAddr(ADDR_32BIT_RANGE));
|
|
MEM_A_WRITE <= std_logic_vector(memAWrite);
|
|
MEM_B_ADDR <= std_logic_vector(memBAddr(ADDR_32BIT_RANGE));
|
|
MEM_B_WRITE <= std_logic_vector(memBWrite);
|
|
memARead <= unsigned(MEM_A_READ);
|
|
memBRead <= unsigned(MEM_B_READ);
|
|
MEM_A_WRITE_ENABLE <= memAWriteEnable;
|
|
MEM_B_WRITE_ENABLE <= memBWriteEnable;
|
|
|
|
-- mem_writeMask is not used in this design, tie it to 1
|
|
mem_writeMask <= (others => '1');
|
|
|
|
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 <= to_unsigned(STACK_ADDR, maxAddrBit)(ADDR_32BIT_RANGE);
|
|
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';
|
|
interrupt_ack <= '0';
|
|
interrupt_done <= '0';
|
|
if DEBUG_CPU = true then
|
|
debugRec <= ZPU_DBG_T_INIT;
|
|
debugCnt <= 0;
|
|
debugLoad <= '0';
|
|
end if;
|
|
|
|
elsif (clk'event and clk = '1') then
|
|
|
|
if DEBUG_CPU = true then
|
|
debugLoad <= '0';
|
|
end if;
|
|
|
|
memAWriteEnable <= '0';
|
|
memBWriteEnable <= '0';
|
|
|
|
-- If the cpu can run, continue with next state.
|
|
--
|
|
if DEBUG_CPU = false or (DEBUG_CPU = true and debugReady = '1') then
|
|
|
|
-- 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(ADDR_BIT_RANGE));
|
|
mem_write <= std_logic_vector(memBRead);
|
|
|
|
decodedOpcode <= sampledDecodedOpcode;
|
|
opcode <= sampledOpcode;
|
|
|
|
-- If interrupt is active, we only clear the interrupt state once the PC is reset to the address which was suspended after the
|
|
-- interrupt, this prevents recursive interrupt triggers, desirable in cetain circumstances but not for this current design.
|
|
--
|
|
interrupt_ack <= '0'; -- Reset interrupt acknowledge if set, width is 1 clock only.
|
|
interrupt_done <= '0'; -- Reset interrupt done if set, width is 1 clock only.
|
|
if inInterrupt = '1' and pc(ADDR_BIT_RANGE) = interrupt_suspended_addr(ADDR_BIT_RANGE) then
|
|
inInterrupt <= '0'; -- no longer in an interrupt
|
|
interrupt_done <= '1'; -- Interrupt service routine complete.
|
|
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(ADDR_BIT_RANGE) <= std_logic_vector(pc);
|
|
--trace_opcode <= opcode;
|
|
--trace_sp <= (others => '0');
|
|
--trace_sp(ADDR_32BIT_RANGE) <= 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));
|
|
|
|
-- Debug code, if enabled, writes out the current instruction.
|
|
if DEBUG_CPU = true and DEBUG_LEVEL >= 1 then
|
|
debugRec.FMT_DATA_PRTMODE <= "00";
|
|
debugRec.FMT_PRE_SPACE <= '0';
|
|
debugRec.FMT_POST_SPACE <= '0';
|
|
debugRec.FMT_PRE_CR <= '1';
|
|
debugRec.FMT_POST_CRLF <= '1';
|
|
debugRec.FMT_SPLIT_DATA <= "00";
|
|
debugRec.DATA_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA2_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA3_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA4_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.WRITE_DATA <= '0';
|
|
debugRec.WRITE_DATA2 <= '0';
|
|
debugRec.WRITE_DATA3 <= '0';
|
|
debugRec.WRITE_DATA4 <= '0';
|
|
debugRec.WRITE_OPCODE <= '1';
|
|
debugRec.WRITE_DECODED_OPCODE <= '1';
|
|
debugRec.WRITE_PC <= '1';
|
|
debugRec.WRITE_SP <= '1';
|
|
debugRec.WRITE_STACK_TOS <= '1';
|
|
debugRec.WRITE_STACK_NOS <= '1';
|
|
debugRec.DATA(63 downto 0) <= (others => '0');
|
|
debugRec.DATA2(63 downto 0) <= (others => '0');
|
|
debugRec.DATA3(63 downto 0) <= (others => '0');
|
|
debugRec.DATA4(63 downto 0) <= (others => '0');
|
|
debugRec.OPCODE <= opcode;
|
|
debugRec.DECODED_OPCODE <= std_logic_vector(to_unsigned(DecodedOpcodeType'POS(decodedOpcode), 6));
|
|
debugRec.PC(ADDR_BIT_RANGE) <= std_logic_vector(pc);
|
|
debugRec.SP(ADDR_32BIT_RANGE) <= std_logic_vector(sp);
|
|
debugRec.STACK_TOS <= std_logic_vector(memARead);
|
|
debugRec.STACK_NOS <= std_logic_vector(memBRead);
|
|
debugLoad <= '1';
|
|
end if;
|
|
|
|
idim_flag <= '0';
|
|
case decodedOpcode is
|
|
when Decoded_Interrupt =>
|
|
interrupt_ack <= '1'; -- Acknowledge interrupt.
|
|
interrupt_suspended_addr <= pc(ADDR_BIT_RANGE); -- Save address which got interrupted.
|
|
sp <= sp - 1;
|
|
memAAddr <= sp - 1;
|
|
memAWriteEnable <= '1';
|
|
memAWrite <= (others => DontCareValue);
|
|
memAWrite(ADDR_BIT_RANGE) <= pc;
|
|
pc <= to_unsigned(32, maxAddrBit); -- 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(ADDR_BIT_RANGE) <= 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(ADDR_32BIT_RANGE) <= sp;
|
|
when Decoded_PopPC =>
|
|
pc <= memARead(ADDR_BIT_RANGE);
|
|
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(ADDR_BIT_RANGE));
|
|
out_mem_readEnable <= '1';
|
|
state <= State_ReadIO;
|
|
else
|
|
memAAddr <= memARead(ADDR_32BIT_RANGE);
|
|
end if;
|
|
when Decoded_Not =>
|
|
memAAddr <= sp(ADDR_32BIT_RANGE);
|
|
memAWriteEnable <= '1';
|
|
memAWrite <= not memARead;
|
|
when Decoded_Flip =>
|
|
memAAddr <= sp(ADDR_32BIT_RANGE);
|
|
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(ADDR_32BIT_RANGE);
|
|
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(ADDR_BIT_RANGE));
|
|
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(ADDR_32BIT_RANGE);
|
|
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;
|
|
|
|
-- If debug enabled, write out state during fetch.
|
|
if DEBUG_CPU = true and DEBUG_LEVEL >= 2 then
|
|
debugRec.FMT_DATA_PRTMODE <= "00";
|
|
debugRec.FMT_PRE_SPACE <= '0';
|
|
debugRec.FMT_POST_SPACE <= '0';
|
|
debugRec.FMT_PRE_CR <= '1';
|
|
debugRec.FMT_POST_CRLF <= '1';
|
|
debugRec.FMT_SPLIT_DATA <= "00";
|
|
debugRec.DATA_BYTECNT <= std_logic_vector(to_unsigned(4, 3));
|
|
debugRec.DATA2_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA3_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA4_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.WRITE_DATA <= '1';
|
|
debugRec.WRITE_DATA2 <= '0';
|
|
debugRec.WRITE_DATA3 <= '0';
|
|
debugRec.WRITE_DATA4 <= '0';
|
|
debugRec.WRITE_OPCODE <= '0';
|
|
debugRec.WRITE_DECODED_OPCODE <= '0';
|
|
debugRec.WRITE_PC <= '1';
|
|
debugRec.WRITE_SP <= '1';
|
|
debugRec.WRITE_STACK_TOS <= '1';
|
|
debugRec.WRITE_STACK_NOS <= '1';
|
|
debugRec.DATA(63 downto 0) <= X"4645544348000000";
|
|
debugRec.DATA2(63 downto 0) <= (others => '0');
|
|
debugRec.DATA3(63 downto 0) <= (others => '0');
|
|
debugRec.DATA4(63 downto 0) <= (others => '0');
|
|
debugRec.OPCODE <= (others => '0');
|
|
debugRec.DECODED_OPCODE <= (others => '0');
|
|
debugRec.PC(ADDR_BIT_RANGE) <= std_logic_vector(pc);
|
|
debugRec.SP(ADDR_32BIT_RANGE) <= std_logic_vector(sp);
|
|
debugRec.STACK_TOS <= std_logic_vector(memARead);
|
|
debugRec.STACK_NOS <= std_logic_vector(memBRead);
|
|
debugLoad <= '1';
|
|
end if;
|
|
when State_Decode =>
|
|
if interrupt_request='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(ADDR_32BIT_RANGE);
|
|
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 State_Debug =>
|
|
case debugState is
|
|
when Debug_Start =>
|
|
|
|
-- Write out the primary data.
|
|
if DEBUG_CPU = true then
|
|
debugRec.FMT_DATA_PRTMODE <= "00";
|
|
debugRec.FMT_PRE_SPACE <= '0';
|
|
debugRec.FMT_POST_SPACE <= '0';
|
|
debugRec.FMT_PRE_CR <= '1';
|
|
debugRec.FMT_POST_CRLF <= '0';
|
|
debugRec.FMT_SPLIT_DATA <= "00";
|
|
debugRec.DATA_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA2_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA3_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA4_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.WRITE_DATA <= '0';
|
|
debugRec.WRITE_DATA2 <= '0';
|
|
debugRec.WRITE_DATA3 <= '0';
|
|
debugRec.WRITE_DATA4 <= '0';
|
|
debugRec.WRITE_OPCODE <= '0';
|
|
debugRec.WRITE_DECODED_OPCODE <= '0';
|
|
debugRec.WRITE_PC <= '1';
|
|
debugRec.WRITE_SP <= '1';
|
|
debugRec.WRITE_STACK_TOS <= '1';
|
|
debugRec.WRITE_STACK_NOS <= '1';
|
|
debugRec.DATA(63 downto 0) <= (others => '0');
|
|
debugRec.DATA2(63 downto 0) <= (others => '0');
|
|
debugRec.DATA3(63 downto 0) <= (others => '0');
|
|
debugRec.DATA4(63 downto 0) <= (others => '0');
|
|
debugRec.OPCODE <= (others => '0');
|
|
debugRec.DECODED_OPCODE <= (others => '0');
|
|
debugRec.PC(ADDR_BIT_RANGE) <= std_logic_vector(pc);
|
|
debugRec.SP(ADDR_32BIT_RANGE) <= std_logic_vector(sp);
|
|
debugRec.STACK_TOS <= std_logic_vector(memARead);
|
|
debugRec.STACK_NOS <= std_logic_vector(memBRead);
|
|
debugLoad <= '1';
|
|
debugCnt <= 0;
|
|
debugState <= Debug_DumpFifo;
|
|
end if;
|
|
|
|
when Debug_DumpFifo =>
|
|
-- Write out the opcode.
|
|
if DEBUG_CPU = true then
|
|
debugRec.FMT_DATA_PRTMODE <= "00";
|
|
debugRec.FMT_PRE_SPACE <= '0';
|
|
debugRec.FMT_POST_SPACE <= '1';
|
|
debugRec.FMT_PRE_CR <= '0';
|
|
if debugCnt = 3 then
|
|
debugRec.FMT_POST_CRLF <= '1';
|
|
else
|
|
debugRec.FMT_POST_CRLF <= '0';
|
|
end if;
|
|
debugRec.FMT_SPLIT_DATA <= "00";
|
|
debugRec.DATA_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA2_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA3_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.DATA4_BYTECNT <= std_logic_vector(to_unsigned(0, 3));
|
|
debugRec.WRITE_DATA <= '0';
|
|
debugRec.WRITE_DATA2 <= '0';
|
|
debugRec.WRITE_DATA3 <= '0';
|
|
debugRec.WRITE_DATA4 <= '0';
|
|
debugRec.WRITE_OPCODE <= '1';
|
|
debugRec.WRITE_DECODED_OPCODE <= '1';
|
|
debugRec.WRITE_PC <= '0';
|
|
debugRec.WRITE_SP <= '0';
|
|
debugRec.WRITE_STACK_TOS <= '0';
|
|
debugRec.WRITE_STACK_NOS <= '0';
|
|
debugRec.DATA(63 downto 0) <= (others => '0');
|
|
debugRec.DATA2(63 downto 0) <= (others => '0');
|
|
debugRec.DATA3(63 downto 0) <= (others => '0');
|
|
debugRec.DATA4(63 downto 0) <= (others => '0');
|
|
debugRec.OPCODE <= opcode;
|
|
debugRec.DECODED_OPCODE <= std_logic_vector(to_unsigned(DecodedOpcodeType'POS(decodedOpcode), 6));
|
|
debugRec.PC(ADDR_BIT_RANGE) <= (others => '0');
|
|
debugRec.SP(ADDR_32BIT_RANGE) <= std_logic_vector(sp);
|
|
debugRec.STACK_TOS <= (others => '0');
|
|
debugRec.STACK_NOS <= (others => '0');
|
|
debugLoad <= '1';
|
|
debugCnt <= 0;
|
|
debugState <= Debug_DumpFifo_1;
|
|
end if;
|
|
|
|
when Debug_DumpFifo_1 =>
|
|
-- Move onto next opcode in Fifo.
|
|
debugCnt <= debugCnt + 1;
|
|
if debugCnt = 3 then
|
|
debugState <= Debug_End;
|
|
else
|
|
debugState <= Debug_DumpFifo;
|
|
end if;
|
|
|
|
when Debug_End =>
|
|
state <= State_Execute;
|
|
end case;
|
|
when others =>
|
|
null;
|
|
end case;
|
|
end if;
|
|
end if;
|
|
end process;
|
|
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Debugger output processor.
|
|
-- This logic takes a debug record and expands it to human readable form then dispatches it to the debug serial port.
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- Add debug uart if required. Increasing the TX and DBG Fifo depth can help short term (ie. initial start of the CPU)
|
|
-- but once full, the debug run will eventually operate at the slowest denominator, ie. the TX speed and how quick it can
|
|
-- shift 10 bits.
|
|
DEBUG : if DEBUG_CPU = true generate
|
|
DEBUGUART: entity work.zpu_uart_debug
|
|
generic map (
|
|
CLK_FREQ => CLK_FREQ -- Frequency of master clock.
|
|
)
|
|
port map (
|
|
-- CPU Interface
|
|
CLK => clk, -- master clock
|
|
RESET => areset, -- high active sync reset
|
|
DEBUG_DATA => debugRec, -- write data
|
|
CS => debugLoad, -- Chip Select.
|
|
READY => debugReady, -- Debug processor ready for next command.
|
|
|
|
-- Serial data
|
|
TXD => debug_txd
|
|
);
|
|
end generate;
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
-- End of debugger output processor.
|
|
-----------------------------------------------------------------------------------------------------------------------------------------------------------
|
|
|
|
end behave;
|