---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
-- Instruction decoder
|
-- Instruction decoder
|
--
|
--
|
-- Part of the LXP32 CPU
|
-- Part of the LXP32 CPU
|
--
|
--
|
-- Copyright (c) 2016 by Alex I. Kuznetsov
|
-- Copyright (c) 2016 by Alex I. Kuznetsov
|
--
|
--
|
-- The second stage of the LXP32 pipeline.
|
-- The second stage of the LXP32 pipeline.
|
---------------------------------------------------------------------
|
---------------------------------------------------------------------
|
|
|
library ieee;
|
library ieee;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.numeric_std.all;
|
use ieee.numeric_std.all;
|
|
|
entity lxp32_decode is
|
entity lxp32_decode is
|
port(
|
port(
|
clk_i: in std_logic;
|
clk_i: in std_logic;
|
rst_i: in std_logic;
|
rst_i: in std_logic;
|
|
|
word_i: in std_logic_vector(31 downto 0);
|
word_i: in std_logic_vector(31 downto 0);
|
next_ip_i: in std_logic_vector(29 downto 0);
|
next_ip_i: in std_logic_vector(29 downto 0);
|
current_ip_i: in std_logic_vector(29 downto 0);
|
current_ip_i: in std_logic_vector(29 downto 0);
|
valid_i: in std_logic;
|
valid_i: in std_logic;
|
jump_valid_i: in std_logic;
|
jump_valid_i: in std_logic;
|
ready_o: out std_logic;
|
ready_o: out std_logic;
|
|
|
interrupt_valid_i: in std_logic;
|
interrupt_valid_i: in std_logic;
|
interrupt_vector_i: in std_logic_vector(2 downto 0);
|
interrupt_vector_i: in std_logic_vector(2 downto 0);
|
interrupt_ready_o: out std_logic;
|
interrupt_ready_o: out std_logic;
|
|
|
|
wakeup_i: in std_logic;
|
|
|
sp_raddr1_o: out std_logic_vector(7 downto 0);
|
sp_raddr1_o: out std_logic_vector(7 downto 0);
|
sp_rdata1_i: in std_logic_vector(31 downto 0);
|
sp_rdata1_i: in std_logic_vector(31 downto 0);
|
sp_raddr2_o: out std_logic_vector(7 downto 0);
|
sp_raddr2_o: out std_logic_vector(7 downto 0);
|
sp_rdata2_i: in std_logic_vector(31 downto 0);
|
sp_rdata2_i: in std_logic_vector(31 downto 0);
|
|
|
ready_i: in std_logic;
|
ready_i: in std_logic;
|
valid_o: out std_logic;
|
valid_o: out std_logic;
|
|
|
cmd_loadop3_o: out std_logic;
|
cmd_loadop3_o: out std_logic;
|
cmd_signed_o: out std_logic;
|
cmd_signed_o: out std_logic;
|
cmd_dbus_o: out std_logic;
|
cmd_dbus_o: out std_logic;
|
cmd_dbus_store_o: out std_logic;
|
cmd_dbus_store_o: out std_logic;
|
cmd_dbus_byte_o: out std_logic;
|
cmd_dbus_byte_o: out std_logic;
|
cmd_addsub_o: out std_logic;
|
cmd_addsub_o: out std_logic;
|
cmd_mul_o: out std_logic;
|
cmd_mul_o: out std_logic;
|
cmd_div_o: out std_logic;
|
cmd_div_o: out std_logic;
|
cmd_div_mod_o: out std_logic;
|
cmd_div_mod_o: out std_logic;
|
cmd_cmp_o: out std_logic;
|
cmd_cmp_o: out std_logic;
|
cmd_jump_o: out std_logic;
|
cmd_jump_o: out std_logic;
|
cmd_negate_op2_o: out std_logic;
|
cmd_negate_op2_o: out std_logic;
|
cmd_and_o: out std_logic;
|
cmd_and_o: out std_logic;
|
cmd_xor_o: out std_logic;
|
cmd_xor_o: out std_logic;
|
cmd_shift_o: out std_logic;
|
cmd_shift_o: out std_logic;
|
cmd_shift_right_o: out std_logic;
|
cmd_shift_right_o: out std_logic;
|
|
|
jump_type_o: out std_logic_vector(3 downto 0);
|
jump_type_o: out std_logic_vector(3 downto 0);
|
|
|
op1_o: out std_logic_vector(31 downto 0);
|
op1_o: out std_logic_vector(31 downto 0);
|
op2_o: out std_logic_vector(31 downto 0);
|
op2_o: out std_logic_vector(31 downto 0);
|
op3_o: out std_logic_vector(31 downto 0);
|
op3_o: out std_logic_vector(31 downto 0);
|
dst_o: out std_logic_vector(7 downto 0)
|
dst_o: out std_logic_vector(7 downto 0)
|
);
|
);
|
end entity;
|
end entity;
|
|
|
architecture rtl of lxp32_decode is
|
architecture rtl of lxp32_decode is
|
|
|
-- Decoder FSM state
|
-- Decoder FSM state
|
|
|
type DecoderState is (Regular,ContinueLc,ContinueCjmp,ContinueInterrupt,Halt);
|
type DecoderState is (Regular,ContinueLc,ContinueCjmp,ContinueInterrupt,Halt);
|
signal state: DecoderState:=Regular;
|
signal state: DecoderState:=Regular;
|
|
|
-- Input instruction portions
|
-- Input instruction portions
|
|
|
signal opcode: std_logic_vector(5 downto 0);
|
signal opcode: std_logic_vector(5 downto 0);
|
signal t1: std_logic;
|
signal t1: std_logic;
|
signal t2: std_logic;
|
signal t2: std_logic;
|
signal destination: std_logic_vector(7 downto 0);
|
signal destination: std_logic_vector(7 downto 0);
|
signal rd1: std_logic_vector(7 downto 0);
|
signal rd1: std_logic_vector(7 downto 0);
|
signal rd2: std_logic_vector(7 downto 0);
|
signal rd2: std_logic_vector(7 downto 0);
|
|
|
-- Signals related to pipeline control
|
-- Signals related to pipeline control
|
|
|
signal downstream_busy: std_logic;
|
signal downstream_busy: std_logic;
|
signal self_busy: std_logic:='0';
|
signal self_busy: std_logic:='0';
|
signal busy: std_logic;
|
signal busy: std_logic;
|
signal valid_out: std_logic:='0';
|
signal valid_out: std_logic:='0';
|
|
|
signal dst_out: std_logic_vector(7 downto 0);
|
signal dst_out: std_logic_vector(7 downto 0);
|
|
|
-- Signals related to RD operand decoding
|
-- Signals related to RD operand decoding
|
|
|
signal rd1_reg: std_logic_vector(7 downto 0);
|
signal rd1_reg: std_logic_vector(7 downto 0);
|
signal rd2_reg: std_logic_vector(7 downto 0);
|
signal rd2_reg: std_logic_vector(7 downto 0);
|
|
|
signal rd1_select: std_logic;
|
signal rd1_select: std_logic;
|
signal rd1_direct: std_logic_vector(31 downto 0);
|
signal rd1_direct: std_logic_vector(31 downto 0);
|
signal rd2_select: std_logic;
|
signal rd2_select: std_logic;
|
signal rd2_direct: std_logic_vector(31 downto 0);
|
signal rd2_direct: std_logic_vector(31 downto 0);
|
|
|
-- Signals related to interrupt handling
|
-- Signals related to interrupt handling
|
|
|
signal interrupt_ready: std_logic:='0';
|
signal interrupt_ready: std_logic:='0';
|
|
signal wakeup_reg: std_logic:='0';
|
|
|
begin
|
begin
|
|
|
-- Dissect input word
|
-- Dissect input word
|
|
|
opcode<=word_i(31 downto 26);
|
opcode<=word_i(31 downto 26);
|
t1<=word_i(25);
|
t1<=word_i(25);
|
t2<=word_i(24);
|
t2<=word_i(24);
|
destination<=word_i(23 downto 16);
|
destination<=word_i(23 downto 16);
|
rd1<=word_i(15 downto 8);
|
rd1<=word_i(15 downto 8);
|
rd2<=word_i(7 downto 0);
|
rd2<=word_i(7 downto 0);
|
|
|
-- Pipeline control
|
-- Pipeline control
|
|
|
downstream_busy<=valid_out and not ready_i;
|
downstream_busy<=valid_out and not ready_i;
|
busy<=downstream_busy or self_busy;
|
busy<=downstream_busy or self_busy;
|
|
|
process (clk_i) is
|
process (clk_i) is
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
if rst_i='1' then
|
if rst_i='1' then
|
valid_out<='0';
|
valid_out<='0';
|
self_busy<='0';
|
self_busy<='0';
|
state<=Regular;
|
state<=Regular;
|
interrupt_ready<='0';
|
interrupt_ready<='0';
|
cmd_loadop3_o<='-';
|
cmd_loadop3_o<='-';
|
cmd_signed_o<='-';
|
cmd_signed_o<='-';
|
cmd_dbus_o<='-';
|
cmd_dbus_o<='-';
|
cmd_dbus_store_o<='-';
|
cmd_dbus_store_o<='-';
|
cmd_dbus_byte_o<='-';
|
cmd_dbus_byte_o<='-';
|
cmd_addsub_o<='-';
|
cmd_addsub_o<='-';
|
cmd_negate_op2_o<='-';
|
cmd_negate_op2_o<='-';
|
cmd_mul_o<='-';
|
cmd_mul_o<='-';
|
cmd_div_o<='-';
|
cmd_div_o<='-';
|
cmd_div_mod_o<='-';
|
cmd_div_mod_o<='-';
|
cmd_cmp_o<='-';
|
cmd_cmp_o<='-';
|
cmd_jump_o<='-';
|
cmd_jump_o<='-';
|
cmd_and_o<='-';
|
cmd_and_o<='-';
|
cmd_xor_o<='-';
|
cmd_xor_o<='-';
|
cmd_shift_o<='-';
|
cmd_shift_o<='-';
|
cmd_shift_right_o<='-';
|
cmd_shift_right_o<='-';
|
rd1_select<='-';
|
rd1_select<='-';
|
rd1_direct<=(others=>'-');
|
rd1_direct<=(others=>'-');
|
rd2_select<='-';
|
rd2_select<='-';
|
rd2_direct<=(others=>'-');
|
rd2_direct<=(others=>'-');
|
op3_o<=(others=>'-');
|
op3_o<=(others=>'-');
|
jump_type_o<=(others=>'-');
|
jump_type_o<=(others=>'-');
|
dst_out<=(others=>'-');
|
dst_out<=(others=>'-');
|
|
wakeup_reg<='0';
|
else
|
else
|
interrupt_ready<='0';
|
interrupt_ready<='0';
|
|
wakeup_reg<=wakeup_reg or wakeup_i;
|
if jump_valid_i='1' then
|
if jump_valid_i='1' then
|
valid_out<='0';
|
valid_out<='0';
|
self_busy<='0';
|
self_busy<='0';
|
state<=Regular;
|
state<=Regular;
|
elsif downstream_busy='0' then
|
elsif downstream_busy='0' then
|
op3_o<=(others=>'-');
|
op3_o<=(others=>'-');
|
rd1_direct<=std_logic_vector(resize(signed(rd1),rd1_direct'length));
|
rd1_direct<=std_logic_vector(resize(signed(rd1),rd1_direct'length));
|
rd2_direct<=std_logic_vector(resize(signed(rd2),rd2_direct'length));
|
rd2_direct<=std_logic_vector(resize(signed(rd2),rd2_direct'length));
|
|
|
cmd_signed_o<=opcode(0);
|
cmd_signed_o<=opcode(0);
|
cmd_div_mod_o<=opcode(1);
|
cmd_div_mod_o<=opcode(1);
|
cmd_shift_right_o<=opcode(1);
|
cmd_shift_right_o<=opcode(1);
|
cmd_dbus_byte_o<=opcode(1);
|
cmd_dbus_byte_o<=opcode(1);
|
cmd_dbus_store_o<=opcode(2);
|
cmd_dbus_store_o<=opcode(2);
|
|
|
case state is
|
case state is
|
when Regular =>
|
when Regular =>
|
cmd_loadop3_o<='0';
|
cmd_loadop3_o<='0';
|
cmd_dbus_o<='0';
|
cmd_dbus_o<='0';
|
cmd_addsub_o<='0';
|
cmd_addsub_o<='0';
|
cmd_negate_op2_o<='0';
|
cmd_negate_op2_o<='0';
|
cmd_mul_o<='0';
|
cmd_mul_o<='0';
|
cmd_div_o<='0';
|
cmd_div_o<='0';
|
cmd_cmp_o<='0';
|
cmd_cmp_o<='0';
|
cmd_jump_o<='0';
|
cmd_jump_o<='0';
|
cmd_and_o<='0';
|
cmd_and_o<='0';
|
cmd_xor_o<='0';
|
cmd_xor_o<='0';
|
cmd_shift_o<='0';
|
cmd_shift_o<='0';
|
|
|
jump_type_o<=opcode(3 downto 0);
|
jump_type_o<=opcode(3 downto 0);
|
|
|
if interrupt_valid_i='1' and valid_i='1' then
|
if interrupt_valid_i='1' and valid_i='1' then
|
cmd_jump_o<='1';
|
cmd_jump_o<='1';
|
cmd_loadop3_o<='1';
|
cmd_loadop3_o<='1';
|
op3_o<=current_ip_i&"01"; -- LSB indicates interrupt return
|
op3_o<=current_ip_i&"01"; -- LSB indicates interrupt return
|
dst_out<=X"FD"; -- interrupt return pointer
|
dst_out<=X"FD"; -- interrupt return pointer
|
rd1_select<='1';
|
rd1_select<='1';
|
rd2_select<='0';
|
rd2_select<='0';
|
valid_out<='1';
|
valid_out<='1';
|
interrupt_ready<='1';
|
interrupt_ready<='1';
|
self_busy<='1';
|
self_busy<='1';
|
state<=ContinueInterrupt;
|
state<=ContinueInterrupt;
|
else
|
else
|
if opcode(5 downto 3)="101" or opcode="000001" then -- lc or lcs
|
if opcode(5 downto 3)="101" or opcode="000001" then -- lc or lcs
|
cmd_loadop3_o<='1';
|
cmd_loadop3_o<='1';
|
-- Setting op3_o here only affects the lcs instruction
|
-- Setting op3_o here only affects the lcs instruction
|
op3_o<=std_logic_vector(resize(signed(opcode(2 downto 0)&
|
op3_o<=std_logic_vector(resize(signed(opcode(2 downto 0)&
|
t1&t2&rd1&rd2),op3_o'length));
|
t1&t2&rd1&rd2),op3_o'length));
|
end if;
|
end if;
|
|
|
if opcode(5 downto 3)="001" then
|
if opcode(5 downto 3)="001" then
|
cmd_dbus_o<='1';
|
cmd_dbus_o<='1';
|
end if;
|
end if;
|
|
|
if opcode(5 downto 1)="01000" then
|
if opcode(5 downto 1)="01000" then
|
cmd_addsub_o<='1';
|
cmd_addsub_o<='1';
|
end if;
|
end if;
|
|
|
cmd_negate_op2_o<=opcode(0);
|
cmd_negate_op2_o<=opcode(0);
|
|
|
if opcode="010010" then
|
if opcode="010010" then
|
cmd_mul_o<='1';
|
cmd_mul_o<='1';
|
end if;
|
end if;
|
|
|
if opcode(5 downto 2)="0101" then
|
if opcode(5 downto 2)="0101" then
|
cmd_div_o<='1';
|
cmd_div_o<='1';
|
end if;
|
end if;
|
|
|
if opcode(5 downto 3)="100" then -- jump or call
|
if opcode(5 downto 3)="100" then -- jump or call
|
cmd_jump_o<='1';
|
cmd_jump_o<='1';
|
cmd_loadop3_o<=opcode(0);
|
cmd_loadop3_o<=opcode(0);
|
-- Setting op3_o here only affects the call instruction
|
-- Setting op3_o here only affects the call instruction
|
op3_o<=next_ip_i&"00";
|
op3_o<=next_ip_i&"00";
|
end if;
|
end if;
|
|
|
-- Note: (a or b) = (a and b) or (a xor b)
|
-- Note: (a or b) = (a and b) or (a xor b)
|
|
|
if opcode(5 downto 1)="01100" then
|
if opcode(5 downto 1)="01100" then
|
cmd_and_o<='1';
|
cmd_and_o<='1';
|
end if;
|
end if;
|
|
|
if opcode="011010" or opcode="011001" then
|
if opcode="011010" or opcode="011001" then
|
cmd_xor_o<='1';
|
cmd_xor_o<='1';
|
end if;
|
end if;
|
|
|
if opcode(5 downto 2)="0111" then
|
if opcode(5 downto 2)="0111" then
|
cmd_shift_o<='1';
|
cmd_shift_o<='1';
|
end if;
|
end if;
|
|
|
if opcode(5 downto 4)="11" then
|
if opcode(5 downto 4)="11" then
|
cmd_cmp_o<='1';
|
cmd_cmp_o<='1';
|
cmd_negate_op2_o<='1';
|
cmd_negate_op2_o<='1';
|
end if;
|
end if;
|
|
|
rd1_select<=t1;
|
rd1_select<=t1;
|
rd2_select<=t2;
|
rd2_select<=t2;
|
|
|
dst_out<=destination;
|
dst_out<=destination;
|
|
|
if valid_i='1' then
|
if valid_i='1' then
|
if opcode="000001" then
|
if opcode="000001" then
|
valid_out<='0';
|
valid_out<='0';
|
self_busy<='0';
|
self_busy<='0';
|
state<=ContinueLc;
|
state<=ContinueLc;
|
elsif opcode="000010" then
|
elsif opcode="000010" then
|
valid_out<='0';
|
valid_out<='0';
|
self_busy<='1';
|
self_busy<='1';
|
|
wakeup_reg<='0';
|
state<=Halt;
|
state<=Halt;
|
elsif opcode(5 downto 4)="11" then
|
elsif opcode(5 downto 4)="11" then
|
valid_out<='1';
|
valid_out<='1';
|
self_busy<='1';
|
self_busy<='1';
|
state<=ContinueCjmp;
|
state<=ContinueCjmp;
|
else
|
else
|
valid_out<='1';
|
valid_out<='1';
|
end if;
|
end if;
|
else
|
else
|
valid_out<='0';
|
valid_out<='0';
|
end if;
|
end if;
|
end if;
|
end if;
|
when ContinueLc =>
|
when ContinueLc =>
|
if valid_i='1' then
|
if valid_i='1' then
|
valid_out<='1';
|
valid_out<='1';
|
op3_o<=word_i;
|
op3_o<=word_i;
|
self_busy<='0';
|
self_busy<='0';
|
state<=Regular;
|
state<=Regular;
|
end if;
|
end if;
|
when ContinueCjmp =>
|
when ContinueCjmp =>
|
valid_out<='1';
|
valid_out<='1';
|
cmd_jump_o<='1';
|
cmd_jump_o<='1';
|
rd1_select<='1';
|
rd1_select<='1';
|
self_busy<='0';
|
self_busy<='0';
|
state<=Regular;
|
state<=Regular;
|
when ContinueInterrupt =>
|
when ContinueInterrupt =>
|
valid_out<='0';
|
valid_out<='0';
|
when Halt =>
|
when Halt =>
|
if interrupt_valid_i='1' then
|
if interrupt_valid_i='1' or wakeup_i='1' or wakeup_reg='1' then
|
self_busy<='0';
|
self_busy<='0';
|
state<=Regular;
|
state<=Regular;
|
end if;
|
end if;
|
end case;
|
end case;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
valid_o<=valid_out;
|
valid_o<=valid_out;
|
dst_o<=dst_out;
|
dst_o<=dst_out;
|
|
|
ready_o<=not busy;
|
ready_o<=not busy;
|
|
|
interrupt_ready_o<=interrupt_ready;
|
interrupt_ready_o<=interrupt_ready;
|
|
|
-- Decode RD (register/direct) operands
|
-- Decode RD (register/direct) operands
|
|
|
process (clk_i) is
|
process (clk_i) is
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
if busy='0' then
|
if busy='0' then
|
rd1_reg<=rd1;
|
rd1_reg<=rd1;
|
rd2_reg<=rd2;
|
rd2_reg<=rd2;
|
end if;
|
end if;
|
end if;
|
end if;
|
end process;
|
end process;
|
|
|
sp_raddr1_o<="11110"&interrupt_vector_i when (state=Regular and interrupt_valid_i='1' and downstream_busy='0') or state=ContinueInterrupt else
|
sp_raddr1_o<="11110"&interrupt_vector_i when (state=Regular and interrupt_valid_i='1' and downstream_busy='0') or state=ContinueInterrupt else
|
dst_out when (state=ContinueCjmp and downstream_busy='0') else
|
dst_out when (state=ContinueCjmp and downstream_busy='0') else
|
rd1_reg when busy='1' else
|
rd1_reg when busy='1' else
|
rd1;
|
rd1;
|
|
|
sp_raddr2_o<=rd2_reg when busy='1' else rd2;
|
sp_raddr2_o<=rd2_reg when busy='1' else rd2;
|
|
|
op1_o<=sp_rdata1_i when rd1_select='1' else rd1_direct;
|
op1_o<=sp_rdata1_i when rd1_select='1' else rd1_direct;
|
op2_o<=sp_rdata2_i when rd2_select='1' else rd2_direct;
|
op2_o<=sp_rdata2_i when rd2_select='1' else rd2_direct;
|
|
|
end architecture;
|
end architecture;
|
|
|