Thursday, June 16, 2011

Generating 16k ROM using Xilinx IP COREGEN and simulating it in modelsim

The instruction ROM is an IP Core. so before interfacing with the open8, it has to be generated. The method of generating and simulating a ROM Xilinx IP Core is described here.

1. app.coe (the initialization file)
2. rom_16k_core.vhd
3. rom_16k_core.vho
4. rom_16k_core.xco
5. top_level.vhd

Creation of the ROM
Xilinx 10.1
1. open ISE
2. create a new project
3. tools -> core generator(12.1) (or right click on the device and add a new file 10.1)
4. In the IP catalog -> Memory and storage elements -> RAM and ROM
5. double click on block memory generator, A new window opens
6. In the new window select single port ROM click next, Write first mode
7. Select
Read Width = 8 and Read Depth = 16384 for 16K ROM -> next
8. The output ports are unregistered, load initialization COE if required -> next
9. No need to use the Reset pin -> next
10. Generate. (takes a little time then shows successfully generated)

This generated ROM has to be connected to the Open8 and functions as the program memory. The ROM provides a VHDL file. needs to be connected to the open8

Simulation using Modelsim
1. The ip core is generated in the ipcore_dir directory inside the current project
2. The most important files are the .vhd, .xco,.vho, .mif
3. Simulate the .vhd file as any other vhdl file. copy the .xco file into the simulation directory and the .vho contains information on how to instantiate the ip core

The simulation directory contains .vhd,.vho,.xco,.mif

4. For simulation it is essential that you compile the xilinx libraries namely unisim, simprim and xilinxcorelib.(mainly xilinxcorelib because it contains the definition for the ipcore).
5. Write a top level that instantiates the memory as a component and write a test bench to test the memory created

ERROR: Error: Could not find xilinxcorelib.blk_mem_gen_v7_2.
Make sure you have compiled the xilinx libraries unisim, simprim and xilinxcorelib in modelsim.

BUG in open8 - solved - It is not a bug but a misunderstanding, THANK YOU Mr. SETH HENRY


There was a misunderstanding regarding to the bug I had encountered while using open 8 core. The bug is that there was a displacement of 1 cycle in the processor code while fetching the return address executing the "RTI" instruction. It is described in detail here.

This is not actually a bug because the processor was pipelined in such a way that the data was to be read from the memory in a span of 2 cycles while my assumption about the memory model was that data was fetched in 1 cycle. This pipelining was done in order to increase the frequency of operation.

So the memory model is described as follows - 16 k single ported ROM in the write first mode. width = 8 and depth = 16k (16384). The pipeline operation is described here as a stand alone project. (not connected to the open8)

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity rom_16k is
  Clock                 : in  std_logic;
  Bus_Address           : in  std_logic_vector(15 downto 0);
  Rd_Enable             : in  std_logic;
  Rd_Data               : out std_logic_vector(7 downto 0)
end entity;

architecture behave of rom_16k is

  constant User_Addr    : std_logic_vector(15 downto 14) := "00";
  alias Comp_Addr       is Bus_Address(15 downto 14);
  signal Comp_Addr_q    : std_logic_vector(15 downto 14);

  alias ROM_Addr        is Bus_Address(13 downto 0);

  signal Rd_Enable_q    : std_logic;
  signal Rd_Data_i      : std_logic_vector(7 downto 0);

  component rom_16k_core
port (
clka: IN std_logic;
addra: IN std_logic_VECTOR(13 downto 0);
douta: OUT std_logic_VECTOR(7 downto 0));
  end component;


  RAM_proc: process( Clock )
    if( rising_edge(Clock) )then
      Comp_Addr_q       <= Comp_Addr;
      Rd_Enable_q       <= Rd_Enable;
      Rd_Data           <= (others => '0');
      if( User_Addr = Comp_Addr_q )then
        if( Rd_Enable_q = '1' )then
          Rd_Data       <= Rd_Data_i;
        end if;
      end if;
    end if;
  end process;

  U_ROM_CORE : rom_16k_core
  port map(
    addra             => ROM_Addr,
    clka              => Clock,
    douta             => Rd_Data_i

It had described in my earlier post the supposed bug

"It is to be seen in the waveform that when rd_data line has the return address (151 in our case) the cache_ctrl is idle. "

This will work fine if the memory model is a 2 stage pipeline before the data is read from the memory. as shown in this figure

It is seen that in this memory model, the address is present before the first clock cycle while the data is read only in the second clock cycle.

How to generate the memory in xilinx and simulate it? it is another story in itself and is described here.

Hence there was no bug in the open8 core. This was elegantly explained to me by Mr. Seth Henry who is the author of the processor. He shared with me the memory model in his mail and helped correct my concept. I truly consider it an honor getting a detailed reply from him. Thank you Mr. Seth Henry. Long live open source.