|
|
 |
FPGA design from scratch. Part 39
Fixing our software device driver
Let's modify our template files and start with the .tcl file.
etc_v2_1_0.tcl
The .tcl script file copies the parameters we specify to the xparameters.h and xextc_g.c files during library generation. It looks like this after modifications.
proc generate {drv_handle} { set level [xget_value $drv_handle "PARAMETER" "level"] xdefine_include_file $drv_handle "xparameters.h" "XEtc" "NUM_INSTANCES" "MEM_BANK0_BASE_ADDR" "MEM_BANK0_HIGH_ADDR" "MEM_BANK1_BASE_ADDR" "MEM_BANK1_HIGH_ADDR" "REGISTER_BASE_ADDR" "REGISTER_HIGH_ADDR" "DEVICE_ID" "C_INTERRUPT_PRESENT" xdefine_config_file $drv_handle "xetc_g.c" "XEtc" "DEVICE_ID" "MEM_BANK0_BASE_ADDR" "MEM_BANK1_BASE_ADDR" "REGISTER_BASE_ADDR" "C_INTERRUPT_PRESENT" }
This is the result taken from the xparameters.h file.
/* Definitions for driver ETC */ #define XPAR_XETC_NUM_INSTANCES 1
/* Definitions for peripheral ETC_0 */ #define XPAR_ETC_0_MEM_BANK0_BASE_ADDR 0x42a08000 #define XPAR_ETC_0_MEM_BANK0_HIGH_ADDR 0x42a08fff #define XPAR_ETC_0_MEM_BANK1_BASE_ADDR 0x42a09000 #define XPAR_ETC_0_MEM_BANK1_HIGH_ADDR 0x42a09fff #define XPAR_ETC_0_REGISTER_BASE_ADDR 0x71A00000 #define XPAR_ETC_0_REGISTER_HIGH_ADDR 0x71A0001F #define XPAR_ETC_0_DEVICE_ID 0 #define XPAR_ETC_0_INTERRUPT_PRESENT 0
etc_v2_1_0.tcl.mdd
The .mdd file looks like this. The "copyfiles" line instructs the EDK tools to copy the source files into the user's project directory and compile them from there.
OPTION psf_version = 2.1;
BEGIN driver etc
OPTION supported_peripherals = (ETC_0); OPTION driver_state = ACTIVE; OPTION depends = (common_v1_00_a); OPTION copyfiles = all;
BEGIN INTERFACE linux END INTERFACE
BEGIN ARRAY interrupt_handler END ARRAY
END driver
Makefile
In the Makefile we have to add all header file under INCLUDEFILES. This will copy the header files to the directory include during library generation.
COMPILER= ARCHIVER= CP=cp COMPILER_FLAGS= EXTRA_COMPILER_FLAGS= LIB=libxil.a
RELEASEDIR=../../../lib INCLUDEDIR=../../../include INCLUDES=-I./. -I${INCLUDEDIR}
INCLUDEFILES=xetc.h xetc_l.h xetc_i.h
LIBSOURCES=*.c OUTS = *.o
xetc_g.c
The xetc_g.c is automatically generated by Libgen. Here is the configuration table taken from the xetc_g.c file.
/* * The configuration table for devices */
XEtc_Config XEtc_ConfigTable[] = { { XPAR_ETC_0_DEVICE_ID, XPAR_ETC_0_MEM_BANK0_BASE_ADDR, XPAR_ETC_0_MEM_BANK1_BASE_ADDR, XPAR_ETC_0_REGISTER_BASE_ADDR, XPAR_ETC_0_INTERRUPT_PRESENT }
xetc.h
The following type definition are modified to match with the configuration table shown above.
/** * This typedef contains configuration information for the device. */ typedef struct { Xuint16 DeviceId; /* Unique ID of device */ Xuint32 Mem0_BaseAddress; /* Memory bank0 base address */ Xuint32 Mem1_BaseAddress; /* Memory bank1 base address */ Xuint32 Reg_BaseAddress; /* Register bank base address */ Xboolean InterruptPresent; /* Are interrupts supported in h/w */ } XEtc_Config;
/** * The XEtc driver instance data. The user is required to allocate a * variable of this type for every ETC device in the system. A pointer * to a variable of this type is then passed to the driver API functions. */ typedef struct { Xuint32 Mem0_BaseAddress; /* Memory bank0 base address */ Xuint32 Mem1_BaseAddress; /* Memory bank1 base address */ Xuint32 Reg_BaseAddress; /* Register bank base address */ Xuint32 IsReady; /* Device is initialized and ready */ XEtc_Config *ConfigPtr; /* Pointer to the configuration */ } XEtc;
xetc_l.h
For the lowest level we only need to provide register read an write functions. We will use the Xilinx standard routines XIo_Out32 and XIo_in32 to give us these functions.
/****************************************************************************/ #define XEtc_mWriteReg(BaseAddress, RegOffset, Data) XIo_Out32((BaseAddress) + (RegOffset), (Xuint32)(Data))
/****************************************************************************/ #define XEtc_mReadReg(BaseAddress, RegOffset) XIo_In32((BaseAddress) + (RegOffset))
The XIo_Out32 and XIo_In32 are defined in the header file xio.h found in the include directory.
* Performs an input operation for a 32-bit memory location by reading from the * specified address and returning the value read from that address. * * @param InputPtr contains the address to perform the input operation at. * * @return The value read from the specified input address. *
#define XIo_In32(InputPtr) (*(volatile Xuint32 *)(InputPtr))
* Performs an output operation for a 32-bit memory location by writing the * specified value to the the specified address. * * @param OutputPtr contains the address to perform the output operation at. * @param Value contains the value to be output at the specified address. * * @return None. *
#define XIo_Out32(OutputPtr, Value) (*(volatile Xuint32 *)((OutputPtr)) = (Value))
Writing an application program
We will start out writing a low level application program only using the read/write functions. Here is an example:
//$$INCLUDE /*************************************************************************/ /* */ /* I N C L U D E H E A D E R F I L E S */ /* */ /*************************************************************************/
#include "xparameters.h" #include "xetc.h" #include "xetc_l.h" #include "xutil.h" #include <stdio.h>
//$$DEFINE /*************************************************************************/ /* */ /* D E F I N E C O N S T A N T S */ /* */ /*************************************************************************/
// The following constant maps to the name of the hardware instances that // were created in the EDK XPS system.
#define ETC_REG_BASEADDR XPAR_ETC_0_REGISTER_BASE_ADDR // The following parameters are used to setup the ETC #define ENABLE_INTERRUPT 0X1000 #define DISABLE_INTERRUPT 0X0 #define ENABLE_LOOP_MODE 0x800 #define DISABLE_LOOP_MODE 0x0 #define SKIP_TDO_SHIFTIR 0x200 #define SKIP_TDO_SHIFTDR 0x400 #define DISABLE_SINGLE_STEP 0x0 #define ENABLE_SINGLE_STEP 0x100 #define DISABLE_TCK 0x0 #define ENABLE_TCK 0x80 #define CLOCK_RATE_DIV_BY_4 0x0 #define CLOCK_RATE_DIV_BY_8 0x10 #define CLOCK_RATE_DIV_BY_16 0x20 #define CLOCK_RATE_DIV_BY_32 0x30 #define CLOCK_RATE_DIV_BY_64 0x40 #define EXTERNAL_TEST 0x8
#define START_ETC 0x1 #define STOP_ETC 0x0
//$$FUNCTIONS /*************************************************************************/ /* */ /* D E F I N E F U N C T I O N S */ /* */ /*************************************************************************/
void usleep(unsigned int useconds) { int i,j; for (j=0;j<useconds;j++) for (i=0;i<26;i++) asm("nop"); }
//$$ETC TEST PROGRAM /*************************************************************************/ /* */ /* E T C T E S T P R O G R A M */ /* */ /*************************************************************************/
// Define testprogram
// TestResetKeepingTrstzLow (10); // LoadInstruction(INSTRUCTION_LENGTH,IDCODE); // ReadWriteDataRegister(IdentificationRegLen+20,{{IdentificationRegLen{1'b0}},20'b1110011101}); // SetExpectedData(IdentificationRegLen+20,{20'b1110011101,{IdentificationRegLen{1'bx}}}); // EndOfTestProgram;
Xuint32 TestProgram[] = { 0x800000a1, 0xc0000043, 0x00000002, 0xc0340004, 0x4000039d, 0x00000000, 0x8000000c }; int ProgramSize = 7;
//$$MAIN /*************************************************************************/ /* */ /* M A I N P R O G R A M */ /* */ /*************************************************************************/
int main(void) {
int i; Xuint32 StatusReg; print("Load test program "); // Load test program to test program RAM for (i = 0; i < ProgramSize; i++) { XEtc_mWriteReg(XPAR_ETC_0_MEM_BANK0_BASE_ADDR, i*4, TestProgram[i]); };
// Write to control register XEtc_mWriteReg(ETC_REG_BASEADDR, XETC_CONTROL_REG_OFFSET, DISABLE_INTERRUPT + DISABLE_LOOP_MODE + SKIP_TDO_SHIFTIR + DISABLE_SINGLE_STEP + ENABLE_TCK + CLOCK_RATE_DIV_BY_4 + EXTERNAL_TEST); print("Start test "); // Start test XEtc_mWriteReg(ETC_REG_BASEADDR, XETC_EXECUTE_REG_OFFSET, START_ETC); // Wait for test to finish usleep(4);
print("Stop test "); // Stop test XEtc_mWriteReg(ETC_REG_BASEADDR, XETC_EXECUTE_REG_OFFSET, STOP_ETC); // Stop TCK XEtc_mWriteReg(ETC_REG_BASEADDR, XETC_CONTROL_REG_OFFSET, DISABLE_INTERRUPT + DISABLE_LOOP_MODE + SKIP_TDO_SHIFTIR + DISABLE_SINGLE_STEP + DISABLE_TCK + CLOCK_RATE_DIV_BY_4 + EXTERNAL_TEST);
// Read status register print("Read status register "); StatusReg = XEtc_mReadReg(ETC_REG_BASEADDR, XETC_STATUS_REG_OFFSET); xil_printf("Status reg : %x ",StatusReg);
return 0; }
Print statements
To save memory space we don't use the standard print routines like printf. Instead we use <xil_printf>and <print>.
Printout from program
After compiling and linking the program we download it to our design. The program starts and prints out the following text:
Load test program Start test Stop test Read status register Status reg : 3464
The value in the status register tells us that the testprogram ran successfully. We have written our first application program to drive the ETC. One more milestone reached.
Generate HDL simulation files
We can use the following command from the commandline to generate the HDL simulation files.
==> cd /home/svenand/root/projects/ETC/xps ==> simgen -f simgen.opt
Here is the output:
Simulation Model Generator Xilinx EDK 9.1.01 EDK_J_SP1.3 Copyright (c) 1995-2007 Xilinx, Inc. All rights reserved. Command Line: simgen -p xc4vfx12ff668-10 -lang vhdl -pe microblaze_0 SDK_projects/ETC_system_program/Debug/ETC_system_program.elf -mixed yes -s ncs -tb -X /home/svenand/root/projects/ETC/verification/database/ncsim/macrolib/ -E /home/svenand/root/projects/ETC/verification/database/ncsim/edklib/ -m behavioral ETC_system.mhs
MHS file : /home/svenand/root/projects/ETC/xps/ETC_system.mhs Language (-lang) : VHDL Simulation Model (-m) : Behavioral Simulator (-s) : NcSim (NCS) Part (-p) [ family ] : xc4vfx12ff668-10 [ virtex4 ] Output directory (-od): /home/svenand/root/projects/ETC/xps/
Edklib (-E) : /home/svenand/root/projects/ETC/verification/database/ncsim/edklib/ Xlib (-X) : /home/svenand/root/projects/ETC/verification/database/ncsim/macrolib/
..........
Analyzing file /home/svenand/root/projects/ETC/xps/SDK_projects/ETC_system_program/Debug/ETC_sy stem_program.elf... INFO:MDT - BRAM lmb_bram will be initialized with ELF of processor microblaze_0 Running Data2Mem with the following command: data2mem -bm ETC_system_sim.bmm -bd /home/svenand/root/projects/ETC/xps/SDK_projects/ETC_system_program/Debug/ETC_sy stem_program.elf tag microblaze_0 -u -o u tmpucf.ucf
Generating simulator compile script ...
Generating the BRAM initialization file
If we only changed the application program file (.elf) we don't have to generate all the HDL simulation files. We only need the BRAM initialization file: ETC_system_init.vhd. This file can generated in these two steps:
- Use data2mem to convert the .elf file to a .ucf file
- Use ucf2vhdl.pl to convert the .ucf file to a .vhdl file
==> cd /home/svenand/root/projects/ETC/xps/simulation/behavioral
==> data2mem -bm ETC_system_sim.bmm -bd /home/svenand/root/projects/ETC/xps/SDK_projects/ETC_system_program/Debug/ETC_sy stem_program.elf tag microblaze_0 -u -o u tmpucf.ucf ==> xilperl /home/svenand/cad/edk91i/bin/lin/ucf2vhdl.pl tmpucf.ucf ETC_system_init.vhd ETC_system ETC_system_conf vhdl Running a simulation
Here is the same application program running in a simulation.

Top Next Previous
Posted at 08:56 am by svenand
|