diff options
Diffstat (limited to 'testsuite/vests/vhdl-93/ashenden/compliant/ch_15_dlx-b.vhd')
-rw-r--r-- | testsuite/vests/vhdl-93/ashenden/compliant/ch_15_dlx-b.vhd | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/testsuite/vests/vhdl-93/ashenden/compliant/ch_15_dlx-b.vhd b/testsuite/vests/vhdl-93/ashenden/compliant/ch_15_dlx-b.vhd new file mode 100644 index 000000000..c1bcb5bda --- /dev/null +++ b/testsuite/vests/vhdl-93/ashenden/compliant/ch_15_dlx-b.vhd @@ -0,0 +1,476 @@ + +-- Copyright (C) 1996 Morgan Kaufmann Publishers, Inc + +-- This file is part of VESTs (Vhdl tESTs). + +-- VESTs 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 2 of the License, or (at +-- your option) any later version. + +-- VESTs 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 VESTs; if not, write to the Free Software Foundation, +-- Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +-- --------------------------------------------------------------------- +-- +-- $Id: ch_15_dlx-b.vhd,v 1.4 2001-11-03 23:19:37 paw Exp $ +-- $Revision: 1.4 $ +-- +-- --------------------------------------------------------------------- + +library bv_utilities; +use bv_utilities.bv_arithmetic.all; + +library work; +use work.dlx_instr.all; + +architecture behavior of dlx is +begin + + interpreter : process + is + + type reg_array is array (reg_index) of dlx_bv_word; + variable reg : reg_array; + variable fp_reg : reg_array; + + variable PC : dlx_bv_word; + constant PC_incr : dlx_bv_word := X"0000_0004"; + + variable IR : dlx_bv_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 disassembled_instr : string(1 to 40); + variable disassembled_instr_len : positive; + + variable rs1, rs2, Itype_rd, Rtype_rd : reg_index; + + variable mem_addr_reg : dlx_bv_address; + variable mem_data_reg : dlx_bv_word; + + variable overflow : boolean; + + -- lookup table for result of set instructions + type set_result_table is array (boolean) of dlx_bv_word; + constant set_if : set_result_table := ( false => X"0000_0000", + true => X"0000_0001" ); + variable instr_count : natural; + + + -- local procedures for use within the interpreter + + + procedure bus_read ( address : in dlx_bv_address; + data_width : in dlx_mem_width; + instr_fetch : in std_logic; + data : out dlx_bv_word ) is + + begin + wait until rising_edge(phi1); + if To_bit(reset) = '1' then + return; + end if; + a <= To_X01(address) after Tpd_clk_out; + width <= data_width after Tpd_clk_out; + ifetch <= instr_fetch after Tpd_clk_out; + mem_enable <= '1' after Tpd_clk_out; + loop + wait until falling_edge(phi2); + if To_bit(reset) = '1' then + return; + end if; + exit when To_bit(ready) = '1'; + end loop; + assert not Is_X(d) report "Bus read data contains unknown bits"; + data := To_bitvector(d); + mem_enable <= '0' after Tpd_clk_out; + end procedure bus_read; + + + procedure bus_write ( address : in dlx_bv_address; + data_width : in dlx_mem_width; + data : in dlx_bv_word ) is + + begin + wait until rising_edge(phi1); + if To_bit(reset) = '1' then + return; + end if; + a <= To_X01(address) after Tpd_clk_out; + ifetch <= '0' after Tpd_clk_out; + width <= data_width after Tpd_clk_out; + d <= To_X01Z(data) after Tpd_clk_out; + write_enable <= '1' after Tpd_clk_out; + mem_enable <= '1' after Tpd_clk_out; + loop + wait until falling_edge(phi2); + if To_bit(reset) = '1' then + return; + end if; + exit when To_bit(ready) = '1'; + end loop; + d <= disabled_dlx_word after Tpd_clk_out; + write_enable <= '0' after Tpd_clk_out; + mem_enable <= '0' after Tpd_clk_out; + end procedure bus_write; + + + procedure execute_op_special is + begin + case IR_sp_func is + when sp_func_nop => + null; + 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_sll => + reg(Rtype_rd) := reg(rs1) sll bv_to_natural(reg(rs2)(27 to 31)); + when sp_func_srl => + reg(Rtype_rd) := reg(rs1) srl bv_to_natural(reg(rs2)(27 to 31)); + when sp_func_sra => + reg(Rtype_rd) := reg(rs1) sra bv_to_natural(reg(rs2)(27 to 31)); + 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_sequ => + reg(Rtype_rd) := set_if( reg(rs1) = reg(rs2) ); + when sp_func_sneu => + reg(Rtype_rd) := set_if( reg(rs1) /= reg(rs2) ); + when sp_func_sltu => + reg(Rtype_rd) := set_if( reg(rs1) < reg(rs2) ); + when sp_func_sgtu => + reg(Rtype_rd) := set_if( reg(rs1) > reg(rs2) ); + when sp_func_sleu => + reg(Rtype_rd) := set_if( reg(rs1) <= reg(rs2) ); + when sp_func_sgeu => + reg(Rtype_rd) := set_if( reg(rs1) >= reg(rs2) ); + when sp_func_seq => + reg(Rtype_rd) := set_if( reg(rs1) = reg(rs2) ); + when sp_func_sne => + reg(Rtype_rd) := set_if( reg(rs1) /= reg(rs2) ); + when sp_func_slt => + reg(Rtype_rd) := set_if( bv_lt(reg(rs1), reg(rs2)) ); + when sp_func_sgt => + reg(Rtype_rd) := set_if( bv_gt(reg(rs1), reg(rs2)) ); + when sp_func_sle => + reg(Rtype_rd) := set_if( bv_le(reg(rs1), reg(rs2)) ); + when sp_func_sge => + reg(Rtype_rd) := set_if( bv_ge(reg(rs1), reg(rs2)) ); + when sp_func_movi2s | sp_func_movs2i + | sp_func_movf | sp_func_movd + | sp_func_movfp2i | sp_func_movi2fp => + report sp_func_names(bv_to_natural(IR_sp_func)) + & " instruction not implemented" severity warning; + when others => + report "undefined special instruction function" severity error; + end case; + end procedure execute_op_special; + + + procedure execute_op_fparith is + begin + case IR_fp_func is + when fp_func_mult | fp_func_multu | fp_func_div | fp_func_divu + | 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 => + report fp_func_names(bv_to_natural(IR_fp_func)) + & " instruction not implemented" severity warning; + when others => + report "undefined floating point instruction function" severity error; + end case; + end procedure execute_op_fparith; + + + procedure execute_load ( data_width : dlx_mem_width; unsigned : boolean ) is + + variable temp : dlx_bv_word; + + -- type for least-significant two bits of address + subtype ls_2_addr_bits is bit_vector(1 downto 0); + + begin + mem_addr_reg := reg(rs1) + bv_sext(IR_immed16, 32); + bus_read(mem_addr_reg, data_width, '0', mem_data_reg); + if To_bit(reset) = '1' then + return; + end if; + case data_width is + when dlx_mem_width_byte => + case ls_2_addr_bits'(mem_addr_reg(1 downto 0)) is + when B"00" => + temp(0 to 7) := mem_data_reg(0 to 7); + when B"01" => + temp(0 to 7) := mem_data_reg(8 to 15); + when B"10" => + temp(0 to 7) := mem_data_reg(16 to 23); + when B"11" => + temp(0 to 7) := mem_data_reg(24 to 31); + end case; + if unsigned then + reg(Itype_rd) := bv_zext(temp(0 to 7), 32); + else + reg(Itype_rd) := bv_sext(temp(0 to 7), 32); + end if; + when dlx_mem_width_halfword => + if mem_addr_reg(1) = '0' then + temp(0 to 15) := mem_data_reg(0 to 15); + else + temp(0 to 15) := mem_data_reg(16 to 31); + end if; + if unsigned then + reg(Itype_rd) := bv_zext(temp(0 to 15), 32); + else + reg(Itype_rd) := bv_sext(temp(0 to 15), 32); + end if; + when dlx_mem_width_word => + reg(Itype_rd) := mem_data_reg; + when others => + null; + end case; + end procedure execute_load; + + + procedure execute_store ( data_width : dlx_mem_width ) is + + variable temp : dlx_bv_word; + + -- type for least-significant two bits of address + subtype ls_2_addr_bits is bit_vector(1 downto 0); + + begin + mem_addr_reg := reg(rs1) + bv_sext(IR_immed16, 32); + mem_data_reg := X"0000_0000"; + case data_width is + when dlx_mem_width_byte => + case ls_2_addr_bits'(mem_addr_reg(1 downto 0)) is + when B"00" => + mem_data_reg(0 to 7) := reg(Itype_rd)(0 to 7); + when B"01" => + mem_data_reg(8 to 15) := reg(Itype_rd)(0 to 7); + when B"10" => + mem_data_reg(16 to 23) := reg(Itype_rd)(0 to 7); + when B"11" => + mem_data_reg(24 to 31) := reg(Itype_rd)(0 to 7); + end case; + when dlx_mem_width_halfword => + if mem_addr_reg(1) = '0' then + mem_data_reg(0 to 15) := reg(Itype_rd)(0 to 15); + else + mem_data_reg(16 to 31) := reg(Itype_rd)(0 to 15); + end if; + when dlx_mem_width_word => + mem_data_reg := reg(Itype_rd); + when others => + null; + end case; + bus_write(mem_addr_reg, data_width, mem_data_reg); + end procedure execute_store; + + + begin -- interpreter + + -- reset the processor + d <= disabled_dlx_word; + halt <= '0'; + write_enable <= '0'; + mem_enable <= '0'; + reg(0) := X"0000_0000"; + PC := X"0000_0000"; + instr_count := 0; + wait on phi2 until falling_edge(phi2) and To_bit(reset) = '0'; + + -- fetch-decode-execute loop + while To_bit(reset) /= '1' loop + -- fetch next instruction + instr_count := instr_count + 1; + if debug = msg_every_100_instructions and instr_count mod 100 = 0 then + report "instruction count = " & natural'image(instr_count); + end if; + + if debug >= msg_each_instruction then + report "fetching instruction"; + end if; + + bus_read( address => PC, data_width => dlx_mem_width_word, + instr_fetch => '1', data => IR ); + exit when To_bit(reset) = '1'; + + if debug >= trace_each_instruction then + disassemble(IR, disassembled_instr, disassembled_instr_len); + report disassembled_instr(1 to disassembled_instr_len); + end if; + + wait until rising_edge(phi1); + + -- increment the PC to point to the following instruction + if debug = trace_each_step then + report "incrementing PC"; + end if; + + PC := bv_addu(PC, PC_incr); + + -- decode the instruction + if debug = trace_each_step then + report "decoding instruction"; + end if; + + 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); + + -- execute the instruction + if debug = trace_each_step then + report "executing instruction"; + end if; + + overflow := false; + + case IR_opcode is + when op_special => + execute_op_special; + when op_fparith => + execute_op_fparith; + when op_j => + PC := PC + bv_sext(IR_immed26, 32); + when op_jal => + reg(link_reg) := PC; + PC := PC + bv_sext(IR_immed26, 32); + when op_jr => + PC := reg(rs1); + when op_jalr => + reg(link_reg) := PC; + PC := reg(rs1); + when op_beqz => + if reg(rs1) = X"0000_0000" then + PC := PC + bv_sext(IR_immed16, 32); + end if; + when op_bnez => + if reg(rs1) /= X"0000_0000" then + PC := PC + bv_sext(IR_immed16, 32); + end if; + 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) := reg(rs1) sll bv_to_natural(IR_immed16(11 to 15)); + when op_srli => + reg(Itype_rd) := reg(rs1) srl bv_to_natural(IR_immed16(11 to 15)); + when op_srai => + reg(Itype_rd) := reg(rs1) sra 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_sequi => + reg(Itype_rd) := set_if( reg(rs1) = bv_zext(IR_immed16, 32) ); + when op_sneui => + reg(Itype_rd) := set_if( reg(rs1) /= bv_zext(IR_immed16, 32) ); + when op_sltui => + reg(Itype_rd) := set_if( reg(rs1) < bv_zext(IR_immed16, 32) ); + when op_sgtui => + reg(Itype_rd) := set_if( reg(rs1) > bv_zext(IR_immed16, 32) ); + when op_sleui => + reg(Itype_rd) := set_if( reg(rs1) <= bv_zext(IR_immed16, 32) ); + when op_sgeui => + reg(Itype_rd) := set_if( reg(rs1) >= bv_zext(IR_immed16, 32) ); + when op_seqi => + reg(Itype_rd) := set_if( reg(rs1) = bv_sext(IR_immed16, 32) ); + when op_snei => + reg(Itype_rd) := set_if( reg(rs1) /= bv_sext(IR_immed16, 32) ); + when op_slti => + reg(Itype_rd) := set_if( bv_lt(reg(rs1), bv_sext(IR_immed16, 32)) ); + when op_sgti => + reg(Itype_rd) := set_if( bv_gt(reg(rs1), bv_sext(IR_immed16, 32)) ); + when op_slei => + reg(Itype_rd) := set_if( bv_le(reg(rs1), bv_sext(IR_immed16, 32)) ); + when op_sgei => + reg(Itype_rd) := set_if( bv_ge(reg(rs1), bv_sext(IR_immed16, 32)) ); + when op_trap => + report "TRAP instruction encountered, execution halted" severity note; + halt <= '1' after Tpd_clk_out; + wait until To_bit(reset) = '1'; + exit; + when op_lb => + execute_load(data_width => dlx_mem_width_byte, unsigned => false); + exit when To_bit(reset) = '1'; + when op_lh => + execute_load(data_width => dlx_mem_width_halfword, unsigned => false); + exit when To_bit(reset) = '1'; + when op_lw => + execute_load(data_width => dlx_mem_width_word, unsigned => false); + exit when To_bit(reset) = '1'; + when op_lbu => + execute_load(data_width => dlx_mem_width_byte, unsigned => true); + exit when To_bit(reset) = '1'; + when op_lhu => + execute_load(data_width => dlx_mem_width_halfword, unsigned => true); + exit when To_bit(reset) = '1'; + when op_sb => + execute_store ( data_width => dlx_mem_width_byte ); + exit when To_bit(reset) = '1'; + when op_sh => + execute_store ( data_width => dlx_mem_width_halfword ); + exit when To_bit(reset) = '1'; + when op_sw => + execute_store ( data_width => dlx_mem_width_word ); + exit when To_bit(reset) = '1'; + when op_rfe | op_bfpt | op_bfpf | op_lf | op_ld | op_sf | op_sd => + report opcode_names(bv_to_natural(IR_opcode)) + & " instruction not implemented" severity warning; + when others => + report "undefined instruction" severity error; + end case; + + -- fix up R0 in case it was overwritten + reg(0) := X"0000_0000"; + + -- overflow and divide-by-zero exception handing + -- (not implemented) + + if debug = trace_each_step then + report "end of execution"; + end if; + + end loop; + -- loop is only exited when reset active: + -- process interpreter starts again from beginning + end process interpreter; + +end architecture behavior; |