Files
vhdl/projects/dlx/src/dlx-behaviour.vhdl
T
jens bdb8fec295 - added
git-svn-id: http://moon:8086/svn/vhdl/trunk@1424 cc03376c-175c-47c8-b038-4cd826a8556b
2021-03-21 11:37:55 +00:00

615 lines
23 KiB
VHDL

--------------------------------------------------------------------------
--
-- Copyright (C) 1993, Peter J. Ashenden
-- Mail: Dept. Computer Science
-- University of Adelaide, SA 5005, Australia
-- e-mail: petera@cs.adelaide.edu.au
--
-- 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 1, 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, write to the Free Software
-- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
--
--------------------------------------------------------------------------
--
-- $RCSfile: dlx-behaviour.vhdl,v $ $Revision: 2.1 $ $Date: 1993/11/02 17:59:40 $
--
--------------------------------------------------------------------------
--
-- Behavioural architecture for DLX processor
--
use work.dlx_instr.all,
work.bv_arithmetic.all,
std.textio.all;
architecture behaviour of dlx is
begin -- behaviour
interpreter: process
type reg_array is array (reg_index) of dlx_word;
variable reg : reg_array;
variable fp_reg : reg_array;
variable PC : dlx_word;
variable user_mode : boolean;
variable overflow, div_by_zero : boolean;
constant PC_incr : dlx_word := X"0000_0004";
variable IR : dlx_word;
alias IR_opcode : dlx_opcode is IR(0 to 5);
alias IR_sp_func : dlx_sp_func is IR(26 to 31);
alias IR_fp_func : dlx_fp_func is IR(27 to 31);
alias IR_rs1 : dlx_reg_addr is IR(6 to 10);
alias IR_rs2 : dlx_reg_addr is IR(11 to 15);
alias IR_Itype_rd : dlx_reg_addr is IR(11 to 15);
alias IR_Rtype_rd : dlx_reg_addr is IR(16 to 20);
alias IR_immed16 : dlx_immed16 is IR(16 to 31);
alias IR_immed26 : dlx_immed26 is IR(6 to 31);
variable IR_opcode_num : dlx_opcode_num;
variable IR_sp_func_num : dlx_sp_func_num;
variable IR_fp_func_num : dlx_fp_func_num;
variable rs1, rs2, Itype_rd, Rtype_rd : reg_index;
variable mem_addr : dlx_address;
variable mem_data : dlx_word;
subtype ls_2_addr_bits is bit_vector(1 downto 0);
variable L : line;
procedure write (address : in dlx_address;
data_width : in mem_width;
data : in dlx_word;
signal phi1, phi2 : in bit; -- 2-phase non-overlapping clks
signal reset : in bit; -- synchronous reset input
signal a : out dlx_address; -- address bus output
signal d : inout dlx_word_bus; -- bidirectional data bus
signal width : out mem_width; -- byte/halfword/word
signal write_enable : out bit; -- selects read/write cycle
signal mem_enable : out bit; -- starts memory cycle
signal ifetch : out bit; -- indicates instruction fetch
signal ready : in bit; -- status from memory system
Tpd_clk_out : in time -- clock to output delay
) is
begin
wait until phi1 = '1';
if reset = '1' then
return;
end if;
a <= address after Tpd_clk_out;
width <= data_width after Tpd_clk_out;
d <= data after Tpd_clk_out;
write_enable <= '1' after Tpd_clk_out;
mem_enable <= '1' after Tpd_clk_out;
ifetch <= '0' after Tpd_clk_out;
loop
wait until phi2 = '0';
exit when ready = '1' or reset = '1';
end loop;
d <= null after Tpd_clk_out;
write_enable <= '0' after Tpd_clk_out;
mem_enable <= '0' after Tpd_clk_out;
end write;
procedure bus_read (address : in dlx_address;
data_width : in mem_width;
instr_fetch : in boolean;
data : out dlx_word;
signal phi1, phi2 : in bit; -- 2-phase non-overlapping clks
signal reset : in bit; -- synchronous reset input
signal a : out dlx_address; -- address bus output
signal d : inout dlx_word_bus; -- bidirectional data bus
signal width : out mem_width; -- byte/halfword/word
signal write_enable : out bit; -- selects read/write cycle
signal mem_enable : out bit; -- starts memory cycle
signal ifetch : out bit; -- indicates instruction eftch
signal ready : in bit; -- status from memory system
Tpd_clk_out : in time -- clock to output delay
) is
begin
wait until phi1 = '1';
if reset = '1' then
return;
end if;
a <= address after Tpd_clk_out;
width <= data_width after Tpd_clk_out;
mem_enable <= '1' after Tpd_clk_out;
ifetch <= bit'val(boolean'pos(instr_fetch)) after Tpd_clk_out;
loop
wait until phi2 = '0';
exit when ready = '1' or reset = '1';
end loop;
data := d;
mem_enable <= '0' after Tpd_clk_out;
end bus_read;
begin -- interpreter
--
-- reset the processor
--
d <= null;
halt <= '0';
write_enable <= '0';
mem_enable <= '0';
reg(0) := X"0000_0000";
PC := X"0000_0000";
user_mode := false;
--
-- fetch-decode-execute loop
--
loop
--
-- fetch next instruction
--
if debug then
write(L, tag);
write(L, string'(": fetching instruction..."));
writeline(output, L);
end if;
--
bus_read(PC, width_word, true, IR,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
--
-- increment the PC to point to the following instruction
--
if debug then
write(L, tag);
write(L, string'(": incrementing PC..."));
writeline(output, L);
end if;
--
bv_add(PC, PC_incr, PC, overflow);
--
-- decode the instruction
--
if debug then
write(L, tag);
write(L, string'(": decoding instruction..."));
writeline(output, L);
end if;
--
IR_opcode_num := bv_to_natural(IR_opcode);
IR_sp_func_num := bv_to_natural(IR_sp_func);
IR_fp_func_num := bv_to_natural(IR_fp_func);
rs1 := bv_to_natural(IR_rs1);
rs2 := bv_to_natural(IR_rs2);
Itype_rd := bv_to_natural(IR_Itype_rd);
Rtype_rd := bv_to_natural(IR_Rtype_rd);
--
-- exectute
--
if debug then
write(L, tag);
write(L, string'(": executing instruction..."));
writeline(output, L);
end if;
--
case IR_opcode is
when op_special =>
case IR_sp_func is
WHEN sp_func_nop =>
null;
when sp_func_sll =>
reg(Rtype_rd) := bv_sll(reg(rs1), bv_to_natural(reg(rs2)(27 to 31)));
when sp_func_srl =>
reg(Rtype_rd) := bv_srl(reg(rs1), bv_to_natural(reg(rs2)(27 to 31)));
when sp_func_sra =>
reg(Rtype_rd) := bv_sra(reg(rs1), bv_to_natural(reg(rs2)(27 to 31)));
when sp_func_sequ =>
if reg(rs1) = reg(rs2) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sneu =>
if reg(rs1) /= reg(rs2) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sltu =>
if reg(rs1) < reg(rs2) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sgtu =>
if reg(rs1) > reg(rs2) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sleu =>
if reg(rs1) <= reg(rs2) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sgeu =>
if reg(rs1) >= reg(rs2) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_add =>
bv_add(reg(rs1), reg(rs2), reg(Rtype_rd), overflow);
when sp_func_addu =>
bv_addu(reg(rs1), reg(rs2), reg(Rtype_rd), overflow);
when sp_func_sub =>
bv_sub(reg(rs1), reg(rs2), reg(Rtype_rd), overflow);
when sp_func_subu =>
bv_subu(reg(rs1), reg(rs2), reg(Rtype_rd), overflow);
when sp_func_and =>
reg(Rtype_rd) := reg(rs1) and reg(rs2);
when sp_func_or =>
reg(Rtype_rd) := reg(rs1) or reg(rs2);
when sp_func_xor =>
reg(Rtype_rd) := reg(rs1) xor reg(rs2);
when sp_func_seq =>
if reg(rs1) = reg(rs2) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sne =>
if reg(rs1) /= reg(rs2) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_slt =>
if bv_lt(reg(rs1), reg(rs2)) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sgt =>
if bv_gt(reg(rs1), reg(rs2)) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sle =>
if bv_le(reg(rs1), reg(rs2)) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_sge =>
if bv_ge(reg(rs1), reg(rs2)) then
reg(Rtype_rd) := X"0000_0001";
else
reg(Rtype_rd) := X"0000_0000";
end if;
when sp_func_movi2s =>
assert false
report "MOVI2S instruction not implemented" severity warning;
when sp_func_movs2i =>
assert false
report "MOVS2I instruction not implemented" severity warning;
when sp_func_movf =>
assert false
report "MOVF instruction not implemented" severity warning;
when sp_func_movd =>
assert false
report "MOVD instruction not implemented" severity warning;
when sp_func_movfp2i =>
reg(Rtype_rd) := fp_reg(rs1);
when sp_func_movi2fp =>
fp_reg(Rtype_rd) := reg(rs1);
when others =>
assert false
report "undefined special instruction function" severity error;
end case;
when op_fparith =>
case IR_fp_func is
when fp_func_mult =>
bv_mult(fp_reg(rs1), fp_reg(rs2), fp_reg(Rtype_rd), overflow);
when fp_func_multu =>
bv_multu(fp_reg(rs1), fp_reg(rs2), fp_reg(Rtype_rd), overflow);
when fp_func_div =>
bv_div(fp_reg(rs1), fp_reg(rs2), fp_reg(Rtype_rd), div_by_zero, overflow);
when fp_func_divu =>
bv_divu(fp_reg(rs1), fp_reg(rs2), fp_reg(Rtype_rd), div_by_zero);
when fp_func_addf | fp_func_subf | fp_func_multf | fp_func_divf |
fp_func_addd | fp_func_subd | fp_func_multd | fp_func_divd |
fp_func_cvtf2d | fp_func_cvtf2i | fp_func_cvtd2f |
fp_func_cvtd2i | fp_func_cvti2f | fp_func_cvti2d |
fp_func_eqf | fp_func_nef | fp_func_ltf | fp_func_gtf |
fp_func_lef | fp_func_gef | fp_func_eqd | fp_func_ned |
fp_func_ltd | fp_func_gtd | fp_func_led | fp_func_ged =>
assert false
report "floating point instructions not implemented" severity warning;
when others =>
assert false
report "undefined floating point instruction function" severity error;
end case;
when op_j =>
bv_add(PC, bv_sext(IR_immed26, 32), PC, overflow);
when op_jal =>
reg(link_reg) := PC;
bv_add(PC, bv_sext(IR_immed26, 32), PC, overflow);
when op_beqz =>
if reg(rs1) = X"0000_0000" then
bv_add(PC, bv_sext(IR_immed16, 32), PC, overflow);
end if;
when op_bnez =>
if reg(rs1) /= X"0000_0000" then
bv_add(PC, bv_sext(IR_immed16, 32), PC, overflow);
end if;
when op_bfpt =>
assert false
report "BFPT instruction not implemented" severity warning;
when op_bfpf =>
assert false
report "BFPF instruction not implemented" severity warning;
when op_addi =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), reg(Itype_rd), overflow);
when op_addui =>
bv_addu(reg(rs1), bv_zext(IR_immed16, 32), reg(Itype_rd), overflow);
when op_subi =>
bv_sub(reg(rs1), bv_sext(IR_immed16, 32), reg(Itype_rd), overflow);
when op_subui =>
bv_subu(reg(rs1), bv_zext(IR_immed16, 32), reg(Itype_rd), overflow);
when op_slli =>
reg(Itype_rd) := bv_sll(reg(rs1), bv_to_natural(IR_immed16(11 to 15)));
when op_srli =>
reg(Itype_rd) := bv_srl(reg(rs1), bv_to_natural(IR_immed16(11 to 15)));
when op_srai =>
reg(Itype_rd) := bv_sra(reg(rs1), bv_to_natural(IR_immed16(11 to 15)));
when op_andi =>
reg(Itype_rd) := reg(rs1) and bv_zext(IR_immed16, 32);
when op_ori =>
reg(Itype_rd) := reg(rs1) or bv_zext(IR_immed16, 32);
when op_xori =>
reg(Itype_rd) := reg(rs1) xor bv_zext(IR_immed16, 32);
when op_lhi =>
reg(Itype_rd) := IR_immed16 & X"0000";
when op_rfe =>
assert false
report "RFE instruction not implemented" severity warning;
when op_trap =>
assert false
report "TRAP instruction encountered, execution halted"
severity note;
halt <= '1' after Tpd_clk_out;
wait until reset = '1';
exit;
when op_jr =>
PC := reg(rs1);
when op_jalr =>
reg(link_reg) := PC;
PC := reg(rs1);
when op_seqi =>
if reg(rs1) = bv_sext(IR_immed16, 32) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_snei =>
if reg(rs1) /= bv_sext(IR_immed16, 32) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_slti =>
if bv_lt(reg(rs1), bv_sext(IR_immed16, 32)) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_sgti =>
if bv_gt(reg(rs1), bv_sext(IR_immed16, 32)) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_slei =>
if bv_le(reg(rs1), bv_sext(IR_immed16, 32)) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_sgei =>
if bv_ge(reg(rs1), bv_sext(IR_immed16, 32)) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_lb =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), mem_addr, overflow);
bus_read(mem_addr, width_byte, false, mem_data,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
case ls_2_addr_bits'(mem_addr(1 downto 0)) is
when B"00" =>
reg(Itype_rd) := bv_sext(mem_data(0 to 7), 32);
when B"01" =>
reg(Itype_rd) := bv_sext(mem_data(8 to 15), 32);
when B"10" =>
reg(Itype_rd) := bv_sext(mem_data(16 to 23), 32);
when B"11" =>
reg(Itype_rd) := bv_sext(mem_data(24 to 31), 32);
end case;
when op_lh =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), mem_addr, overflow);
bus_read(mem_addr, width_halfword, false, mem_data,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
if mem_addr(1) = '0' then
reg(Itype_rd) := bv_sext(mem_data(0 to 15), 32);
else
reg(Itype_rd) := bv_sext(mem_data(16 to 31), 32);
end if;
when op_lw =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), mem_addr, overflow);
bus_read(mem_addr, width_word, false, mem_data,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
reg(Itype_rd) := mem_data;
when op_lbu =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), mem_addr, overflow);
bus_read(mem_addr, width_byte, false, mem_data,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
case ls_2_addr_bits'(mem_addr(1 downto 0)) is
when B"00" =>
reg(Itype_rd) := bv_zext(mem_data(0 to 7), 32);
when B"01" =>
reg(Itype_rd) := bv_zext(mem_data(8 to 15), 32);
when B"10" =>
reg(Itype_rd) := bv_zext(mem_data(16 to 23), 32);
when B"11" =>
reg(Itype_rd) := bv_zext(mem_data(24 to 31), 32);
end case;
when op_lhu =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), mem_addr, overflow);
bus_read(mem_addr, width_halfword, false, mem_data,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
if mem_addr(1) = '0' then
reg(Itype_rd) := bv_zext(mem_data(0 to 15), 32);
else
reg(Itype_rd) := bv_zext(mem_data(16 to 31), 32);
end if;
when op_lf =>
assert false
report "LF instruction not implemented" severity warning;
when op_ld =>
assert false
report "LD instruction not implemented" severity warning;
when op_sb =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), mem_addr, overflow);
mem_data := X"0000_0000";
case ls_2_addr_bits'(mem_addr(1 downto 0)) is
when B"00" =>
mem_data(0 to 7) := reg(Itype_rd)(0 to 7);
when B"01" =>
mem_data(8 to 15) := reg(Itype_rd)(0 to 7);
when B"10" =>
mem_data(16 to 23) := reg(Itype_rd)(0 to 7);
when B"11" =>
mem_data(24 to 31) := reg(Itype_rd)(0 to 7);
end case;
write(mem_addr, width_halfword, mem_data,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
when op_sh =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), mem_addr, overflow);
mem_data := X"0000_0000";
if mem_addr(1) = '0' then
mem_data(0 to 15) := reg(Itype_rd)(0 to 15);
else
mem_data(16 to 31) := reg(Itype_rd)(0 to 15);
end if;
write(mem_addr, width_halfword, mem_data,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
when op_sw =>
bv_add(reg(rs1), bv_sext(IR_immed16, 32), mem_addr, overflow);
mem_data := reg(Itype_rd);
write(mem_addr, width_word, mem_data,
phi1, phi2, reset, a, d, width, write_enable, mem_enable, ifetch, ready,
Tpd_clk_out);
exit when reset = '1';
when op_sf =>
assert false
report "SF instruction not implemented" severity warning;
when op_sd =>
assert false
report "SD instruction not implemented" severity warning;
when op_sequi =>
if reg(rs1) = bv_zext(IR_immed16, 32) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_sneui =>
if reg(rs1) /= bv_zext(IR_immed16, 32) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_sltui =>
if reg(rs1) < bv_zext(IR_immed16, 32) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_sgtui =>
if reg(rs1) > bv_zext(IR_immed16, 32) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_sleui =>
if reg(rs1) <= bv_zext(IR_immed16, 32) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when op_sgeui =>
if reg(rs1) >= bv_zext(IR_immed16, 32) then
reg(Itype_rd) := X"0000_0001";
else
reg(Itype_rd) := X"0000_0000";
end if;
when others =>
assert false
report "undefined instruction" severity error;
end case;
--
-- fix up R0 in case it was overwritten
--
reg(0) := X"0000_0000";
--
if debug then
write(L, tag);
write(L, string'(": end of execution"));
writeline(output, L);
end if;
--
end loop;
--
-- loop is only exited when reset active: wait until it goes inactive
--
assert reset = '1'
report "reset code reached with reset = '0'" severity error;
wait until phi2 = '0' and reset = '0';
--
-- process interpreter now starts again from beginning
--
end process interpreter;
end behaviour;