copyleft: gplv3 added and set repo to public
[calu.git] / cpu / src / decoder_b.vhd
index 1804811a9efac1583bd20e450b6c0d1afe32b734..abeedb9806ef1e2371a876e229f4eeb6f8f66922 100644 (file)
@@ -1,3 +1,24 @@
+--   `Deep Thought', a softcore CPU implemented on a FPGA
+--
+--  Copyright (C) 2010 Markus Hofstaetter <markus.manrow@gmx.at>
+--  Copyright (C) 2010 Martin Perner <e0725782@student.tuwien.ac.at>
+--  Copyright (C) 2010 Stefan Rebernig <stefan.rebernig@gmail.com>
+--  Copyright (C) 2010 Manfred Schwarz <e0725898@student.tuwien.ac.at>
+--  Copyright (C) 2010 Bernhard Urban <lewurm@gmail.com>
+--
+--  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 <http://www.gnu.org/licenses/>.
+
 library IEEE;
 use IEEE.std_logic_1164.all;
 use IEEE.numeric_std.all;
@@ -25,15 +46,18 @@ begin
        instr_s.reg_src2_addr := (others => '0');
 
        instr_s.immediate := (others => '0');
-       instr_s.displacement := (others => '0');
        instr_s.jmptype := (others => '0');
-       instr_s.carry := '0';
-       instr_s.sreg_update := '0';
        instr_s.high_low := '0';
        instr_s.fill := '0';
        instr_s.signext := '0';
        instr_s.bp := '0';
-       instr_s.arith := '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
 
@@ -44,8 +68,32 @@ begin
                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);
+
+               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);
@@ -84,14 +132,21 @@ begin
                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.signext = '1' and instr_s.immediate(11) = '1') then
                        instr_s.immediate(31 downto 12) := (others => '1');
                end if;
-       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);
@@ -113,7 +168,25 @@ begin
                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.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
@@ -133,16 +206,20 @@ begin
 --             instr_s.sreg_update := instruction(0);
 --
 --=================================================================
-       if (instr_s.opcode = "01010" or instr_s.opcode = "01011") then
+       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.left_right := instruction(3);           
-               instr_s.arith := instruction(2);                
-               instr_s.carry := instruction(1);
-               instr_s.sreg_update := instruction(0);
+
+               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
@@ -160,13 +237,43 @@ begin
 --     when "01110" =>         --ldw
                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);
+               instr_s.displacement(14 downto 0) := instruction(14 downto 0);
 
-               if (instr_s.signext = '1' and instr_s.immediate(11) = '1') then
-                       instr_s.immediate(31 downto 16) := (others => '1');
+               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;
 
@@ -198,11 +305,56 @@ begin
        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_src1_addr := instruction(22 downto 19);     -- register value
-               instr_s.reg_src2_addr := instruction(18 downto 15);     -- mem addr
+               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);
@@ -227,6 +379,67 @@ begin
                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
@@ -242,7 +455,21 @@ begin
 --     when "11000" =>         --cmp
                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);
+
+               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