-------------------------------------------------------------------------- -- Project: JCPU, a portable 8-bit RISC CPU written in VHDL -- This file: Types, constants and functions for JCPU -- -- Copyright (C) 2007 J. Ahrensfeld -- -- This program is free software: you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation, either version 3 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program. If not, see . -- -- For questions and ideas, please contact the author at jens@jayfield.org -- -------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.ALL; package cpu_pkg is -- Revision of the CPU constant REVISION : integer := 2; -- Chipram depth (can be tweaked) constant CHIPRAM_SIZE_BITS : integer := 10; -- Chipregister file depth constant CHIPREG_SIZE_BITS : integer := 8; -- Number of registers (can be tweaked) constant REG_SIZE_BITS : integer := 4; -- Instruction memory constant IMEM_ADDR_WIDTH : integer := 12; -- Data memory constant DMEM_DATA_WIDTH : integer := 8; constant DMEM_ADDR_WIDTH : integer := 8; -- Instruction format constant INST_OPCODE_WIDTH : integer := 6; constant IMEM_DATA_WIDTH : integer := INST_OPCODE_WIDTH + DMEM_DATA_WIDTH + REG_SIZE_BITS; -- Microcode ROM constant MUCODE_ADDR_WIDTH : integer := 9; -- Stack depth constant STACK_SIZE_BITS : integer := CHIPRAM_SIZE_BITS-1; --Types subtype iphase_t is integer range 0 to 1; type mem_access_t is (cmem_access, xmem_access, cio_access, xio_access); type reg_src_t is (alu_src, stk_src, cmem_src, xmem_src); type alu_src_t is (reg_a, reg_b, const); type ddata_src_t is (reg_a, reg_b, const); type daddr_src_t is (reg_a, reg_b, const); subtype instr_name_t is string(1 to 12); type instr_name_array_t is array (0 to 63) of instr_name_t; subtype opcode_t is unsigned (INST_OPCODE_WIDTH-1 downto 0); subtype inst_data_t is unsigned (IMEM_ADDR_WIDTH-1 downto 0); subtype inst_addr_t is unsigned (IMEM_ADDR_WIDTH-1 downto 0); subtype inst_t is unsigned (IMEM_DATA_WIDTH-1 downto 0); subtype dmem_data_t is unsigned (DMEM_DATA_WIDTH-1 downto 0); subtype dmem_addr_t is unsigned (DMEM_DATA_WIDTH-1 downto 0); subtype reg_ptr_t is unsigned (3 downto 0); type dmem_array_t is array (natural range <>) of dmem_data_t; type instr_addr_array is array (integer range <>) of inst_addr_t; subtype page_sel_t is unsigned (CHIPRAM_SIZE_BITS-DMEM_DATA_WIDTH-2 downto 0); type alu_op_t is ( pass_op2, op1_add_op2, op1_sub_op2, op1_addc_op2, op1_subc_op2, op1_and_op2, op1_or_op2, op1_xor_op2, swap_op, shl_op, shr_op, rol_op, ror_op, rolc_op, rorc_op ); type alu_status_t is record zero : STD_LOGIC; carry : STD_LOGIC; end record; type cpu_status_t is record alu : alu_status_t; end record; type ctrl_lines_t is record reg_we : STD_LOGIC; reg_src_sel : reg_src_t; alu_op1_src_sel : alu_src_t; alu_op2_src_sel : alu_src_t; alu_opsel : alu_op_t; alu_load : STD_LOGIC; ddata_src_sel : ddata_src_t; daddr_src_sel : daddr_src_t; pc_load : STD_LOGIC; pc_inc : STD_LOGIC; stk_push : STD_LOGIC; stk_pop : STD_LOGIC; stk_pushd : STD_LOGIC; stk_popd : STD_LOGIC; mem_access : mem_access_t; mem_read : STD_LOGIC; mem_write : STD_LOGIC; int_exit : STD_LOGIC; end record; type dpath_ctrl_out_t is record lines : ctrl_lines_t; reg_a_ptr : reg_ptr_t; reg_b_ptr : reg_ptr_t; end record; type int_ctrl_in_t is record enable : std_logic; polarity : std_logic; edge_sens : std_logic; request : std_logic; end record; type creg_ctrl_out_t is record page_sel : page_sel_t; int_ctrl : int_ctrl_in_t; stk_high : unsigned(IMEM_ADDR_WIDTH-DMEM_ADDR_WIDTH-1 downto 0); cmem_high : unsigned(IMEM_ADDR_WIDTH-DMEM_ADDR_WIDTH-1 downto 0); end record; type creg_ctrl_in_t is record alu : alu_status_t; end record; type murom_t is array (0 to integer(2**MUCODE_ADDR_WIDTH)-1) of ctrl_lines_t; constant instr_name_array : instr_name_array_t := ( "NOP ", -- 00 "HALT ", -- 01 "MOV|R|R ", -- 02 "MOV|R|K ", -- 03 "MOVX|R|Ri ", -- 04 "MOVX|R|Ki ", -- 05 "MOVX|Ri|R ", -- 06 "MOVX|Ri|K ", -- 07 "MOVX|Ki|R ", -- 08 "MOVC|R|Ri ", -- 09 "MOVC|R|Ki ", -- 0A "MOVC|Ri|R ", -- 0B "MOVC|Ri|K ", -- 0C "MOVC|Ki|R ", -- 0D "CMP|R|R ", -- 0E "CMP|R|K ", -- 0F "ADD|R|R ", -- 10 "ADD|R|K ", -- 11 "ADDC|R|R ", -- 12 "ADDC|R|K ", -- 13 "SUB|R|R ", -- 14 "SUB|R|K ", -- 15 "SUBC|R|R ", -- 16 "SUBC|R|K ", -- 17 "AND|R|R ", -- 18 "AND|R|K ", -- 19 "OR|R|R ", -- 1A "OR|R|K ", -- 1B "XOR|R|R ", -- 1C "XOR|R|K ", -- 1D "SHL|R ", -- 1E "SHR|R ", -- 1F "ROL|R ", -- 20 "ROR|R ", -- 21 "ROLC|R ", -- 22 "RORC|R ", -- 23 "XOUT|Ki|R ", -- 24 "XOUT|Ri|K ", -- 25 "COUT|Ki|R ", -- 26 "COUT|Ri|K ", -- 27 "XIN|R|Ki ", -- 28 "CIN|R|Ki ", -- 29 "SWAP|R ", -- 2A "UNDEF ", -- 2B "UNDEF ", -- 2C "UNDEF ", -- 2D "SUB|K|R ", -- 2E "SUBC|K|R ", -- 2F "JMP|K ", -- 30 "JZ|K ", -- 31 "JNZ|K ", -- 32 "JC|K ", -- 33 "JNC|K ", -- 34 "JLT|K ", -- 35 "JGT|K ", -- 36 "JLE|K ", -- 37 "JGE|K ", -- 38 "JEQ|K ", -- 39 "JNE|K ", -- 3A "CALL|K ", -- 3B "PUSH|R ", -- 3C "POP|R ", -- 3D "RET ", -- 3E "RETI " -- 3F ); -- Functions function Instr(opcode : opcode_t) return inst_t; function Instr(opcode : opcode_t; data : inst_data_t) return inst_t; function Instr(opcode : opcode_t; data : inst_data_t; reg : integer) return inst_t; function Instr(opcode : opcode_t; reg_a : integer) return inst_t; function Instr(opcode : opcode_t; reg_a, reg_b : integer) return inst_t; function Instr(opcode : opcode_t; reg_a, reg_b, reg_c : integer) return inst_t; function ctrl_lines_default return ctrl_lines_t; function idecoder(instr_name : instr_name_t; iphase : iphase_t; alu_status : alu_status_t) return ctrl_lines_t; function idecoder(opcode : opcode_t; iphase : iphase_t; alu_status : alu_status_t) return ctrl_lines_t; function gen_murom return murom_t; function get_muromaddr (opcode : opcode_t; iphase : iphase_t; alu_status : alu_status_t) return unsigned; function MIN (X, Y: INTEGER) return INTEGER; function MAX (X, Y: INTEGER) return INTEGER; end cpu_pkg; package body cpu_pkg is function Instr(opcode : opcode_t) return inst_t is variable inst : inst_t := (others => '0'); begin inst(inst_t'length-1 downto inst_t'length-opcode_t'length) := opcode; return inst; end Instr; function Instr(opcode : opcode_t; data : inst_data_t) return inst_t is variable inst : inst_t := (others => '0'); begin inst(inst_t'length-1 downto inst_t'length-opcode_t'length) := opcode; inst(inst_t'length-opcode_t'length-1 downto inst_t'length-opcode_t'length-inst_addr_t'length) := data; return inst; end Instr; function Instr(opcode : opcode_t; data : inst_data_t; reg : integer) return inst_t is variable inst : inst_t := (others => '0'); begin inst(inst_t'length-1 downto inst_t'length-opcode_t'length) := opcode; inst(inst_t'length-opcode_t'length-1 downto inst_t'length-opcode_t'length-inst_data_t'length) := data; inst(reg_ptr_t'length-1 downto 0) := reg_ptr_t(to_unsigned(reg, reg_ptr_t'length)); return inst; end Instr; function Instr(opcode : opcode_t; reg_a : integer) return inst_t is variable inst : inst_t := (others => '0'); begin inst(inst_t'length-1 downto inst_t'length-opcode_t'length) := opcode; inst(reg_ptr_t'length-1 downto 0) := reg_ptr_t(to_unsigned(reg_a, reg_ptr_t'length)); return inst; end Instr; function Instr(opcode : opcode_t; reg_a, reg_b : integer) return inst_t is variable inst : inst_t := (others => '0'); begin inst(inst_t'length-1 downto inst_t'length-opcode_t'length) := opcode; inst(2*(reg_ptr_t'length)-1 downto reg_ptr_t'length) := reg_ptr_t(to_unsigned(reg_b, reg_ptr_t'length)); inst(reg_ptr_t'length-1 downto 0) := reg_ptr_t(to_unsigned(reg_a, reg_ptr_t'length)); return inst; end Instr; function Instr(opcode : opcode_t; reg_a, reg_b, reg_c : integer) return inst_t is variable inst : inst_t := (others => '0'); begin inst(inst_t'length-1 downto inst_t'length-opcode_t'length) := opcode; inst(3*(reg_ptr_t'length)-1 downto 2*reg_ptr_t'length) := reg_ptr_t(to_unsigned(reg_c, reg_ptr_t'length)); inst(2*(reg_ptr_t'length)-1 downto reg_ptr_t'length) := reg_ptr_t(to_unsigned(reg_b, reg_ptr_t'length)); inst(reg_ptr_t'length-1 downto 0) := reg_ptr_t(to_unsigned(reg_a, reg_ptr_t'length)); return inst; end Instr; function ctrl_lines_default return ctrl_lines_t is variable result : ctrl_lines_t; begin result.pc_load := '0'; result.pc_inc := '0'; result.stk_push := '0'; result.stk_pop := '0'; result.stk_pushd := '0'; result.stk_popd := '0'; result.reg_we := '0'; result.reg_src_sel := alu_src; result.ddata_src_sel := reg_a; result.daddr_src_sel := reg_b; result.alu_opsel := pass_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.alu_load := '0'; result.mem_access := cmem_access; result.mem_read := '0'; result.mem_write := '0'; result.int_exit := '0'; return result; end ctrl_lines_default; function idecoder(opcode : opcode_t; iphase : iphase_t; alu_status : alu_status_t) return ctrl_lines_t is variable instr_name : instr_name_t; begin instr_name := instr_name_array(to_integer(opcode)); return idecoder(instr_name, iphase, alu_status); end idecoder; function idecoder(instr_name : instr_name_t; iphase : iphase_t; alu_status : alu_status_t) return ctrl_lines_t is variable result : ctrl_lines_t; variable ze, cy : STD_LOGIC; begin ze := alu_status.zero; cy := alu_status.carry; result := ctrl_lines_default; if iphase = 0 then result.pc_inc := '1'; end if; case instr_name is when "HALT " => result.pc_inc := '0'; when "MOV|R|R " => -- R(a) <= R(b) result.reg_src_sel := alu_src; result.alu_opsel := pass_op2; result.alu_op2_src_sel := reg_b; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "MOV|R|K " => -- R(a) <= #kk result.reg_src_sel := alu_src; result.alu_opsel := pass_op2; result.alu_op2_src_sel := const; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "MOVC|Ri|R " => -- [R(b)] <= R(a) result.mem_access := cmem_access; result.daddr_src_sel := reg_b; result.ddata_src_sel := reg_a; if iphase = 0 then result.mem_write := '1'; end if; when "MOVC|Ri|K " => -- [R(a)] <= kk result.mem_access := cmem_access; result.daddr_src_sel := reg_a; result.ddata_src_sel := const; if iphase = 0 then result.mem_write := '1'; end if; when "COUT|Ri|K " => -- [R(a)] <= kk result.mem_access := cio_access; result.daddr_src_sel := reg_a; result.ddata_src_sel := const; if iphase = 0 then result.mem_write := '1'; end if; when "MOVC|R|Ri " => -- R(a) <= [R(b)] result.mem_access := cmem_access; result.reg_src_sel := cmem_src; result.daddr_src_sel := reg_b; if iphase = 1 then result.reg_we := '1'; end if; when "MOVC|R|Ki " => -- R(a) <= [#addr] result.mem_access := cmem_access; result.reg_src_sel := cmem_src; result.daddr_src_sel := const; if iphase = 1 then result.reg_we := '1'; end if; when "CIN|R|Ki " => -- R(a) <= [#addr] result.mem_access := cio_access; result.reg_src_sel := cmem_src; result.daddr_src_sel := const; if iphase = 1 then result.reg_we := '1'; end if; when "MOVC|Ki|R " => -- [#addr] <= R(a) result.mem_access := cmem_access; result.daddr_src_sel := const; result.ddata_src_sel := reg_a; if iphase = 0 then result.mem_write := '1'; end if; when "COUT|Ki|R " => -- [#addr] <= R(a) result.mem_access := cio_access; result.daddr_src_sel := const; result.ddata_src_sel := reg_a; if iphase = 0 then result.mem_write := '1'; end if; when "MOVX|Ri|R " => -- [R(b)] <= R(a) result.mem_access := xmem_access; result.daddr_src_sel := reg_b; result.ddata_src_sel := reg_a; if iphase = 0 then result.mem_write := '1'; end if; when "MOVX|Ri|K " => -- [R(a)] <= kk result.mem_access := xmem_access; result.daddr_src_sel := reg_a; result.ddata_src_sel := const; if iphase = 0 then result.mem_write := '1'; end if; when "XOUT|Ri|K " => -- [R(a)] <= kk result.mem_access := xio_access; result.daddr_src_sel := reg_a; result.ddata_src_sel := const; if iphase = 0 then result.mem_write := '1'; end if; when "MOVX|R|Ri " => -- R(a) <= [R(b)] result.mem_access := xmem_access; result.reg_src_sel := xmem_src; result.daddr_src_sel := reg_b; if iphase = 0 then result.mem_read := '1'; elsif iphase = 1 then result.reg_we := '1'; end if; when "MOVX|R|Ki " => -- R(a) <= [#addr] result.mem_access := xmem_access; result.reg_src_sel := xmem_src; result.daddr_src_sel := const; if iphase = 0 then result.mem_read := '1'; elsif iphase = 1 then result.reg_we := '1'; end if; when "XIN|R|Ki " => -- R(a) <= [#addr] result.mem_access := xio_access; result.reg_src_sel := xmem_src; result.daddr_src_sel := const; if iphase = 0 then result.mem_read := '1'; elsif iphase = 1 then result.reg_we := '1'; end if; when "MOVX|Ki|R " => -- [#addr] <= R(a) result.mem_access := xmem_access; result.daddr_src_sel := const; result.ddata_src_sel := reg_a; if iphase = 0 then result.mem_write := '1'; end if; when "XOUT|Ki|R " => -- [#addr] <= R(a) result.mem_access := xio_access; result.daddr_src_sel := const; result.ddata_src_sel := reg_a; if iphase = 0 then result.mem_write := '1'; end if; when "ADD|R|R " => -- R(a) <= R(a) + R(b) result.alu_opsel := op1_add_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "ADD|R|K " => -- R(a) <= R(a) + k result.alu_opsel := op1_add_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := const; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "ADDC|R|R " => -- R(a) <= R(a) + R(b) result.alu_opsel := op1_addc_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "ADDC|R|K " => -- R(a) <= R(a) + k result.alu_opsel := op1_addc_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := const; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SUB|R|R " => -- R(a) <= R(a) + R(b) result.alu_opsel := op1_sub_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SUB|R|K " => -- R(a) <= R(a) + k result.alu_opsel := op1_sub_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := const; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SUB|K|R " => -- R(a) <= k - R(a) result.alu_opsel := op1_sub_op2; result.alu_op1_src_sel := const; result.alu_op2_src_sel := reg_a; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SUBC|R|R " => -- R(a) <= R(a) + R(b) result.alu_opsel := op1_subc_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SUBC|R|K " => -- R(a) <= R(a) + k result.alu_opsel := op1_subc_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := const; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SUBC|K|R " => -- R(a) <= K - R(a) result.alu_opsel := op1_subc_op2; result.alu_op1_src_sel := const; result.alu_op2_src_sel := reg_a; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "AND|R|R " => -- R(a) <= R(a) and R(b) result.alu_opsel := op1_and_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "AND|R|K " => -- R(a) <= R(a) and k result.alu_opsel := op1_and_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := const; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "OR|R|R " => -- R(a) <= R(a) or R(b) result.alu_opsel := op1_or_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "OR|R|K " => -- R(a) <= R(a) or R(b) result.alu_opsel := op1_or_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := const; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "XOR|R|R " => -- R(a) <= R(a) xor R(b) result.alu_opsel := op1_xor_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "XOR|R|K " => -- R(a) <= R(a) xor R(b) result.alu_opsel := op1_xor_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := const; result.reg_src_sel := alu_src; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SWAP|R " => -- R(a) <= R(b) result.reg_src_sel := alu_src; result.alu_opsel := swap_op; result.alu_op1_src_sel := reg_a; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SHL|R " => -- R(a) <= R(a) xor R(b) result.reg_src_sel := alu_src; result.alu_opsel := shl_op; result.alu_op1_src_sel := reg_a; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "SHR|R " => -- R(a) <= R(a) xor R(b) result.reg_src_sel := alu_src; result.alu_opsel := shr_op; result.alu_op1_src_sel := reg_a; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "ROL|R " => -- R(a) <= R(a) xor R(b) result.reg_src_sel := alu_src; result.alu_opsel := rol_op; result.alu_op1_src_sel := reg_a; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "ROR|R " => -- R(a) <= R(a) xor R(b) result.reg_src_sel := alu_src; result.alu_opsel := ror_op; result.alu_op1_src_sel := reg_a; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "ROLC|R " => -- R(a) <= R(a) xor R(b) result.reg_src_sel := alu_src; result.alu_opsel := rolc_op; result.alu_op1_src_sel := reg_a; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "RORC|R " => -- R(a) <= R(a) xor R(b) result.reg_src_sel := alu_src; result.alu_opsel := rorc_op; result.alu_op1_src_sel := reg_a; result.alu_load := '1'; if iphase = 1 then result.reg_we := '1'; end if; when "CMP|R|R " => -- result.alu_opsel := op1_sub_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := reg_b; result.alu_load := '1'; when "CMP|R|K " => -- result.alu_opsel := op1_sub_op2; result.alu_op1_src_sel := reg_a; result.alu_op2_src_sel := const; result.alu_load := '1'; when "JMP|K " => -- PC <= #addr if iphase = 0 then result.pc_load := '1'; end if; when "JZ|K " => -- PC <= #addr, zero if iphase = 0 then if ze = '1' then result.pc_load := '1'; end if; end if; when "JNZ|K " => -- PC <= #addr, !zero if iphase = 0 then if ze = '0' then result.pc_load := '1'; end if; end if; when "JC|K " => -- PC <= #addr, carry if iphase = 0 then if cy = '1' then result.pc_load := '1'; end if; end if; when "JNC|K " => -- PC <= #addr, !carry if iphase = 0 then if cy = '0' then result.pc_load := '1'; end if; end if; when "JLT|K " => -- PC <= #addr, !carry if iphase = 0 then if cy = '1' then result.pc_load := '1'; end if; end if; when "JGT|K " => -- if iphase = 0 then if (cy or ze) = '0' then result.pc_load := '1'; end if; end if; when "JLE|K " => -- if iphase = 0 then if (cy xor ze) = '1' then result.pc_load := '1'; end if; end if; when "JGE|K " => -- if iphase = 0 then if (not cy or ze) = '1' then result.pc_load := '1'; end if; end if; when "JEQ|K " => -- if iphase = 0 then if ze = '1' then result.pc_load := '1'; end if; end if; when "JNE|K " => -- if iphase = 0 then if ze = '0' then result.pc_load := '1'; end if; end if; when "PUSH|R " => -- push if iphase = 0 then result.stk_pushd := '1'; end if; when "POP|R " => -- pop result.reg_src_sel := stk_src; if iphase = 0 then result.stk_popd := '1'; elsif iphase = 1 then result.reg_we := '1'; end if; when "CALL|K " => -- call if iphase = 0 then result.pc_load := '1'; result.stk_push := '1'; end if; when "RET " => -- return if iphase = 0 then result.pc_load := '1'; result.stk_pop := '1'; end if; when "RETI " => -- return result.pc_inc := '0'; result.int_exit := '1'; when others => null; -- nop end case; return result; end idecoder; function gen_murom return murom_t is variable result : murom_t; variable opcode : opcode_t; variable iphase : iphase_t; variable addr : unsigned(MUCODE_ADDR_WIDTH-1 downto 0); variable alu_status : alu_status_t; variable pos : integer := 0; begin for i in 0 to 2**addr'length-1 loop addr := to_unsigned(i, addr'length); opcode := addr(opcode'length-1 downto 0); pos := opcode'length; iphase := 0; if addr(pos) = '1' then iphase := 1; end if; pos := pos + 1; alu_status.zero := addr(pos); pos := pos + 1; alu_status.carry := addr(pos); result(i) := idecoder(opcode, iphase, alu_status); end loop; return result; end gen_murom; function get_muromaddr (opcode : opcode_t; iphase : iphase_t; alu_status : alu_status_t) return unsigned is variable addr : unsigned(MUCODE_ADDR_WIDTH-1 downto 0); begin addr := alu_status.carry & alu_status.zero & to_unsigned(iphase, 1) & opcode; return addr; end get_muromaddr; ------------------------------------------------------------- function MIN (X, Y: INTEGER) return INTEGER is variable res : integer := X; begin if Y < X then res := Y; end if; return res; end MIN; ------------------------------------------------------------- function MAX (X, Y: INTEGER) return INTEGER is variable res : integer := X; begin if Y > X then res := Y; end if; return res; end MAX; end cpu_pkg;