Files
ZPU/cpu/zpu_core_small.vhd

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;