-- `Deep Thought', a softcore CPU implemented on a FPGA -- -- Copyright (C) 2010 Markus Hofstaetter -- Copyright (C) 2010 Martin Perner -- Copyright (C) 2010 Stefan Rebernig -- Copyright (C) 2010 Manfred Schwarz -- Copyright (C) 2010 Bernhard Urban -- -- 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 . library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all; use work.mem_pkg.all; use work.core_pkg.all; use work.common_pkg.all; architecture behav_d of decoder is begin split_instr: process(instruction) variable instr_s : instruction_rec; begin instr_s.predicates := instruction(31 downto 28); instr_s.opcode := instruction(27 downto 27-OPCODE_WIDTH+1); instr_s.reg_dest_addr := (others => '0'); instr_s.reg_src1_addr := (others => '0'); instr_s.reg_src2_addr := (others => '0'); instr_s.immediate := (others => '0'); instr_s.jmptype := (others => '0'); instr_s.high_low := '0'; instr_s.fill := '0'; instr_s.signext := '0'; instr_s.bp := '0'; instr_s.op_detail := (others => '0'); instr_s.displacement := (others => '0'); instr_s.int := '0'; instr_s.op_group := ADDSUB_OP; -- type op_info_t is (ADDSUB_OP,AND_OP,OR_OP, XOR_OP,SHIFT_OP); -- special function register operations missing -- case opcode is --================================================================= if (instr_s.opcode = "00000" or instr_s.opcode = "00001" or instr_s.opcode = "00100" or instr_s.opcode = "00110" or instr_s.opcode = "01000") then -- when "00000" => --add instr_s.reg_dest_addr := instruction(22 downto 19); instr_s.reg_src1_addr := instruction(18 downto 15); instr_s.reg_src2_addr := instruction(14 downto 11); instr_s.op_detail(NO_PSW_OPT) := instruction(0); --instr_s.sreg_update; instr_s.op_group := ADDSUB_OP; if (instr_s.opcode = "00000") then instr_s.op_detail(CARRY_OPT) := instruction(1); --instr_s.carry; end if; if (instr_s.opcode = "00001") then instr_s.op_detail(SUB_OPT) := '1'; instr_s.op_detail(CARRY_OPT) := instruction(1); --instr_s.carry; end if; if (instr_s.opcode = "00100") then instr_s.op_group := AND_OP; end if; if (instr_s.opcode = "00110") then instr_s.op_group := OR_OP; end if; if (instr_s.opcode = "01000") then instr_s.op_group := XOR_OP; end if; end if; -- when "00001" => --sub -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(18 downto 15); -- instr_s.reg_src2_addr := instruction(14 downto 11); -- instr_s.carry := instruction(1); -- instr_s.sreg_update := instruction(0); -- when "00100" => --and -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(18 downto 15); -- instr_s.reg_src2_addr := instruction(14 downto 11); -- instr_s.carry := instruction(1); --negligible -- instr_s.sreg_update := instruction(0); -- when "00110" => --or -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(18 downto 15); -- instr_s.reg_src2_addr := instruction(14 downto 11); -- instr_s.carry := instruction(1); --negligible -- instr_s.sreg_update := instruction(0); -- when "01000" => --xor -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(18 downto 15); -- instr_s.reg_src2_addr := instruction(14 downto 11); -- instr_s.carry := instruction(1); --negligible -- instr_s.sreg_update := instruction(0); --================================================================= if (instr_s.opcode = "00010" or instr_s.opcode = "00011") then -- when "00010" => --addi instr_s.reg_dest_addr := instruction(22 downto 19); instr_s.reg_src1_addr := instruction(18 downto 15); instr_s.immediate(11 downto 0) := instruction(14 downto 3); instr_s.signext := instruction(2); if (instr_s.signext = '1' and instr_s.immediate(11) = '1') then instr_s.immediate(31 downto 12) := (others => '1'); end if; instr_s.op_detail(IMM_OPT) := '1'; instr_s.op_detail(CARRY_OPT) := instruction(1); instr_s.op_detail(NO_PSW_OPT) := instruction(0); instr_s.op_group := ADDSUB_OP; if (instr_s.opcode = "00011") then instr_s.op_detail(SUB_OPT) := '1'; end if; end if; -- when "00011" => --subi -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(18 downto 15); -- instr_s.immediate(11 downto 0) := instruction(14 downto 3); -- instr_s.signext := instruction(2); -- instr_s.carry := instruction(1); -- instr_s.sreg_update := instruction(0); --================================================================= if (instr_s.opcode = "00101" or instr_s.opcode = "00111" or instr_s.opcode = "01001") then -- when "00101" => --andx instr_s.reg_dest_addr := instruction(22 downto 19); instr_s.reg_src1_addr := instruction(22 downto 19); instr_s.immediate(15 downto 0) := instruction(18 downto 3); instr_s.high_low := instruction(2); instr_s.fill := instruction(1); if (instr_s.fill = '1') then instr_s.immediate(31 downto 16) := (others => '1'); end if; instr_s.op_detail(IMM_OPT) := '1'; instr_s.op_detail(NO_PSW_OPT) := instruction(0); if (instr_s.opcode = "00101") then instr_s.op_group := AND_OP; end if; if (instr_s.opcode = "00111") then instr_s.op_group := OR_OP; end if; if (instr_s.opcode = "01001") then instr_s.op_group := XOR_OP; end if; end if; -- when "00111" => --orx -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(22 downto 19); -- instr_s.immediate(15 downto 0) := instruction(18 downto 3); -- instr_s.high_low := instruction(2); -- instr_s.fill := instruction(1); -- instr_s.sreg_update := instruction(0); -- -- when "01001" => --xorx -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(22 downto 19); -- instr_s.immediate(15 downto 0) := instruction(18 downto 3); -- instr_s.high_low := instruction(2); -- instr_s.fill := instruction(1); -- instr_s.sreg_update := instruction(0); -- --================================================================= if (instr_s.opcode = "01010") then -- when "01010" => --shift instr_s.reg_dest_addr := instruction(22 downto 19); instr_s.reg_src1_addr := instruction(18 downto 15); instr_s.immediate(4 downto 0) := instruction(14 downto 10); instr_s.op_detail(RIGHT_OPT) := instruction(3); instr_s.op_detail(NO_PSW_OPT) := instruction(0); instr_s.op_detail(CARRY_OPT) := instruction(1); instr_s.op_detail(ARITH_OPT) := instruction(2); instr_s.op_detail(IMM_OPT) := '1'; instr_s.op_group := SHIFT_OP; end if; -- when "01011" => --stackop -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(22 downto 19); -- instr_s.immediate(1 downto 0) := instruction(18 downto 17); -- instr_s.left_right := instruction(3); -- instr_s.arith := instruction(2); -- instr_s.carry := instruction(1); -- instr_s.sreg_update := instruction(0); --================================================================= if (instr_s.opcode = "01110" or instr_s.opcode = "10000" or instr_s.opcode = "10010" or instr_s.opcode = "11010") then -- when "01110" => --ldw instr_s.reg_dest_addr := instruction(22 downto 19); instr_s.reg_src1_addr := instruction(18 downto 15); instr_s.signext := instruction(2); instr_s.high_low := instruction(1); instr_s.displacement(14 downto 0) := instruction(14 downto 0); instr_s.op_group := LDST_OP; instr_s.op_detail(NO_PSW_OPT) := '1'; if (instr_s.displacement(14) = '1') then instr_s.displacement(31 downto 15) := (others => '1'); end if; if (instr_s.opcode = "11010") then --ldi instr_s.reg_src1_addr := instr_s.reg_dest_addr; instr_s.op_detail(LOW_HIGH_OPT) := instr_s.high_low; instr_s.op_detail(LDI_REPLACE_OPT) := instr_s.signext; if (instr_s.high_low = '1') then instr_s.immediate(31 downto 16) := instruction(18 downto 3); instr_s.immediate(15 downto 0) := (others => '0'); else instr_s.immediate(15 downto 0) := instruction(18 downto 3); instr_s.immediate(31 downto 16) := (others => '0'); end if; if (instr_s.signext = '1' and instr_s.immediate(11) = '1') then instr_s.immediate(31 downto 16) := (others => '1'); end if; instr_s.op_detail(IMM_OPT) := '1'; end if; if (instr_s.opcode = "10000") then instr_s.op_detail(HWORD_OPT) := '1'; end if; if (instr_s.opcode = "10010") then instr_s.op_detail(BYTE_OPT) := '1'; end if; end if; -- when "10000" => --ldh -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(18 downto 15); -- instr_s.displacement(14 downto 0) := instruction(14 downto 0); -- instr_s.immediate(15 downto 0) := instruction(18 downto 3); -- instr_s.signext := instruction(2); -- instr_s.high_low := instruction(1); -- when "10010" => --ldb -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(18 downto 15); -- instr_s.displacement(14 downto 0) := instruction(14 downto 0); -- instr_s.immediate(15 downto 0) := instruction(18 downto 3); -- instr_s.signext := instruction(2); -- instr_s.high_low := instruction(1); -- when "11010" => --ldi -- instr_s.reg_dest_addr := instruction(22 downto 19); -- instr_s.reg_src1_addr := instruction(18 downto 15); -- instr_s.displacement(14 downto 0) := instruction(14 downto 0); -- instr_s.immediate(15 downto 0) := instruction(18 downto 3); -- instr_s.signext := instruction(2); -- instr_s.high_low := instruction(1); --================================================================= if (instr_s.opcode = "01111" or instr_s.opcode = "10001" or instr_s.opcode = "10011" or instr_s.opcode = "10101") then --when "01111" => --stw instr_s.reg_src2_addr := instruction(22 downto 19); -- register value instr_s.reg_src1_addr := instruction(18 downto 15); -- mem addr instr_s.displacement(14 downto 0) := instruction(14 downto 0); instr_s.op_detail(NO_PSW_OPT) := '1'; instr_s.op_detail(ST_OPT) := '1'; instr_s.op_group := LDST_OP; if (instr_s.displacement(14) = '1') then instr_s.displacement(31 downto 15) := (others => '1'); end if; if (instr_s.opcode = "10001") then instr_s.op_detail(HWORD_OPT) := '1'; end if; if (instr_s.opcode = "10011") then instr_s.op_detail(BYTE_OPT) := '1'; end if; end if; -- =============================================================== if (instr_s.opcode = "01011") then -- stack op instr_s.reg_src1_addr := instruction(22 downto 19); instr_s.reg_dest_addr := instruction(22 downto 19); instr_s.op_group := STACK_OP; instr_s.op_detail(NO_PSW_OPT) := '1'; instr_s.op_detail(PWREN_OPT) := '1'; case instruction(18 downto 17) is when "00" => --pop instr_s.op_detail(PUSH_OPT) := '0'; when "01" => --disc instr_s.op_detail(PUSH_OPT) := '0'; instr_s.op_detail(NO_DST_OPT) := '1'; when "10" => --fetch instr_s.op_detail(PUSH_OPT) := '0'; instr_s.op_detail(PWREN_OPT) := '0'; when "11" => --push instr_s.op_detail(PUSH_OPT) := '1'; when others => null; end case; end if; -- when "10001" => --sth -- instr_s.reg_src1_addr := instruction(22 downto 19); -- instr_s.reg_src2_addr := instruction(18 downto 15); -- instr_s.displacement(14 downto 0) := instruction(14 downto 0); -- when "10011" => --stb -- instr_s.reg_src1_addr := instruction(22 downto 19); -- instr_s.reg_src2_addr := instruction(18 downto 15); -- instr_s.displacement(14 downto 0) := instruction(14 downto 0); -- when "10101" => --stx -- instr_s.reg_src1_addr := instruction(22 downto 19); -- instr_s.reg_src2_addr := instruction(18 downto 15); -- instr_s.displacement(14 downto 0) := instruction(14 downto 0); --================================================================= if (instr_s.opcode = "10110" or instr_s.opcode = "10111") then -- when "10110" => --jumpop instr_s.reg_src1_addr := instruction(22 downto 19); -- register value instr_s.immediate(15 downto 0) := instruction(22 downto 7); instr_s.bp := instruction(1); instr_s.jmptype := instruction(3 downto 2); instr_s.signext := instruction(0); instr_s.op_detail(NO_PSW_OPT) := '1'; instr_s.op_detail(DIRECT_JUMP_OPT) := instruction(4); instr_s.int := instruction(4); if (instr_s.opcode = "10110") then instr_s.op_detail(IMM_OPT) := '1'; else instr_s.immediate(31 downto 0) := (others => '0'); instr_s.op_detail(JMP_REG_OPT) := '1'; instr_s.op_detail(IMM_OPT) := '1'; end if; if (instr_s.signext = '1' and instr_s.immediate(15) = '1') then instr_s.immediate(31 downto 16) := (others => '1'); end if; case instr_s.jmptype is when "00" => instr_s.op_group := JMP_OP; when "01" => instr_s.op_group := JMP_ST_OP; when "10" => instr_s.op_group := JMP_ST_OP; instr_s.op_detail(RET_OPT) := '1'; when "11" => instr_s.op_group := JMP_OP; instr_s.op_detail(JMP_REG_OPT) := '1'; instr_s.op_detail(IMM_OPT) := '1'; instr_s.immediate := (others => '0'); when others => null; end case; -- if (instr_s.jmptype = "00") then ---- instr_s.op_detail(SUB_OPT) := not instr_s.opcode(0); -- instr_s.op_group := JMP_OP; -- end if; -- -- if (instr_s.jmptype = "01") then -- instr_s.op_group := JMP_ST_OP; -- -- instr_s.op_detail(RET_OPT) := '0'; -- end if; -- -- if (instr_s.jmptype = "10") then -- instr_s.op_group := JMP_ST_OP; -- instr_s.op_detail(RET_OPT) := '1'; -- end if; -- -- if (instr_s.jmptype = "11") then -- instr_s.op_group := JMP_OP; -- instr_s.op_detail(JMP_REG_OPT) := '1'; -- instr_s.op_detail(IMM_OPT) := '1'; -- instr_s.immediate := (others => '0'); -- end if; if (instr_s.predicates = "1111" or instr_s.jmptype = "10") then instr_s.bp := '0'; end if; end if; -- when "10111" => --brreg -- instr_s.reg_src1_addr := instruction(22 downto 19); -- register value -- instr_s.immediate(15 downto 0) := instruction(22 downto 7); -- negligible -- instr_s.bp := instruction(1); -- negligible -- instr_s.jmptype := instruction(3 downto 2); -- only lsb -- instr_s.signext := instruction(0); -- negligible --================================================================= if (instr_s.opcode = "11000" or instr_s.opcode = "11001") then -- when "11000" => --cmp instr_s.reg_src1_addr := instruction(22 downto 19); instr_s.reg_src2_addr := instruction(18 downto 15); if (instr_s.opcode = "11001") then instr_s.immediate(15 downto 0) := instruction(18 downto 3); instr_s.signext := instruction(2); if (instr_s.signext = '1' and instr_s.immediate(15) = '1') then instr_s.immediate(31 downto 16) := (others => '1'); end if; instr_s.op_detail(IMM_OPT) := '1'; end if; instr_s.op_detail(NO_DST_OPT) := '1'; instr_s.op_group := ADDSUB_OP; instr_s.op_detail(SUB_OPT) := '1'; end if; -- when "11001" => --cmpi -- instr_s.reg_src1_addr := instruction(22 downto 19); -- instr_s.reg_src2_addr := instruction(18 downto 15); -- instr_s.immediate(15 downto 0) := instruction(18 downto 3); -- when others => null; -- end case; instr_spl <= instr_s; end process; end behav_d; --===========================================================================