My name is Sven Andersson and I
work as a consultant in embedded
system design, implemented in ASIC
and FPGA.
In my spare time I write this blog
and I hope it will inspire others to
learn more about this fantastic field.
I live in Stockholm Sweden and have
my own company
Contact
You are welcome to contact me
and ask questions or make comments
about my blog.
We will take one step back and look at the Xilinx simulation environment and use the program Simgen.
Simgen
Simgen creates and configures various VHDL and Verilog simulation models for a specified hardware. It takes a Microprocessor Hardware Specification (MHS) file as input, which describes the instantiations and connections of hardware components. Simgen is also capable of creating scripts for a specified vendor simulation tool. The scripts compile the generated simulation models. The hardware component is defined by the MHS file. Refer to the "Microprocessor Hardware Specification (MHS)" chapter in the Platform Specification Format Reference Manual for more information. For more information about Simgen read the Embedded System Tools Reference Manual (chapter 3). Before we run Simgen let's make sure we have our software project selected in Xilinx Platform Studio. We also make sure we ticked the Marked for BRAM initialization (right-click Project: ETC_system_program).
We invoke Simgen from the Xilinx Platform Studio using the menu command: Simulation->Generate HDL Simulation Files. When the Simgen program has finished we find a new sub directory (simulation) in our xps directory.
Data2MEM Memory Tool
Data2MEM is a command line executable that transforms CPU execution code (in the form of an ELF file), or pure data, into Block RAM initialization records. Simgen will use Data2MEM to convert our ETC_system_program.elf file to a VHDL file that can be used to initialize the BRAM. Here is more information about Data2Mem. Here are some of the files that were generated during the Simgen run.
ETC_system_sim.bmm
ETC_system_sim.bmm defines the BRAM size and address space.
configuration lmb_bram_conf of lmb_bram_wrapper is for STRUCTURE for lmb_bram : lmb_bram_elaborate use entity lmb_bram_elaborate_v1_00_a.lmb_bram_elaborate; for STRUCTURE for ramb16_0 : ramb16 use entity unisim.ramb16(ramb16_v) generic map( READ_WIDTH_A => READ_WIDTH_A, READ_WIDTH_B => READ_WIDTH_B, WRITE_WIDTH_A => WRITE_WIDTH_A, WRITE_WIDTH_B => WRITE_WIDTH_B, WRITE_MODE_A => WRITE_MODE_A, WRITE_MODE_B => WRITE_MODE_B, RAM_EXTENSION_A => RAM_EXTENSION_A, RAM_EXTENSION_B => RAM_EXTENSION_B, INIT_00 => X"B8BCF930E0B82080B93030310000000000000000000000B8000000B800B800B8", INIT_01 => X"F8BC062020F92030B6E98099BC3030B0BCF930E830B6E9F03030BEE8E88099F8", .........................removed
INIT_3E => X"0000000000000000000000000000000000000000000000000000000000000000", INIT_3F => X"0000000000000000000000000000000000000000000000000000000000000000"); end for;
end for; end for; end for; end lmb_bram_conf;
configuration ETC_system_conf of etc_system is for STRUCTURE for all : lmb_bram_wrapper use configuration work.lmb_bram_conf; end for; end for; end ETC_system_conf;
ETC_system_tb.vhd
ETC_system_tb.vhd is the VHDL top testbench file.
------------------------------------------------------------------------------- -- ETC_system_tb.vhd ------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL;
library UNISIM; use UNISIM.VCOMPONENTS.ALL;
entity ETC_system_tb is end ETC_system_tb;
architecture STRUCTURE of ETC_system_tb is
constant fpga_0_DDR_CLK_FB_PERIOD : time := 10 ns; constant sys_clk_pin_PERIOD : time := 10 ns; constant sys_rst_pin_LENGTH : time := 160 ns;
component ETC_system is port ( fpga_0_RS232_Uart_RX_pin : in std_logic; fpga_0_RS232_Uart_TX_pin : out std_logic; fpga_0_LEDs_4Bit_GPIO_IO_pin : inout std_logic_vector(0 to 3); fpga_0_LEDs_Positions_GPIO_IO_pin : inout std_logic_vector(0 to 4); fpga_0_Push_Buttons_Position_GPIO_IO_pin : inout std_logic_vector(0 to 4); fpga_0_DDR_SDRAM_64Mx32_DDR_Clk_pin : out std_logic; fpga_0_DDR_SDRAM_64Mx32_DDR_Clkn_pin : out std_logic; fpga_0_DDR_SDRAM_64Mx32_DDR_Addr_pin : out std_logic_vector(0 to 12); fpga_0_DDR_SDRAM_64Mx32_DDR_BankAddr_pin : out std_logic_vector(0 to 1); fpga_0_DDR_SDRAM_64Mx32_DDR_CASn_pin : out std_logic; fpga_0_DDR_SDRAM_64Mx32_DDR_CKE_pin : out std_logic; fpga_0_DDR_SDRAM_64Mx32_DDR_CSn_pin : out std_logic; fpga_0_DDR_SDRAM_64Mx32_DDR_RASn_pin : out std_logic; fpga_0_DDR_SDRAM_64Mx32_DDR_WEn_pin : out std_logic; fpga_0_DDR_SDRAM_64Mx32_DDR_DM_pin : out std_logic_vector(0 to 3); fpga_0_DDR_SDRAM_64Mx32_DDR_DQS_pin : inout std_logic_vector(0 to 3); fpga_0_DDR_SDRAM_64Mx32_DDR_DQ_pin : inout std_logic_vector(0 to 31); fpga_0_DDR_CLK_FB : in std_logic; sys_clk_pin : in std_logic; sys_rst_pin : in std_logic; ETC_0_I_RESETS_pin : in std_logic; ETC_0_ETC_TDI_EX_pin : in std_logic; ETC_0_ETC_TCKI_pin : in std_logic; ETC_0_ETC_TRSTZI_pin : in std_logic; ETC_0_ETC_TMSI_pin : in std_logic; ETC_0_JTC_TDO_ENB_pin : in std_logic; ETC_0_JTC_TDO_pin : in std_logic; ETC_0_CE1_pin : in std_logic; ETC_0_JTC_TCK_pin : out std_logic; ETC_0_JTC_TRSTZ_pin : out std_logic; ETC_0_JTC_TMS_pin : out std_logic; ETC_0_JTC_TDI_pin : out std_logic; ETC_0_ETC_TCKO_pin : out std_logic; ETC_0_ETC_TMSO_pin : out std_logic; ETC_0_ETC_TDO_pin : out std_logic; ETC_0_ETC_TDO_ENB_pin : out std_logic; ETC_0_ETC_TRSTZO_pin : out std_logic; ETC_0_ETC_ENB_pin : out std_logic; ETC_0_ETC_TDI_FX_pin : in std_logic; ETC_0_O_INTERRUPT_pin : out std_logic; LCD_16x2_GPIO_IO_pin : inout std_logic_vector(0 to 6) ); end component;
.........................removed -- Clock generator for fpga_0_DDR_CLK_FB
process begin fpga_0_DDR_CLK_FB <= '0'; loop wait for (fpga_0_DDR_CLK_FB_PERIOD/2); fpga_0_DDR_CLK_FB <= not fpga_0_DDR_CLK_FB; end loop; end process;
-- Clock generator for sys_clk_pin
process begin sys_clk_pin <= '0'; loop wait for (sys_clk_pin_PERIOD/2); sys_clk_pin <= not sys_clk_pin; end loop; end process;
-- Reset Generator for sys_rst_pin
process begin sys_rst_pin <= '0'; wait for (sys_rst_pin_LENGTH); sys_rst_pin <= not sys_rst_pin; wait; end process;
-- START USER CODE (Do not remove this line)
-- User: Put your stimulus here. Code in this -- section will not be overwritten.
-- END USER CODE (Do not remove this line)
end architecture STRUCTURE;
configuration ETC_system_tb_conf of ETC_system_tb is for STRUCTURE for all : ETC_system use configuration work.ETC_system_conf; end for; end for; end ETC_system_tb_conf;
Modifying the testbench file
We normally run all our simulations in batch mode and we need a simple way to tell how long the simulation will run. Here is one method to run 80000 ns after reset is released.
process begin sys_rst_pin <= '0'; wait for (sys_rst_pin_LENGTH); sys_rst_pin <= not sys_rst_pin; wait for 800000 ns; assert false report "NONE. End of simulation." severity failure; end process;
Compiling the BRAM initialization file
We compile the ETC_system_init.vhd together with the wrapper files and store it in the top library.
Compiling the testbench file
We compile the ETC_system_tb.vhd testbench file into the ETC_system_tb library and after elaboration we have the following database structure.
Simulating program execution
Here is the whole sequence to add a new application program to our simulation environment.
Compile and link the program
Convert the ELF file to a BRAM memory image (ETC_system_init.vhd)
Compile the ETC_system_init.vhd using ncvhdl
Elaborate everything using ncelab
Run the simulation using ncsim (ETC_SYSTEM_TB_CONF)
Save the waveforms
When the simulation has finish look at the waveforms in Simvision.
Here is the program.
// The following constant maps to the name of the hardware instances that // were created in the EDK XPS system. #define GPIO_LCD_DEVICE_ID XPAR_LCD_16X2_DEVICE_ID #define GPIO_LED4_DEVICE_ID XPAR_LEDS_4BIT_DEVICE_ID #define GPIO_LEDP_DEVICE_ID XPAR_LEDS_POSITIONS_DEVICE_ID
// The following constant is used to determine which channel of the GPIO is // used if there are 2 channels supported.
#define LCD_CHANNEL 1 #define LED_CHANNEL 1
// The following are declared globally so they are zeroed and so they are // easily accessible from a debugger
XGpio GpioLCD; /* The Instance of the GPIO LCD Driver */ XGpio GpioLED4; /* The Instance of the GPIO LED4 Driver */ XGpio GpioLEDPOS; /* The Instance of the GPIO LEDPOS Driver */
int main(void) {
XStatus Status; // Initialize the GPIO component Status = XGpio_Initialize(&GpioLCD, GPIO_LCD_DEVICE_ID); if (Status != XST_SUCCESS) return XST_FAILURE; Status = XGpio_Initialize(&GpioLED4, GPIO_LED4_DEVICE_ID); if (Status != XST_SUCCESS) return XST_FAILURE; Status = XGpio_Initialize(&GpioLEDPOS, GPIO_LEDP_DEVICE_ID); if (Status != XST_SUCCESS) return XST_FAILURE; // Set the direction for all bits to be outputs XGpio_SetDataDirection(&GpioLCD, LCD_CHANNEL, 0x00); XGpio_SetDataDirection(&GpioLED4, LED_CHANNEL, 0x00); XGpio_SetDataDirection(&GpioLEDPOS, LED_CHANNEL, 0x00); // Turn on LEDs XGpio_DiscreteWrite(&GpioLED4, LED_CHANNEL, 0xa); XGpio_DiscreteWrite(&GpioLEDPOS, LED_CHANNEL, 0xa); // Write to LCD XGpio_DiscreteWrite(&GpioLCD, LCD_CHANNEL, 0xa); return XST_SUCCESS;
}
Here is the result.
The simulation runs as expected. One more milestone reached.