Line 3... |
Line 3... |
--
|
--
|
-- Simulates the MCU core connected to a simulated external static RAM on a
|
-- Simulates the MCU core connected to a simulated external static RAM on a
|
-- 16-bit bus, plus an optional 8-bit static ROM. This setup is more or less
|
-- 16-bit bus, plus an optional 8-bit static ROM. This setup is more or less
|
-- that of develoment board DE-1 from Terasic.
|
-- that of develoment board DE-1 from Terasic.
|
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
|
-- Simulated I/O
|
|
-- Apart from the io devices within the SoC module, this test bench simulates
|
|
-- the following ports:
|
|
--
|
|
-- 20010000: HW IRQ 0 countdown register (R/o).
|
|
-- 20010004: HW IRQ 1 countdown register (R/o).
|
|
-- 20010008: HW IRQ 2 countdown register (R/o).
|
|
-- 2001000c: HW IRQ 3 countdown register (R/o).
|
|
-- 20010010: HW IRQ 4 countdown register (R/o).
|
|
-- 20010014: HW IRQ 5 countdown register (R/o).
|
|
-- 20010018: HW IRQ 6 countdown register (R/o).
|
|
-- 2001001c: HW IRQ 7 countdown register (R/o).
|
|
-- 20010020: Debug register 0 (R/W).
|
|
-- 20010024: Debug register 1 (R/W).
|
|
-- 20010028: Debug register 2 (R/W).
|
|
-- 2001002c: Debug register 3 (R/W).
|
|
--
|
|
-- NOTE: these addresses are for write accesses only. for read accesses, the
|
|
-- debug registers 0..3 are mirrored over all the io address range 2001xxxxh.
|
|
--
|
|
-- Writing N to an IRQ X countdown register will trigger hardware interrupt X
|
|
-- N clock cycles later. The interrupt line will be asserted for 1 clock cycle.
|
|
--
|
|
-- The debug registers 0 to 3 can only be used to test 32-bit i/o.
|
|
-- All of these registers can only be addressed as 32-bit words. Any other type
|
|
-- of access will yield undefined results.
|
|
--------------------------------------------------------------------------------
|
-- Console logging:
|
-- Console logging:
|
--
|
--
|
-- Console output (at addresses compatible to Plasma's) is logged to text file
|
-- Console output (at addresses compatible to Plasma's) is logged to text file
|
-- "hw_sim_console_log.txt".
|
-- "hw_sim_console_log.txt".
|
--
|
--
|
Line 25... |
Line 52... |
use ieee.std_logic_1164.all;
|
use ieee.std_logic_1164.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_arith.all;
|
use ieee.std_logic_unsigned.all;
|
use ieee.std_logic_unsigned.all;
|
use std.textio.all;
|
use std.textio.all;
|
|
|
|
use work.txt_util.all;
|
use work.mips_pkg.all;
|
use work.mips_pkg.all;
|
use work.mips_tb_pkg.all;
|
use work.mips_tb_pkg.all;
|
use work.sim_params_pkg.all;
|
use work.sim_params_pkg.all;
|
use work.txt_util.all;
|
|
|
|
entity mips_tb is
|
entity mips_tb is
|
end;
|
end;
|
|
|
|
|
architecture testbench of mips_tb is
|
architecture testbench of mips_tb is
|
|
|
-- NOTE: simulation parameters are defined in sim_params_pkg
|
-- External 16-bit SRAM and interface signals ----------------------------------
|
|
|
|
|
-- External SRAM and interface signals -----------------------------------------
|
-- External SRAM address length -- these are 16-bit word addresses.
|
|
constant SRAM_ADDR_SIZE : integer := log2(SRAM_SIZE);
|
|
|
-- Static 16-bit wide RAM modelled as two separate byte-wide arrays foer easy
|
-- Static 16-bit wide RAM.
|
-- simulation of byte enables.
|
|
-- Using shared variables for big memory arrays speeds up simulation a lot;
|
-- Using shared variables for big memory arrays speeds up simulation a lot;
|
-- see Modelsim 6.3 User Manual, section on 'Modelling Memory'.
|
-- see Modelsim 6.3 User Manual, section on 'Modelling Memory'.
|
-- WARNING: I have only tested this construct with Modelsim SE 6.3.
|
-- WARNING: I have only tested this construct with Modelsim SE 6.3.
|
shared variable sram1 : t_sram := ( others => X"00");
|
shared variable sram : t_hword_table(0 to SRAM_SIZE-1) := objcode_to_htable(SRAM_INIT, SRAM_SIZE);
|
shared variable sram0 : t_sram := ( others => X"00");
|
|
|
|
signal sram_chip_addr : std_logic_vector(SRAM_ADDR_SIZE downto 1);
|
signal sram_chip_addr : std_logic_vector(SRAM_ADDR_SIZE downto 1);
|
signal sram_output : std_logic_vector(15 downto 0);
|
signal sram_output : t_halfword;
|
|
|
|
|
-- PROM table and interface signals --------------------------------------------
|
-- PROM table and interface signals --------------------------------------------
|
|
|
|
constant PROM_ADDR_SIZE : integer := log2(PROM_SIZE);
|
|
subtype t_prom_address is std_logic_vector(PROM_ADDR_SIZE-1 downto 0);
|
|
|
-- We'll simulate a 16-bit-wide static PROM (e.g. a Flash) with some serious
|
-- We'll simulate a 16-bit-wide static PROM (e.g. a Flash) with some serious
|
-- cycle time (70 or 90 ns).
|
-- cycle time (70 or 90 ns).
|
-- FIXME FLASH read cycle time not modelled yet.
|
-- FIXME FLASH read cycle time not modelled yet.
|
signal prom_rd_addr : t_prom_address;
|
signal prom_rd_addr : t_prom_address;
|
signal prom_output : std_logic_vector(7 downto 0);
|
signal prom_output : t_byte;
|
signal prom_oe_n : std_logic;
|
signal prom_oe_n : std_logic;
|
|
|
-- 8-bit wide FLASH modelled as read only block.
|
-- 8-bit wide FLASH modelled as read only block.
|
-- We don't simulate the actual FLASH chip: no FLASH writes, control regs, etc.
|
-- We don't simulate the actual FLASH chip: no FLASH writes, control regs, etc.
|
shared variable prom : t_prom := ( PROM_DATA );
|
shared variable prom : t_byte_table(0 to PROM_SIZE-1) := objcode_to_btable(PROM_INIT, PROM_SIZE);
|
|
|
|
|
-- I/O devices -----------------------------------------------------------------
|
-- I/O devices -----------------------------------------------------------------
|
|
|
signal data_uart : std_logic_vector(31 downto 0);
|
signal data_uart : std_logic_vector(31 downto 0);
|
Line 82... |
Line 112... |
signal reset : std_logic := '1';
|
signal reset : std_logic := '1';
|
signal interrupt : std_logic := '0';
|
signal interrupt : std_logic := '0';
|
signal done : std_logic := '0';
|
signal done : std_logic := '0';
|
|
|
-- interface to asynchronous 16-bit-wide external SRAM
|
-- interface to asynchronous 16-bit-wide external SRAM
|
signal mpu_sram_address : t_word;
|
signal mpu_sram_address : std_logic_vector(31 downto 0);
|
signal mpu_sram_data_rd : std_logic_vector(15 downto 0);
|
signal mpu_sram_data_rd : t_halfword;
|
signal mpu_sram_data_wr : std_logic_vector(15 downto 0);
|
signal mpu_sram_data_wr : t_halfword;
|
signal mpu_sram_byte_we_n : std_logic_vector(1 downto 0);
|
signal mpu_sram_byte_we_n : std_logic_vector(1 downto 0);
|
signal mpu_sram_oe_n : std_logic;
|
signal mpu_sram_oe_n : std_logic;
|
|
|
-- interface to i/o
|
-- interface to i/o
|
signal io_rd_data : std_logic_vector(31 downto 0);
|
signal io_rd_data : std_logic_vector(31 downto 0);
|
Line 134... |
Line 164... |
|
|
|
|
begin
|
begin
|
|
|
-- UUT instantiation -------------------------------------------------------
|
-- UUT instantiation -------------------------------------------------------
|
mpu: entity work.mips_mpu
|
mpu: entity work.mips_soc
|
generic map (
|
generic map (
|
|
BOOT_BRAM_SIZE => bram_size,
|
|
OBJ_CODE => obj_code,
|
CLOCK_FREQ => 50000000,
|
CLOCK_FREQ => 50000000,
|
SRAM_ADDR_SIZE => 32
|
SRAM_ADDR_SIZE => 32
|
)
|
)
|
port map (
|
port map (
|
interrupt => cpu_irq,
|
interrupt => cpu_irq,
|
Line 213... |
Line 245... |
|
|
sram_chip_addr <= mpu_sram_address(SRAM_ADDR_SIZE downto 1);
|
sram_chip_addr <= mpu_sram_address(SRAM_ADDR_SIZE downto 1);
|
|
|
-- FIXME should add some verification of /WE
|
-- FIXME should add some verification of /WE
|
sram_output <=
|
sram_output <=
|
sram1(conv_integer(unsigned(sram_chip_addr))) &
|
sram(conv_integer(unsigned(sram_chip_addr))) when mpu_sram_oe_n='0'
|
sram0(conv_integer(unsigned(sram_chip_addr))) when mpu_sram_oe_n='0'
|
|
else (others => 'Z');
|
else (others => 'Z');
|
|
|
simulated_sram_write:
|
simulated_sram_write:
|
process(mpu_sram_byte_we_n, mpu_sram_address, mpu_sram_oe_n)
|
process(mpu_sram_byte_we_n, mpu_sram_address, mpu_sram_oe_n)
|
begin
|
begin
|
-- Write cycle
|
-- Write cycle
|
-- FIXME should add OE\ to write control logic
|
-- FIXME should add OE\ to write control logic
|
if mpu_sram_byte_we_n'event or mpu_sram_address'event then
|
if mpu_sram_byte_we_n'event or mpu_sram_address'event then
|
if mpu_sram_byte_we_n(1)='0' then
|
if mpu_sram_byte_we_n(1)='0' then
|
sram1(conv_integer(unsigned(sram_chip_addr))) := mpu_sram_data_wr(15 downto 8);
|
sram(conv_integer(unsigned(sram_chip_addr)))(15 downto 8) := mpu_sram_data_wr(15 downto 8);
|
end if;
|
end if;
|
if mpu_sram_byte_we_n(0)='0' then
|
if mpu_sram_byte_we_n(0)='0' then
|
sram0(conv_integer(unsigned(sram_chip_addr))) := mpu_sram_data_wr( 7 downto 0);
|
sram(conv_integer(unsigned(sram_chip_addr)))( 7 downto 0) := mpu_sram_data_wr( 7 downto 0);
|
end if;
|
end if;
|
end if;
|
end if;
|
end process simulated_sram_write;
|
end process simulated_sram_write;
|
|
|
|
|
-- Do a very basic simulation of an external PROM (FLASH) ------------------
|
-- Do a very basic simulation of an external PROM (FLASH) ------------------
|
-- (wired to the same bus as the sram and both are static).
|
-- (wired to the same bus as the sram and both are static).
|
|
|
prom_rd_addr <= mpu_sram_address(PROM_ADDR_SIZE+1 downto 2);
|
prom_rd_addr <= mpu_sram_address(PROM_ADDR_SIZE-1 downto 0);
|
|
|
prom_oe_n <= mpu_sram_oe_n;
|
prom_oe_n <= mpu_sram_oe_n;
|
|
|
|
simulated_flash:
|
|
if PROM_SIZE > 0 generate
|
prom_output <=
|
prom_output <=
|
prom(conv_integer(unsigned(prom_rd_addr)))(31 downto 24) when prom_oe_n='0' and mpu_sram_address(1 downto 0)="00" else
|
prom(conv_integer(unsigned(prom_rd_addr))) when prom_oe_n='0' else
|
prom(conv_integer(unsigned(prom_rd_addr)))(23 downto 16) when prom_oe_n='0' and mpu_sram_address(1 downto 0)="01" else
|
|
prom(conv_integer(unsigned(prom_rd_addr)))(15 downto 8) when prom_oe_n='0' and mpu_sram_address(1 downto 0)="10" else
|
|
prom(conv_integer(unsigned(prom_rd_addr)))( 7 downto 0) when prom_oe_n='0' and mpu_sram_address(1 downto 0)="11" else
|
|
(others => 'Z');
|
(others => 'Z');
|
|
end generate;
|
|
|
|
unused_flash:
|
|
if PROM_SIZE <= 0 generate
|
|
prom_output <= (others => 'Z');
|
|
end generate;
|
|
|
-- Simulate dummy I/O traffic external to the MCU --------------------------
|
-- Simulate dummy I/O traffic external to the MCU --------------------------
|
-- the only IO present is the test interrupt trigger registers
|
-- The only IO present is the test interrupt trigger registers and the
|
|
-- debug register block.
|
simulated_io:
|
simulated_io:
|
process(clk)
|
process(clk)
|
variable i : integer;
|
variable i : integer;
|
variable uart_data : integer;
|
variable uart_data : integer;
|
begin
|
begin
|
if clk'event and clk='1' then
|
if clk'event and clk='1' then
|
if io_byte_we /= "0000" then
|
if io_byte_we /= "0000" then
|
if io_wr_addr(31 downto 16)=X"2001" then
|
if io_wr_addr(31 downto 16)=X"2001" then
|
|
if io_wr_addr(5)='0' then
|
-- IRQ trigger register block (write only)
|
-- IRQ trigger register block (write only)
|
irq_trigger_load <= '1';
|
irq_trigger_load <= '1';
|
irq_trigger_data <= io_wr_data;
|
irq_trigger_data <= io_wr_data;
|
irq_trigger_addr <= io_wr_addr(4 downto 2);
|
irq_trigger_addr <= io_wr_addr(4 downto 2);
|
elsif io_wr_addr(31 downto 12)=X"2000f" then
|
else
|
-- Debug register block (read/write)
|
-- Debug register block (read/write)
|
debug_reg_block(conv_integer(unsigned(io_wr_addr(3 downto 2)))) <= io_wr_data;
|
debug_reg_block(conv_integer(unsigned(io_wr_addr(3 downto 2)))) <= io_wr_data;
|
|
end if;
|
else
|
else
|
irq_trigger_load <= '0';
|
irq_trigger_load <= '0';
|
end if;
|
end if;
|
else
|
else
|
irq_trigger_load <= '0';
|
irq_trigger_load <= '0';
|
Line 276... |
Line 314... |
end if;
|
end if;
|
end process simulated_io;
|
end process simulated_io;
|
|
|
-- The only readable i/o is the debug reg block. We simulate an asynchronous
|
-- The only readable i/o is the debug reg block. We simulate an asynchronous
|
-- read port (a mux).
|
-- read port (a mux).
|
|
-- For read accesses, this register block is mirrored all over the io
|
|
--- address space 2001xxxxh.
|
io_rd_data <= debug_reg_block(conv_integer(unsigned(io_rd_addr(3 downto 2))));
|
io_rd_data <= debug_reg_block(conv_integer(unsigned(io_rd_addr(3 downto 2))));
|
|
|
-- Simulate IRQs -----------------------------------------------------------
|
-- Simulate IRQs -----------------------------------------------------------
|
irq_trigger_registers:
|
irq_trigger_registers:
|
process(clk)
|
process(clk)
|