From 0d7bc56eab8ff2d28aa9c4721a56b022385e13d9 Mon Sep 17 00:00:00 2001 From: oharboe Date: Thu, 1 May 2008 08:23:39 +0000 Subject: * zpu/hdl/zy1000 - ZPU implementation used on the zy1000 dev kit --- .settings/org.eclipse.core.resources.prefs | 3 + zpu/ChangeLog | 2 + zpu/hdl/zpu4/src/zpu_core_wip.vhd | 948 ----------------------------- zpu/hdl/zy2000/timer.vhd | 137 +++++ zpu/hdl/zy2000/trace.vhd | 84 +++ zpu/hdl/zy2000/txt_util.vhd | 587 ++++++++++++++++++ zpu/hdl/zy2000/zpu_config.vhd | 20 + zpu/hdl/zy2000/zpu_config_fast.vhd | 20 + zpu/hdl/zy2000/zpu_core.vhd | 948 +++++++++++++++++++++++++++++ zpu/hdl/zy2000/zpupkg.vhd | 168 +++++ 10 files changed, 1969 insertions(+), 948 deletions(-) create mode 100644 .settings/org.eclipse.core.resources.prefs delete mode 100644 zpu/hdl/zpu4/src/zpu_core_wip.vhd create mode 100644 zpu/hdl/zy2000/timer.vhd create mode 100644 zpu/hdl/zy2000/trace.vhd create mode 100644 zpu/hdl/zy2000/txt_util.vhd create mode 100644 zpu/hdl/zy2000/zpu_config.vhd create mode 100644 zpu/hdl/zy2000/zpu_config_fast.vhd create mode 100644 zpu/hdl/zy2000/zpu_core.vhd create mode 100644 zpu/hdl/zy2000/zpupkg.vhd diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..3f4041d --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +#Wed Apr 30 20:08:12 CEST 2008 +eclipse.preferences.version=1 +encoding//zpu/hdl/zpu4/src/zpu_core_small_wip.vhd=UTF-8 diff --git a/zpu/ChangeLog b/zpu/ChangeLog index 249ff02..bb48431 100644 --- a/zpu/ChangeLog +++ b/zpu/ChangeLog @@ -1,3 +1,5 @@ +2008-05-01 Øyvind Harboe + * zpu/hdl/zy1000 - ZPU implementation used on the zy1000 dev kit 2008-04-17 Arnim Läuger * zpu/hdl/example_ghdl/ghdl_import.sh, zpu/hdl/example_ghdl/ghdl_make.sh, zpu/hdl/example_ghdl/ghdl_options.sh, zpu/hdl/example_ghdl/README: GHDL example diff --git a/zpu/hdl/zpu4/src/zpu_core_wip.vhd b/zpu/hdl/zpu4/src/zpu_core_wip.vhd deleted file mode 100644 index 882719d..0000000 --- a/zpu/hdl/zpu4/src/zpu_core_wip.vhd +++ /dev/null @@ -1,948 +0,0 @@ - --- Company: ZPU4 generic memory interface CPU --- Engineer: Øyvind Harboe - -library IEEE; -use IEEE.STD_LOGIC_1164.ALL; -use IEEE.STD_LOGIC_UNSIGNED.ALL; -use IEEE.STD_LOGIC_arith.ALL; - -library work; -use work.zpu_config.all; -use work.zpupkg.all; - - - - - -entity zpu_core is - Port ( clk : in std_logic; - areset : in std_logic; - enable : in std_logic; - mem_req : out std_logic; - mem_we : out std_logic; - mem_ack : 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); - mem_writeMask: out std_logic_vector(wordBytes-1 downto 0); - interrupt : in std_logic; - break : out std_logic; - zpu_status : out std_logic_vector(63 downto 0)); -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_Interrupt, -State_InsnFetch -); - -type StateType is -( -State_Idle, -- using first state first on the list out of paranoia -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_Mult6, -State_Mult4, -State_BinaryOpResult -); - - -signal pc : std_logic_vector(maxAddrBitIncIO downto 0); -signal sp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); -signal incSp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); -signal incIncSp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); -signal decSp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); -signal stackA : std_logic_vector(wordSize-1 downto 0); -signal binaryOpResult : std_logic_vector(wordSize-1 downto 0); -signal multResult2 : std_logic_vector(wordSize-1 downto 0); -signal multResult3 : std_logic_vector(wordSize-1 downto 0); -signal multResult : std_logic_vector(wordSize-1 downto 0); -signal multA : std_logic_vector(wordSize-1 downto 0); -signal multB : std_logic_vector(wordSize-1 downto 0); -signal stackB : std_logic_vector(wordSize-1 downto 0); -signal idim_flag : std_logic; -signal busy : 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 mem_busy : 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); - -signal out_mem_req : std_logic; - -signal inInterrupt : std_logic; - --- state machine. - -begin - - zpu_status(maxAddrBitIncIO downto 0) <= trace_pc; - zpu_status(31) <= '1'; - zpu_status(39 downto 32) <= trace_opcode; - zpu_status(40) <= '1' when (state = State_Idle) else '0'; - zpu_status(62) <= '1'; - - 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_addr(maxAddrBitIncIO downto minAddrBit) <= mem_addr; - out_mem_addr(minAddrBit-1 downto 0) <= (others => '0'); - mem_req <= out_mem_req; - - incSp <= sp + 1; - incIncSp <= sp + 2; - decSp <= sp - 1; - - mem_busy <= out_mem_req and not mem_ack; -- '1' when the memory is busy - - opcodeControl: - process(clk, areset) - variable tOpcode : std_logic_vector(OpCode_Size-1 downto 0); - variable spOffset : std_logic_vector(4 downto 0); - variable tSpOffset : std_logic_vector(4 downto 0); - variable nextPC : std_logic_vector(maxAddrBitIncIO downto 0); - variable tNextState : InsnType; - variable tDecodedOpcode : InsnArray; - variable tMultResult : std_logic_vector(wordSize*2-1 downto 0); - begin - if areset = '1' then - state <= State_Idle; - break <= '0'; - sp <= spStart(maxAddrBitIncIO downto minAddrBit); - - pc <= (others => '0'); - idim_flag <= '0'; - begin_inst <= '0'; - mem_we <= '0'; - multA <= (others => '0'); - multB <= (others => '0'); - mem_writeMask <= (others => '1'); - out_mem_req <= '0'; - mem_addr <= (others => DontCareValue); - mem_write <= (others => DontCareValue); - inInterrupt <= '0'; - 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); - - - spOffset(4):=not opcode(conv_integer(pc(byteBits-1 downto 0)))(4); - spOffset(3 downto 0):=opcode(conv_integer(pc(byteBits-1 downto 0)))(3 downto 0); - nextPC := pc + 1; - - -- prepare trace snapshot - trace_opcode <= opcode(conv_integer(pc(byteBits-1 downto 0))); - trace_pc <= pc; - trace_sp <= sp; - trace_topOfStack <= stackA; - trace_topOfStackB <= stackB; - begin_inst <= '0'; - - -- we terminate the requeset as soon as we get acknowledge - if mem_ack = '1' then - out_mem_req <= '0'; - mem_we <= '0'; - end if; - - if interrupt='0' then - inInterrupt <= '0'; -- no longer in an interrupt - 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 mem_busy='0' then - mem_addr <= sp; - out_mem_req <= '1'; - state <= State_Resync2; - end if; - when State_Resync2 => - if mem_busy='0' then - stackA <= mem_read; - mem_addr <= incSp; - out_mem_req <= '1'; - state <= State_Resync3; - end if; - when State_Resync3 => - if mem_busy='0' then - stackB <= mem_read; - mem_addr <= pc(maxAddrBitIncIO downto minAddrBit); - out_mem_req <= '1'; - state <= State_Decode; - end if; - when State_Decode => - if mem_busy='0' then - decodeWord <= mem_read; - state <= State_Decode2; - 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):=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(conv_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(conv_integer(nextPC(byteBits-1 downto 0))); - - case insn is - when State_InsnFetch => - state <= State_Fetch; - when State_Im => - if 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) <= opcode(conv_integer(pc(byteBits-1 downto 0)))(6 downto 0); - else - out_mem_req <= '1'; - mem_we <= '1'; - mem_addr <= incSp; - mem_write <= stackB; - stackB <= stackA; - sp <= decSp; - for i in wordSize-1 downto 7 loop - stackA(i) <= opcode(conv_integer(pc(byteBits-1 downto 0)))(6); - end loop; - stackA(6 downto 0) <= opcode(conv_integer(pc(byteBits-1 downto 0)))(6 downto 0); - end if; - else - insn <= insn; - end if; - when State_StoreSP => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_StoreSP2; - - out_mem_req <= '1'; - mem_we <= '1'; - mem_addr <= sp+spOffset; - mem_write <= stackA; - stackA <= stackB; - sp <= incSp; - else - insn <= insn; - end if; - - - when State_LoadSP => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_LoadSP2; - - sp <= decSp; - out_mem_req <= '1'; - mem_we <= '1'; - mem_addr <= incSp; - mem_write <= stackB; - else - insn <= insn; - end if; - when State_Emulate => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - sp <= decSp; - out_mem_req <= '1'; - mem_we <= '1'; - mem_addr <= incSp; - mem_write <= 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) <= opcode(conv_integer(pc(byteBits-1 downto 0)))(4 downto 0); - state <= State_Fetch; - else - insn <= insn; - end if; - when State_Callpcrel => - if 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; - else - insn <= insn; - end if; - when State_Call => - if 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; - else - insn <= insn; - end if; - when State_AddSP => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_AddSP2; - - out_mem_req <= '1'; - mem_addr <= sp+spOffset; - else - insn <= insn; - end if; - when State_PushSP => - if 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; - out_mem_req <= '1'; - mem_we <= '1'; - mem_addr <= incSp; - mem_write <= stackB; - else - insn <= insn; - end if; - when State_PopPC => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= stackA(maxAddrBitIncIO downto 0); - sp <= incSp; - - out_mem_req <= '1'; - mem_we <= '1'; - mem_addr <= incSp; - mem_write <= stackB; - state <= State_Resync; - else - insn <= insn; - end if; - when State_PopPCRel => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= stackA(maxAddrBitIncIO downto 0) + pc; - sp <= incSp; - - out_mem_req <= '1'; - mem_we <= '1'; - mem_addr <= incSp; - mem_write <= stackB; - state <= State_Resync; - else - insn <= insn; - end if; - when State_Add => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - stackA <= stackA + stackB; - - out_mem_req <= '1'; - mem_addr <= incIncSp; - sp <= incSp; - state <= State_Popped; - else - insn <= insn; - end if; - when State_Sub => - begin_inst <= '1'; - idim_flag <= '0'; - binaryOpResult <= stackB - stackA; - state <= State_BinaryOpResult; - when State_Pop => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - mem_addr <= incIncSp; - out_mem_req <= '1'; - sp <= incSp; - stackA <= stackB; - state <= State_Popped; - else - insn <= insn; - end if; - when State_PopDown => - if mem_busy='0' then - -- PopDown leaves top of stack unchanged - begin_inst <= '1'; - idim_flag <= '0'; - mem_addr <= incIncSp; - out_mem_req <= '1'; - sp <= incSp; - state <= State_Popped; - else - insn <= insn; - end if; - when State_Or => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - stackA <= stackA or stackB; - out_mem_req <= '1'; - mem_addr <= incIncSp; - sp <= incSp; - state <= State_Popped; - else - insn <= insn; - end if; - when State_And => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - - stackA <= stackA and stackB; - out_mem_req <= '1'; - mem_addr <= incIncSp; - sp <= incSp; - state <= State_Popped; - else - insn <= insn; - end if; - when State_Eq => - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (stackA=stackB) then - binaryOpResult(0) <= '1'; - end if; - state <= State_BinaryOpResult; - when State_Ulessthan => - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (stackA - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (stackA<=stackB) then - binaryOpResult(0) <= '1'; - end if; - state <= State_BinaryOpResult; - when State_Lessthan => - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (signed(stackA) - begin_inst <= '1'; - idim_flag <= '0'; - - binaryOpResult <= (others => '0'); - if (signed(stackA)<=signed(stackB)) then - binaryOpResult(0) <= '1'; - end if; - state <= State_BinaryOpResult; - when State_Load => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_Load2; - - mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); - out_mem_req <= '1'; - else - insn <= insn; - end if; - - when State_Dup => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - sp <= decSp; - stackB <= stackA; - mem_write <= stackB; - mem_addr <= incSp; - out_mem_req <= '1'; - mem_we <= '1'; - else - insn <= insn; - end if; - when State_DupStackB => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - sp <= decSp; - stackA <= stackB; - stackB <= stackA; - mem_write <= stackB; - mem_addr <= incSp; - out_mem_req <= '1'; - mem_we <= '1'; - else - insn <= insn; - end if; - when State_Store => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); - mem_write <= stackB; - out_mem_req <= '1'; - mem_we <= '1'; - sp <= incIncSp; - state <= State_Resync; - else - insn <= insn; - end if; - when State_PopSP => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - pc <= pc + 1; - - mem_write <= stackB; - mem_addr <= incSp; - out_mem_req <= '1'; - mem_we <= '1'; - sp <= stackA(maxAddrBitIncIO downto minAddrBit); - state <= State_Resync; - else - insn <= insn; - 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 mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_Loadb2; - - mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); - out_mem_req <= '1'; - else - insn <= insn; - end if; - when State_Storeb => - if mem_busy='0' then - begin_inst <= '1'; - idim_flag <= '0'; - state <= State_Storeb2; - - mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); - out_mem_req <= '1'; - else - insn <= insn; - end if; - - when others => --- sp <= (others => DontCareValue); - report "Illegal instruction" severity failure; - break <= '1'; - end case; - - - when State_StoreSP2 => - if mem_busy='0' then - mem_addr <= incSp; - out_mem_req <= '1'; - state <= State_Popped; - end if; - when State_LoadSP2 => - if mem_busy='0' then - state <= State_LoadSP3; - out_mem_req <= '1'; - mem_addr <= sp+spOffset+1; - end if; - when State_LoadSP3 => - if mem_busy='0' then - pc <= pc + 1; - state <= State_Execute; - stackB <= stackA; - stackA <= mem_read; - end if; - when State_AddSP2 => - if mem_busy='0' then - pc <= pc + 1; - state <= State_Execute; - stackA <= stackA + mem_read; - end if; - when State_Load2 => - if mem_busy='0' then - stackA <= mem_read; - pc <= pc + 1; - state <= State_Execute; - end if; - when State_Loadb2 => - if mem_busy='0' then - stackA <= (others => '0'); - stackA(7 downto 0) <= mem_read(((wordBytes-1-conv_integer(stackA(byteBits-1 downto 0)))*8+7) downto (wordBytes-1-conv_integer(stackA(byteBits-1 downto 0)))*8); - pc <= pc + 1; - state <= State_Execute; - end if; - when State_Storeb2 => - if mem_busy='0' then - mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); - mem_write <= mem_read; - mem_write(((wordBytes-1-conv_integer(stackA(byteBits-1 downto 0)))*8+7) downto (wordBytes-1-conv_integer(stackA(byteBits-1 downto 0)))*8) <= stackB(7 downto 0) ; - out_mem_req <= '1'; - mem_we <= '1'; - pc <= pc + 1; - sp <= incIncSp; - state <= State_Resync; - end if; - when State_Fetch => - if mem_busy='0' then - if interrupt='1' and inInterrupt='0' and idim_flag='0' then - -- We got an interrupt - inInterrupt <= '1'; - - sp <= decSp; - out_mem_req <= '1'; - mem_we <= '1'; - mem_addr <= incSp; - mem_write <= stackB; - stackA <= (others => DontCareValue); - stackA(maxAddrBitIncIO downto 0) <= pc; - stackB <= stackA; - - pc <= conv_std_logic_vector(32, maxAddrBitIncIo+1); -- interrupt address - - report "ZPU jumped to interrupt!" severity note; - else - mem_addr <= pc(maxAddrBitIncIO downto minAddrBit); - out_mem_req <= '1'; - state <= State_Decode; - end if; - end if; - when State_Mult2 => - state <= State_Mult3; - when State_Mult3 => - state <= State_Mult4; - when State_Mult4 => - state <= State_Mult5; - when State_Mult5 => - stackA <= multResult3; - state <= State_Mult6; - when State_Mult6 => - if mem_busy='0' then - out_mem_req <= '1'; - mem_addr <= incIncSp; - sp <= incSp; - state <= State_Popped; - end if; - when State_BinaryOpResult => - if mem_busy='0' then - -- NB!!!! we know that the memory isn't busy at this point!!!! - out_mem_req <= '1'; - mem_addr <= incIncSp; - sp <= incSp; - stackA <= binaryOpResult; - state <= State_Popped; - end if; - when State_Popped => - if mem_busy='0' then - pc <= pc + 1; - stackB <= 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; - - - -end behave; diff --git a/zpu/hdl/zy2000/timer.vhd b/zpu/hdl/zy2000/timer.vhd new file mode 100644 index 0000000..bff82f2 --- /dev/null +++ b/zpu/hdl/zy2000/timer.vhd @@ -0,0 +1,137 @@ +library ieee; +use ieee.std_logic_1164.all; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +entity timer is + port( + clk : in std_logic; + areset : in std_logic; + sample : in std_logic; + reset : in std_logic; + counter : out std_logic_vector(63 downto 0)); +end timer; + + +architecture behave of timer is + +signal c : std_logic_vector(1 to 7); + +signal cnt : std_logic_vector(63 downto 0); +signal cnt_smp : std_logic_vector(63 downto 0); + +begin + + counter <= cnt_smp; + + process(clk, areset) -- Carry generation + begin + if areset = '1' then + c <= "0000000"; + elsif (clk'event and clk = '1') then + if reset = '1' then + c <= "0000000"; + else + if cnt(7 downto 0) = "11111110" then + c(1) <= '1'; + else + c(1) <= '0'; + end if; + if cnt(15 downto 8) = "11111111" then + c(2) <= '1'; + else + c(2) <= '0'; + end if; + if cnt(23 downto 16) = "11111111" and c(2) = '1' then + c(3) <= '1'; + else + c(3) <= '0'; + end if; + if cnt(31 downto 24) = "11111111" and c(3) = '1' then + c(4) <= '1'; + else + c(4) <= '0'; + end if; + if cnt(39 downto 32) = "11111111" and c(4) = '1' then + c(5) <= '1'; + else + c(5) <= '0'; + end if; + if cnt(47 downto 40) = "11111111" and c(5) = '1' then + c(6) <= '1'; + else + c(6) <= '0'; + end if; + if cnt(55 downto 48) = "11111111" and c(6) = '1' then + c(7) <= '1'; + else + c(7) <= '0'; + end if; + end if; + end if; + end process; + + process(clk, areset) + begin + if areset = '1' then + cnt <= (others=>'0'); + elsif (clk'event and clk = '1') then + if reset = '1' then + cnt <= (others=>'0'); + else + cnt(7 downto 0) <= cnt(7 downto 0) + '1'; + if c(1) = '1' then + cnt(15 downto 8) <= cnt(15 downto 8) + '1'; + else + cnt(15 downto 8) <= cnt(15 downto 8); + end if; + if c(2) = '1' and c(1) = '1' then + cnt(23 downto 16) <= cnt(23 downto 16) + '1'; + else + cnt(23 downto 16) <= cnt(23 downto 16); + end if; + if c(3) = '1' and c(1) = '1' then + cnt(31 downto 24) <= cnt(31 downto 24) + '1'; + else + cnt(31 downto 24) <= cnt(31 downto 24); + end if; + if c(4) = '1' and c(1) = '1' then + cnt(39 downto 32) <= cnt(39 downto 32) + '1'; + else + cnt(39 downto 32) <= cnt(39 downto 32); + end if; + if c(5) = '1' and c(1) = '1' then + cnt(47 downto 40) <= cnt(47 downto 40) + '1'; + else + cnt(47 downto 40) <= cnt(47 downto 40); + end if; + if c(6) = '1' and c(1) = '1' then + cnt(55 downto 48) <= cnt(55 downto 48) + '1'; + else + cnt(55 downto 48) <= cnt(55 downto 48); + end if; + if c(7) = '1' and c(1) = '1' then + cnt(63 downto 56) <= cnt(63 downto 56) + '1'; + else + cnt(63 downto 56) <= cnt(63 downto 56); + end if; + end if; + end if; + end process; + + process(clk, areset) + begin + if areset = '1' then + cnt_smp <= (others=>'0'); + elsif (clk'event and clk = '1') then + if reset = '1' then + cnt_smp <= (others=>'0'); + elsif sample = '1' then + cnt_smp <= cnt; + else + cnt_smp <= cnt_smp; + end if; + end if; + end process; + +end behave; + diff --git a/zpu/hdl/zy2000/trace.vhd b/zpu/hdl/zy2000/trace.vhd new file mode 100644 index 0000000..bc5279f --- /dev/null +++ b/zpu/hdl/zy2000/trace.vhd @@ -0,0 +1,84 @@ +library ieee; +use ieee.std_logic_1164.all; +--use IEEE.STD_LOGIC_ARITH.ALL; +use IEEE.STD_LOGIC_UNSIGNED.ALL; + +use std.textio.all; + +library work; +use work.zpu_config.all; +use work.zpupkg.all; +use work.txt_util.all; + + +entity trace is + generic ( + log_file: string := "trace.txt" + ); + 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 2); + 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 trace; + + +architecture behave of trace is + + +file l_file : TEXT open write_mode is log_file; + + +begin + + +-- write data and control information to a file + +receive_data: process + +variable l: line; +variable t : std_logic_vector(wordSize-1 downto 0); +variable t2 : std_logic_vector(maxAddrBitIncIO downto 0); +variable counter : std_logic_vector(63 downto 0); + + + +begin + + t:= (others => '0'); + t2:= (others => '0'); + +counter := (others => '0'); + -- print header for the logfile + print(l_file, "#pc,opcode,sp,top_of_stack "); + print(l_file, "#----------"); + print(l_file, " "); + + wait until clk = '1'; + wait until clk = '0'; + + while true loop + + counter := counter + 1; + if begin_inst = '1' then + t(maxAddrBitIncIO downto 2):=sp; + t2:=pc; + print(l_file, "0x" & hstr(t2) & " 0x" & hstr(opcode) & " 0x" & hstr(t) & " 0x" & hstr(memA) & " 0x" & hstr(memB) & " 0x" & hstr(intSp) & " 0x" & hstr(counter)); + end if; + + wait until clk = '0'; + + end loop; + + end process receive_data; + + + +end behave; + diff --git a/zpu/hdl/zy2000/txt_util.vhd b/zpu/hdl/zy2000/txt_util.vhd new file mode 100644 index 0000000..d3bf01a --- /dev/null +++ b/zpu/hdl/zy2000/txt_util.vhd @@ -0,0 +1,587 @@ +library ieee; +use ieee.std_logic_1164.all; +use std.textio.all; + +library work; + +package txt_util is + + -- prints a message to the screen + procedure print(text: string); + + -- prints the message when active + -- useful for debug switches + procedure print(active: boolean; text: string); + + -- converts std_logic into a character + function chr(sl: std_logic) return character; + + -- converts std_logic into a string (1 to 1) + function str(sl: std_logic) return string; + + -- converts std_logic_vector into a string (binary base) + function str(slv: std_logic_vector) return string; + + -- converts boolean into a string + function str(b: boolean) return string; + + -- converts an integer into a single character + -- (can also be used for hex conversion and other bases) + function chr(int: integer) return character; + + -- converts integer into string using specified base + function str(int: integer; base: integer) return string; + + -- converts integer to string, using base 10 + function str(int: integer) return string; + + -- convert std_logic_vector into a string in hex format + function hstr(slv: std_logic_vector) return string; + + + -- functions to manipulate strings + ----------------------------------- + + -- convert a character to upper case + function to_upper(c: character) return character; + + -- convert a character to lower case + function to_lower(c: character) return character; + + -- convert a string to upper case + function to_upper(s: string) return string; + + -- convert a string to lower case + function to_lower(s: string) return string; + + + + -- functions to convert strings into other formats + -------------------------------------------------- + + -- converts a character into std_logic + function to_std_logic(c: character) return std_logic; + + -- converts a string into std_logic_vector + function to_std_logic_vector(s: string) return std_logic_vector; + + + + -- file I/O + ----------- + + -- read variable length string from input file + procedure str_read(file in_file: TEXT; + res_string: out string); + + -- print string to a file and start new line + procedure print(file out_file: TEXT; + new_string: in string); + + -- print character to a file and start new line + procedure print(file out_file: TEXT; + char: in character); + +end txt_util; + + + + +package body txt_util is + + + + + -- prints text to the screen + + procedure print(text: string) is + variable msg_line: line; + begin + write(msg_line, text); + writeline(output, msg_line); + end print; + + + + + -- prints text to the screen when active + + procedure print(active: boolean; text: string) is + begin + if active then + print(text); + end if; + end print; + + + -- converts std_logic into a character + + function chr(sl: std_logic) return character is + variable c: character; + begin + case sl is + when 'U' => c:= 'U'; + when 'X' => c:= 'X'; + when '0' => c:= '0'; + when '1' => c:= '1'; + when 'Z' => c:= 'Z'; + when 'W' => c:= 'W'; + when 'L' => c:= 'L'; + when 'H' => c:= 'H'; + when '-' => c:= '-'; + end case; + return c; + end chr; + + + + -- converts std_logic into a string (1 to 1) + + function str(sl: std_logic) return string is + variable s: string(1 to 1); + begin + s(1) := chr(sl); + return s; + end str; + + + + -- converts std_logic_vector into a string (binary base) + -- (this also takes care of the fact that the range of + -- a string is natural while a std_logic_vector may + -- have an integer range) + + function str(slv: std_logic_vector) return string is + variable result : string (1 to slv'length); + variable r : integer; + begin + r := 1; + for i in slv'range loop + result(r) := chr(slv(i)); + r := r + 1; + end loop; + return result; + end str; + + + function str(b: boolean) return string is + + begin + if b then + return "true"; + else + return "false"; + end if; + end str; + + + -- converts an integer into a character + -- for 0 to 9 the obvious mapping is used, higher + -- values are mapped to the characters A-Z + -- (this is usefull for systems with base > 10) + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + + function chr(int: integer) return character is + variable c: character; + begin + case int is + when 0 => c := '0'; + when 1 => c := '1'; + when 2 => c := '2'; + when 3 => c := '3'; + when 4 => c := '4'; + when 5 => c := '5'; + when 6 => c := '6'; + when 7 => c := '7'; + when 8 => c := '8'; + when 9 => c := '9'; + when 10 => c := 'A'; + when 11 => c := 'B'; + when 12 => c := 'C'; + when 13 => c := 'D'; + when 14 => c := 'E'; + when 15 => c := 'F'; + when 16 => c := 'G'; + when 17 => c := 'H'; + when 18 => c := 'I'; + when 19 => c := 'J'; + when 20 => c := 'K'; + when 21 => c := 'L'; + when 22 => c := 'M'; + when 23 => c := 'N'; + when 24 => c := 'O'; + when 25 => c := 'P'; + when 26 => c := 'Q'; + when 27 => c := 'R'; + when 28 => c := 'S'; + when 29 => c := 'T'; + when 30 => c := 'U'; + when 31 => c := 'V'; + when 32 => c := 'W'; + when 33 => c := 'X'; + when 34 => c := 'Y'; + when 35 => c := 'Z'; + when others => c := '?'; + end case; + return c; + end chr; + + + + -- convert integer to string using specified base + -- (adapted from Steve Vogwell's posting in comp.lang.vhdl) + + function str(int: integer; base: integer) return string is + + variable temp: string(1 to 10); + variable num: integer; + variable abs_int: integer; + variable len: integer := 1; + variable power: integer := 1; + + begin + + -- bug fix for negative numbers + abs_int := abs(int); + + num := abs_int; + + while num >= base loop -- Determine how many + len := len + 1; -- characters required + num := num / base; -- to represent the + end loop ; -- number. + + for i in len downto 1 loop -- Convert the number to + temp(i) := chr(abs_int/power mod base); -- a string starting + power := power * base; -- with the right hand + end loop ; -- side. + + -- return result and add sign if required + if int < 0 then + return '-'& temp(1 to len); + else + return temp(1 to len); + end if; + + end str; + + + -- convert integer to string, using base 10 + function str(int: integer) return string is + + begin + + return str(int, 10) ; + + end str; + + + + -- converts a std_logic_vector into a hex string. + function hstr(slv: std_logic_vector) return string is + variable hexlen: integer; + variable longslv : std_logic_vector(67 downto 0) := (others => '0'); + variable hex : string(1 to 16); + variable fourbit : std_logic_vector(3 downto 0); + begin + hexlen := (slv'left+1)/4; + if (slv'left+1) mod 4 /= 0 then + hexlen := hexlen + 1; + end if; + longslv(slv'left downto 0) := slv; + for i in (hexlen -1) downto 0 loop + fourbit := longslv(((i*4)+3) downto (i*4)); + case fourbit is + when "0000" => hex(hexlen -I) := '0'; + when "0001" => hex(hexlen -I) := '1'; + when "0010" => hex(hexlen -I) := '2'; + when "0011" => hex(hexlen -I) := '3'; + when "0100" => hex(hexlen -I) := '4'; + when "0101" => hex(hexlen -I) := '5'; + when "0110" => hex(hexlen -I) := '6'; + when "0111" => hex(hexlen -I) := '7'; + when "1000" => hex(hexlen -I) := '8'; + when "1001" => hex(hexlen -I) := '9'; + when "1010" => hex(hexlen -I) := 'A'; + when "1011" => hex(hexlen -I) := 'B'; + when "1100" => hex(hexlen -I) := 'C'; + when "1101" => hex(hexlen -I) := 'D'; + when "1110" => hex(hexlen -I) := 'E'; + when "1111" => hex(hexlen -I) := 'F'; + when "ZZZZ" => hex(hexlen -I) := 'z'; + when "UUUU" => hex(hexlen -I) := 'u'; + when "XXXX" => hex(hexlen -I) := 'x'; + when others => hex(hexlen -I) := '?'; + end case; + end loop; + return hex(1 to hexlen); + end hstr; + + + + -- functions to manipulate strings + ----------------------------------- + + + -- convert a character to upper case + + function to_upper(c: character) return character is + + variable u: character; + + begin + + case c is + when 'a' => u := 'A'; + when 'b' => u := 'B'; + when 'c' => u := 'C'; + when 'd' => u := 'D'; + when 'e' => u := 'E'; + when 'f' => u := 'F'; + when 'g' => u := 'G'; + when 'h' => u := 'H'; + when 'i' => u := 'I'; + when 'j' => u := 'J'; + when 'k' => u := 'K'; + when 'l' => u := 'L'; + when 'm' => u := 'M'; + when 'n' => u := 'N'; + when 'o' => u := 'O'; + when 'p' => u := 'P'; + when 'q' => u := 'Q'; + when 'r' => u := 'R'; + when 's' => u := 'S'; + when 't' => u := 'T'; + when 'u' => u := 'U'; + when 'v' => u := 'V'; + when 'w' => u := 'W'; + when 'x' => u := 'X'; + when 'y' => u := 'Y'; + when 'z' => u := 'Z'; + when others => u := c; + end case; + + return u; + + end to_upper; + + + -- convert a character to lower case + + function to_lower(c: character) return character is + + variable l: character; + + begin + + case c is + when 'A' => l := 'a'; + when 'B' => l := 'b'; + when 'C' => l := 'c'; + when 'D' => l := 'd'; + when 'E' => l := 'e'; + when 'F' => l := 'f'; + when 'G' => l := 'g'; + when 'H' => l := 'h'; + when 'I' => l := 'i'; + when 'J' => l := 'j'; + when 'K' => l := 'k'; + when 'L' => l := 'l'; + when 'M' => l := 'm'; + when 'N' => l := 'n'; + when 'O' => l := 'o'; + when 'P' => l := 'p'; + when 'Q' => l := 'q'; + when 'R' => l := 'r'; + when 'S' => l := 's'; + when 'T' => l := 't'; + when 'U' => l := 'u'; + when 'V' => l := 'v'; + when 'W' => l := 'w'; + when 'X' => l := 'x'; + when 'Y' => l := 'y'; + when 'Z' => l := 'z'; + when others => l := c; + end case; + + return l; + + end to_lower; + + + + -- convert a string to upper case + + function to_upper(s: string) return string is + + variable uppercase: string (s'range); + + begin + + for i in s'range loop + uppercase(i):= to_upper(s(i)); + end loop; + return uppercase; + + end to_upper; + + + + -- convert a string to lower case + + function to_lower(s: string) return string is + + variable lowercase: string (s'range); + + begin + + for i in s'range loop + lowercase(i):= to_lower(s(i)); + end loop; + return lowercase; + + end to_lower; + + + +-- functions to convert strings into other types + + +-- converts a character into a std_logic + +function to_std_logic(c: character) return std_logic is + variable sl: std_logic; + begin + case c is + when 'U' => + sl := 'U'; + when 'X' => + sl := 'X'; + when '0' => + sl := '0'; + when '1' => + sl := '1'; + when 'Z' => + sl := 'Z'; + when 'W' => + sl := 'W'; + when 'L' => + sl := 'L'; + when 'H' => + sl := 'H'; + when '-' => + sl := '-'; + when others => + sl := 'X'; + end case; + return sl; + end to_std_logic; + + +-- converts a string into std_logic_vector + +function to_std_logic_vector(s: string) return std_logic_vector is + variable slv: std_logic_vector(s'high-s'low downto 0); + variable k: integer; +begin + k := s'high-s'low; + for i in s'range loop + slv(k) := to_std_logic(s(i)); + k := k - 1; + end loop; + return slv; +end to_std_logic_vector; + + + + + + +---------------- +-- file I/O -- +---------------- + + + +-- read variable length string from input file + +procedure str_read(file in_file: TEXT; + res_string: out string) is + + variable l: line; + variable c: character; + variable is_string: boolean; + + begin + + readline(in_file, l); + -- clear the contents of the result string + for i in res_string'range loop + res_string(i) := ' '; + end loop; + -- read all characters of the line, up to the length + -- of the results string + for i in res_string'range loop + read(l, c, is_string); + res_string(i) := c; + if not is_string then -- found end of line + exit; + end if; + end loop; + +end str_read; + + +-- print string to a file +procedure print(file out_file: TEXT; + new_string: in string) is + + variable l: line; + + begin + + write(l, new_string); + writeline(out_file, l); + +end print; + + +-- print character to a file and start new line +procedure print(file out_file: TEXT; + char: in character) is + + variable l: line; + + begin + + write(l, char); + writeline(out_file, l); + +end print; + + + +-- appends contents of a string to a file until line feed occurs +-- (LF is considered to be the end of the string) + +procedure str_write(file out_file: TEXT; + new_string: in string) is + begin + + for i in new_string'range loop + print(out_file, new_string(i)); + if new_string(i) = LF then -- end of string + exit; + end if; + end loop; + +end str_write; + + + + +end txt_util; + + + + diff --git a/zpu/hdl/zy2000/zpu_config.vhd b/zpu/hdl/zy2000/zpu_config.vhd new file mode 100644 index 0000000..61949c5 --- /dev/null +++ b/zpu/hdl/zy2000/zpu_config.vhd @@ -0,0 +1,20 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.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 := '0'; + -- Clock frequency in MHz. + constant ZPU_Frequency : std_logic_vector(7 downto 0) := x"40"; + -- This is the msb address bit. bytes=2^(maxAddrBitIncIO+1) + constant maxAddrBitIncIO : integer := 27; + + -- start byte address of stack. + -- point to top of RAM - 2*words + constant spStart : std_logic_vector(maxAddrBitIncIO downto 0) := x"1fffff8"; + +end zpu_config; diff --git a/zpu/hdl/zy2000/zpu_config_fast.vhd b/zpu/hdl/zy2000/zpu_config_fast.vhd new file mode 100644 index 0000000..61949c5 --- /dev/null +++ b/zpu/hdl/zy2000/zpu_config_fast.vhd @@ -0,0 +1,20 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.std_logic_unsigned.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 := '0'; + -- Clock frequency in MHz. + constant ZPU_Frequency : std_logic_vector(7 downto 0) := x"40"; + -- This is the msb address bit. bytes=2^(maxAddrBitIncIO+1) + constant maxAddrBitIncIO : integer := 27; + + -- start byte address of stack. + -- point to top of RAM - 2*words + constant spStart : std_logic_vector(maxAddrBitIncIO downto 0) := x"1fffff8"; + +end zpu_config; diff --git a/zpu/hdl/zy2000/zpu_core.vhd b/zpu/hdl/zy2000/zpu_core.vhd new file mode 100644 index 0000000..2450f14 --- /dev/null +++ b/zpu/hdl/zy2000/zpu_core.vhd @@ -0,0 +1,948 @@ + +-- Company: ZPU4 generic memory interface CPU +-- Engineer: Øyvind Harboe + +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.STD_LOGIC_UNSIGNED.ALL; +use IEEE.STD_LOGIC_arith.ALL; + +library work; +use work.zpu_config.all; +use work.zpupkg.all; + + + + + +entity zpu_core is + Port ( clk : in std_logic; + areset : in std_logic; + enable : in std_logic; + mem_req : out std_logic; + mem_we : out std_logic; + mem_ack : 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); + mem_writeMask: out std_logic_vector(wordBytes-1 downto 0); + interrupt : in std_logic; + break : out std_logic; + zpu_status : out std_logic_vector(63 downto 0)); +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_Interrupt, +State_InsnFetch +); + +type StateType is +( +State_Idle, -- using first state first on the list out of paranoia +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_Mult6, +State_Mult4, +State_BinaryOpResult +); + + +signal pc : std_logic_vector(maxAddrBitIncIO downto 0); +signal sp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); +signal incSp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); +signal incIncSp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); +signal decSp : std_logic_vector(maxAddrBitIncIO downto minAddrBit); +signal stackA : std_logic_vector(wordSize-1 downto 0); +signal binaryOpResult : std_logic_vector(wordSize-1 downto 0); +signal multResult2 : std_logic_vector(wordSize-1 downto 0); +signal multResult3 : std_logic_vector(wordSize-1 downto 0); +signal multResult : std_logic_vector(wordSize-1 downto 0); +signal multA : std_logic_vector(wordSize-1 downto 0); +signal multB : std_logic_vector(wordSize-1 downto 0); +signal stackB : std_logic_vector(wordSize-1 downto 0); +signal idim_flag : std_logic; +signal busy : 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 mem_busy : 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); + +signal out_mem_req : std_logic; + +signal inInterrupt : std_logic; + +-- state machine. + +begin + + zpu_status(maxAddrBitIncIO downto 0) <= trace_pc; + zpu_status(31) <= '1'; + zpu_status(39 downto 32) <= trace_opcode; + zpu_status(40) <= '1' when (state = State_Idle) else '0'; + zpu_status(62) <= '1'; + + 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_addr(maxAddrBitIncIO downto minAddrBit) <= mem_addr; + out_mem_addr(minAddrBit-1 downto 0) <= (others => '0'); + mem_req <= out_mem_req; + + incSp <= sp + 1; + incIncSp <= sp + 2; + decSp <= sp - 1; + + mem_busy <= out_mem_req and not mem_ack; -- '1' when the memory is busy + + opcodeControl: + process(clk, areset) + variable tOpcode : std_logic_vector(OpCode_Size-1 downto 0); + variable spOffset : std_logic_vector(4 downto 0); + variable tSpOffset : std_logic_vector(4 downto 0); + variable nextPC : std_logic_vector(maxAddrBitIncIO downto 0); + variable tNextState : InsnType; + variable tDecodedOpcode : InsnArray; + variable tMultResult : std_logic_vector(wordSize*2-1 downto 0); + begin + if areset = '1' then + state <= State_Idle; + break <= '0'; + sp <= spStart(maxAddrBitIncIO downto minAddrBit); + + pc <= (others => '0'); + idim_flag <= '0'; + begin_inst <= '0'; + mem_we <= '0'; + multA <= (others => '0'); + multB <= (others => '0'); + mem_writeMask <= (others => '1'); + out_mem_req <= '0'; + mem_addr <= (others => DontCareValue); + mem_write <= (others => DontCareValue); + inInterrupt <= '0'; + 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); + + + spOffset(4):=not opcode(conv_integer(pc(byteBits-1 downto 0)))(4); + spOffset(3 downto 0):=opcode(conv_integer(pc(byteBits-1 downto 0)))(3 downto 0); + nextPC := pc + 1; + + -- prepare trace snapshot + trace_opcode <= opcode(conv_integer(pc(byteBits-1 downto 0))); + trace_pc <= pc; + trace_sp <= sp; + trace_topOfStack <= stackA; + trace_topOfStackB <= stackB; + begin_inst <= '0'; + + -- we terminate the requeset as soon as we get acknowledge + if mem_ack = '1' then + out_mem_req <= '0'; + mem_we <= '0'; + end if; + + if interrupt='0' then + inInterrupt <= '0'; -- no longer in an interrupt + 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 mem_busy='0' then + mem_addr <= sp; + out_mem_req <= '1'; + state <= State_Resync2; + end if; + when State_Resync2 => + if mem_busy='0' then + stackA <= mem_read; + mem_addr <= incSp; + out_mem_req <= '1'; + state <= State_Resync3; + end if; + when State_Resync3 => + if mem_busy='0' then + stackB <= mem_read; + mem_addr <= pc(maxAddrBitIncIO downto minAddrBit); + out_mem_req <= '1'; + state <= State_Decode; + end if; + when State_Decode => + if mem_busy='0' then + decodeWord <= mem_read; + state <= State_Decode2; + 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):=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(conv_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(conv_integer(nextPC(byteBits-1 downto 0))); + + case insn is + when State_InsnFetch => + state <= State_Fetch; + when State_Im => + if 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) <= opcode(conv_integer(pc(byteBits-1 downto 0)))(6 downto 0); + else + out_mem_req <= '1'; + mem_we <= '1'; + mem_addr <= incSp; + mem_write <= stackB; + stackB <= stackA; + sp <= decSp; + for i in wordSize-1 downto 7 loop + stackA(i) <= opcode(conv_integer(pc(byteBits-1 downto 0)))(6); + end loop; + stackA(6 downto 0) <= opcode(conv_integer(pc(byteBits-1 downto 0)))(6 downto 0); + end if; + else + insn <= insn; + end if; + when State_StoreSP => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_StoreSP2; + + out_mem_req <= '1'; + mem_we <= '1'; + mem_addr <= sp+spOffset; + mem_write <= stackA; + stackA <= stackB; + sp <= incSp; + else + insn <= insn; + end if; + + + when State_LoadSP => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_LoadSP2; + + sp <= decSp; + out_mem_req <= '1'; + mem_we <= '1'; + mem_addr <= incSp; + mem_write <= stackB; + else + insn <= insn; + end if; + when State_Emulate => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + sp <= decSp; + out_mem_req <= '1'; + mem_we <= '1'; + mem_addr <= incSp; + mem_write <= 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) <= opcode(conv_integer(pc(byteBits-1 downto 0)))(4 downto 0); + state <= State_Fetch; + else + insn <= insn; + end if; + when State_Callpcrel => + if 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; + else + insn <= insn; + end if; + when State_Call => + if 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; + else + insn <= insn; + end if; + when State_AddSP => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_AddSP2; + + out_mem_req <= '1'; + mem_addr <= sp+spOffset; + else + insn <= insn; + end if; + when State_PushSP => + if 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; + out_mem_req <= '1'; + mem_we <= '1'; + mem_addr <= incSp; + mem_write <= stackB; + else + insn <= insn; + end if; + when State_PopPC => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= stackA(maxAddrBitIncIO downto 0); + sp <= incSp; + + out_mem_req <= '1'; + mem_we <= '1'; + mem_addr <= incSp; + mem_write <= stackB; + state <= State_Resync; + else + insn <= insn; + end if; + when State_PopPCRel => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= stackA(maxAddrBitIncIO downto 0) + pc; + sp <= incSp; + + out_mem_req <= '1'; + mem_we <= '1'; + mem_addr <= incSp; + mem_write <= stackB; + state <= State_Resync; + else + insn <= insn; + end if; + when State_Add => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + stackA <= stackA + stackB; + + out_mem_req <= '1'; + mem_addr <= incIncSp; + sp <= incSp; + state <= State_Popped; + else + insn <= insn; + end if; + when State_Sub => + begin_inst <= '1'; + idim_flag <= '0'; + binaryOpResult <= stackB - stackA; + state <= State_BinaryOpResult; + when State_Pop => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + mem_addr <= incIncSp; + out_mem_req <= '1'; + sp <= incSp; + stackA <= stackB; + state <= State_Popped; + else + insn <= insn; + end if; + when State_PopDown => + if mem_busy='0' then + -- PopDown leaves top of stack unchanged + begin_inst <= '1'; + idim_flag <= '0'; + mem_addr <= incIncSp; + out_mem_req <= '1'; + sp <= incSp; + state <= State_Popped; + else + insn <= insn; + end if; + when State_Or => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + stackA <= stackA or stackB; + out_mem_req <= '1'; + mem_addr <= incIncSp; + sp <= incSp; + state <= State_Popped; + else + insn <= insn; + end if; + when State_And => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + + stackA <= stackA and stackB; + out_mem_req <= '1'; + mem_addr <= incIncSp; + sp <= incSp; + state <= State_Popped; + else + insn <= insn; + end if; + when State_Eq => + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (stackA=stackB) then + binaryOpResult(0) <= '1'; + end if; + state <= State_BinaryOpResult; + when State_Ulessthan => + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (stackA + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (stackA<=stackB) then + binaryOpResult(0) <= '1'; + end if; + state <= State_BinaryOpResult; + when State_Lessthan => + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (signed(stackA) + begin_inst <= '1'; + idim_flag <= '0'; + + binaryOpResult <= (others => '0'); + if (signed(stackA)<=signed(stackB)) then + binaryOpResult(0) <= '1'; + end if; + state <= State_BinaryOpResult; + when State_Load => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_Load2; + + mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); + out_mem_req <= '1'; + else + insn <= insn; + end if; + + when State_Dup => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + sp <= decSp; + stackB <= stackA; + mem_write <= stackB; + mem_addr <= incSp; + out_mem_req <= '1'; + mem_we <= '1'; + else + insn <= insn; + end if; + when State_DupStackB => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + sp <= decSp; + stackA <= stackB; + stackB <= stackA; + mem_write <= stackB; + mem_addr <= incSp; + out_mem_req <= '1'; + mem_we <= '1'; + else + insn <= insn; + end if; + when State_Store => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); + mem_write <= stackB; + out_mem_req <= '1'; + mem_we <= '1'; + sp <= incIncSp; + state <= State_Resync; + else + insn <= insn; + end if; + when State_PopSP => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + pc <= pc + 1; + + mem_write <= stackB; + mem_addr <= incSp; + out_mem_req <= '1'; + mem_we <= '1'; + sp <= stackA(maxAddrBitIncIO downto minAddrBit); + state <= State_Resync; + else + insn <= insn; + 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 mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_Loadb2; + + mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); + out_mem_req <= '1'; + else + insn <= insn; + end if; + when State_Storeb => + if mem_busy='0' then + begin_inst <= '1'; + idim_flag <= '0'; + state <= State_Storeb2; + + mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); + out_mem_req <= '1'; + else + insn <= insn; + end if; + + when others => +-- sp <= (others => DontCareValue); + report "Illegal instruction" severity failure; + break <= '1'; + end case; + + + when State_StoreSP2 => + if mem_busy='0' then + mem_addr <= incSp; + out_mem_req <= '1'; + state <= State_Popped; + end if; + when State_LoadSP2 => + if mem_busy='0' then + state <= State_LoadSP3; + out_mem_req <= '1'; + mem_addr <= sp+spOffset+1; + end if; + when State_LoadSP3 => + if mem_busy='0' then + pc <= pc + 1; + state <= State_Execute; + stackB <= stackA; + stackA <= mem_read; + end if; + when State_AddSP2 => + if mem_busy='0' then + pc <= pc + 1; + state <= State_Execute; + stackA <= stackA + mem_read; + end if; + when State_Load2 => + if mem_busy='0' then + stackA <= mem_read; + pc <= pc + 1; + state <= State_Execute; + end if; + when State_Loadb2 => + if mem_busy='0' then + stackA <= (others => '0'); + stackA(7 downto 0) <= mem_read(((wordBytes-1-conv_integer(stackA(byteBits-1 downto 0)))*8+7) downto (wordBytes-1-conv_integer(stackA(byteBits-1 downto 0)))*8); + pc <= pc + 1; + state <= State_Execute; + end if; + when State_Storeb2 => + if mem_busy='0' then + mem_addr <= stackA(maxAddrBitIncIO downto minAddrBit); + mem_write <= mem_read; + mem_write(((wordBytes-1-conv_integer(stackA(byteBits-1 downto 0)))*8+7) downto (wordBytes-1-conv_integer(stackA(byteBits-1 downto 0)))*8) <= stackB(7 downto 0) ; + out_mem_req <= '1'; + mem_we <= '1'; + pc <= pc + 1; + sp <= incIncSp; + state <= State_Resync; + end if; + when State_Fetch => + if mem_busy='0' then + if interrupt='1' and inInterrupt='0' and idim_flag='0' then + -- We got an interrupt + inInterrupt <= '1'; + + sp <= decSp; + out_mem_req <= '1'; + mem_we <= '1'; + mem_addr <= incSp; + mem_write <= stackB; + stackA <= (others => DontCareValue); + stackA(maxAddrBitIncIO downto 0) <= pc; + stackB <= stackA; + + pc <= conv_std_logic_vector(32, maxAddrBitIncIo+1); -- interrupt address + + report "ZPU jumped to interrupt!" severity note; + else + mem_addr <= pc(maxAddrBitIncIO downto minAddrBit); + out_mem_req <= '1'; + state <= State_Decode; + end if; + end if; + when State_Mult2 => + state <= State_Mult3; + when State_Mult3 => + state <= State_Mult4; + when State_Mult4 => + state <= State_Mult5; + when State_Mult5 => + stackA <= multResult3; + state <= State_Mult6; + when State_Mult6 => + if mem_busy='0' then + out_mem_req <= '1'; + mem_addr <= incIncSp; + sp <= incSp; + state <= State_Popped; + end if; + when State_BinaryOpResult => + if mem_busy='0' then + -- NB!!!! we know that the memory isn't busy at this point!!!! + out_mem_req <= '1'; + mem_addr <= incIncSp; + sp <= incSp; + stackA <= binaryOpResult; + state <= State_Popped; + end if; + when State_Popped => + if mem_busy='0' then + pc <= pc + 1; + stackB <= 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; + + + +end behave; diff --git a/zpu/hdl/zy2000/zpupkg.vhd b/zpu/hdl/zy2000/zpupkg.vhd new file mode 100644 index 0000000..1a01563 --- /dev/null +++ b/zpu/hdl/zy2000/zpupkg.vhd @@ -0,0 +1,168 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.all; +use IEEE.STD_LOGIC_ARITH.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(maxAddrBit 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(maxAddrBit 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; + mem_req : out std_logic; + mem_we : out std_logic; + mem_ack : 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); + mem_writeMask: out std_logic_vector(wordBytes-1 downto 0); + interrupt : in std_logic; + break : out std_logic; + zpu_status : out std_logic_vector(63 downto 0)); + end component; + + + + component timer is + port( + clk : in std_logic; + areset : in std_logic; + sample : in std_logic; + reset : in std_logic; + counter : out std_logic_vector(63 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_Shiftleft: std_logic_vector(3 downto 0) := "0001"; + constant OpCode_PushSP : std_logic_vector(3 downto 0) := "0010"; + constant OpCode_PushInt : 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_Compare : std_logic_vector(3 downto 0) := "1110"; + constant OpCode_PopInt : std_logic_vector(3 downto 0) := "1111"; + + constant OpCode_Lessthan : std_logic_vector(5 downto 0) := conv_std_logic_vector(36, 6); + constant OpCode_Lessthanorequal : std_logic_vector(5 downto 0) := conv_std_logic_vector(37, 6); + constant OpCode_Ulessthan : std_logic_vector(5 downto 0) := conv_std_logic_vector(38, 6); + constant OpCode_Ulessthanorequal : std_logic_vector(5 downto 0) := conv_std_logic_vector(39, 6); + + constant OpCode_Swap : std_logic_vector(5 downto 0) := conv_std_logic_vector(40, 6); + constant OpCode_Mult : std_logic_vector(5 downto 0) := conv_std_logic_vector(41, 6); + + constant OpCode_Lshiftright : std_logic_vector(5 downto 0) := conv_std_logic_vector(42, 6); + constant OpCode_Ashiftleft : std_logic_vector(5 downto 0) := conv_std_logic_vector(43, 6); + constant OpCode_Ashiftright : std_logic_vector(5 downto 0) := conv_std_logic_vector(44, 6); + constant OpCode_Call : std_logic_vector(5 downto 0) := conv_std_logic_vector(45, 6); + + constant OpCode_Eq : std_logic_vector(5 downto 0) := conv_std_logic_vector(46, 6); + constant OpCode_Neq : std_logic_vector(5 downto 0) := conv_std_logic_vector(47, 6); + + constant OpCode_Sub : std_logic_vector(5 downto 0) := conv_std_logic_vector(49, 6); + constant OpCode_Loadb : std_logic_vector(5 downto 0) := conv_std_logic_vector(51, 6); + constant OpCode_Storeb : std_logic_vector(5 downto 0) := conv_std_logic_vector(52, 6); + + constant OpCode_Eqbranch : std_logic_vector(5 downto 0) := conv_std_logic_vector(55, 6); + constant OpCode_Neqbranch : std_logic_vector(5 downto 0) := conv_std_logic_vector(56, 6); + constant OpCode_Poppcrel : std_logic_vector(5 downto 0) := conv_std_logic_vector(57, 6); + + constant OpCode_Pushspadd : std_logic_vector(5 downto 0) := conv_std_logic_vector(61, 6); + constant OpCode_Mult16x16 : std_logic_vector(5 downto 0) := conv_std_logic_vector(62, 6); + constant OpCode_Callpcrel : std_logic_vector(5 downto 0) := conv_std_logic_vector(63, 6); + + + + constant OpCode_Size : integer := 8; + + + +end zpupkg; -- cgit v1.1