New Horizons

Welcome to my blog

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


You are welcome to contact me
and ask questions or make comments
about my blog.


New Horizons
What's new
Starting a blog
Writing a blog
Using an RSS reader

Zynq Design From Scratch
Started February 2014
1 Introduction
Changes and updates
2 Zynq-7000 All Programmable SoC
3 ZedBoard and other boards
4 Computer platform and VirtualBox
5 Installing Ubuntu
6 Fixing Ubuntu
7 Installing Vivado
8 Starting Vivado
9 Using Vivado
10 Lab 1. Create a Zynq project
11 Lab 1. Build a hardware platform
12 Lab 1. Create a software application
13 Lab 1. Connect to ZedBoard
14 Lab 1. Run a software application
15 Lab 1. Benchmarking ARM Cortex-A9
16 Lab 2. Adding a GPIO peripheral
17 Lab 2. Create a custom HDL module
18 Lab 2. Connect package pins and implement
19 Lab 2. Create a software application and configure the PL
20 Lab 2. Debugging a software application
21 Running Linux from SD card
22 Installing PetaLinux
23 Booting PetaLinux
24 Connect to ZedBoad via ethernet
25 Rebuilding the PetaLinux kernel image
26 Running a DHCP server on the host
27 Running a TFTP server on the host
28 PetaLinux boot via U-boot
29 PetaLinux application development
30 Fixing the host computer
31 Running NFS servers
32 VirtualBox seamless mode
33 Mounting guest file system using sshfs
34 PetaLinux. Setting up a web server
35 PetaLinux. Using cgi scripts
36 PetaLinux. Web enabled application
37 Convert from VirtualBox to VMware
38 Running Linaro Ubuntu on ZedBoard
39 Running Android on ZedBoard
40 Lab2. Booting from SD card and SPI flash
41 Lab2. PetaLinux board bringup
42 Lab2. Writing userspace IO device driver
43 Lab2. Hardware debugging
44 MicroZed quick start
45 Installing Vivado 2014.1
46 Lab3. Adding push buttons to our Zynq system
47 Lab3. Adding an interrupt service routine
48 Installing Ubuntu 14.04
49 Installing Vivado and Petalinux 2014.2
50 Using Vivado 2014.2
51 Upgrading to Ubuntu 14.04
52 Using Petalinux 2014.2
53 Booting from SD card and SPI flash
54 Booting Petalinux 2014.2 from SD card
55 Booting Petalinux 2014.2 from SPI flash
56 Installing Vivado 2014.3

Chipotle Verification System

EE Times Retrospective Series
It all started more than 40 years ago
My first job as an electrical engineer
The Memory (R)evolution
The Microprocessor (R)evolution

Four soft-core processors
Started January 2012
Table of contents
OpenRISC 1200
Nios II

Using the Spartan-6 LX9 MicroBoard
Started August 2011
Table of contents
Problems, fixes and solutions

FPGA Design From Scratch
Started December 2006
Table of contents
Acronyms and abbreviations

Actel FPGA design
Designing with an Actel FPGA. Part 1
Designing with an Actel FPGA. Part 2
Designing with an Actel FPGA. Part 3
Designing with an Actel FPGA. Part 4
Designing with an Actel FPGA. Part 5

A hardware designer's best friend
Zoo Design Platform

Installing Cobra Command Tool
A processor benchmark

Porting a Unix program to Mac OS X
Fixing a HyperTerminal in Mac OS X
A dream come true

Stockholm by bike

The New York City Marathon

Kittelfjall Lappland

Tour skating in Sweden and around the world
Wild skating
Tour day
Safety equipment
A look at the equipment you need
Skate maintenance
Books, photos, films and videos
Weather forecasts

38000 feet above see level
A trip to Spain
Florida the sunshine state

Photo Albums
Seaside Florida
Ronda Spain
Sevilla Spain
Cordoba Spain
Alhambra Spain
KittelfjÀll Lapland
Landsort Art Walk
Skating on thin ice

100 Power Tips for FPGA Designers

Adventures in ASIC
Computer History Museum
Design & Reuse
d9 Tech Blog
EDA Cafe
EDA DesignLine
Eli's tech Blog
FPGA Arcade
FPGA Central
FPGA developer
FPGA Journal
FPGA World
Lesley Shannon Courses
Mac 2 Ubuntu
Programmable Logic DesignLine
World of ASIC

If you want to be updated on this weblog Enter your email here:

rss feed

Wednesday, May 02, 2007
FPGA design from scratch. Part 24
System simulations

System simulation is an effective method for verifying that software drivers are compatible with the hardware. Using a simulator for that purpose offers several advantages over
GDB. For example, no physical link to the hardware is required and internal system signals may be easily monitored. In addition, the hardware does not need to be run through the implementation tools to run a system simulation, allowing the quick analysis of the effects of changes to the code or the generics. The flow presented here can easily be modified to support structural and timing simulation.

EDK System Simulation guide presents Xilinx idea about system simulations. They use Modelsim and the setup is to complicated for my taste. We will stay with NCSIM and the simulation strategy we formulated in part 23. We will specify testcases to verify all interfaces in our system. Each testcase will include a c-program to access the peripheral and it's registers. Here is our system.

DDR SDRAM controller

The DDR SDRAM controller (
opb_ddr) connects the DDR SDRAM to the OPB. The DDR SDRAM is a Micron  MT46V16M16P-6T.

  • OPB interface
  • Performs device initialization sequence upon power-up and reset conditions for ~200uS. Provides a parameter to adjust this time for simulation purposes only.
  • Performs auto-refresh cycles
  • Supports CAS latencies of 2 or 3 set by a design parameter
  • Supports 16, 32 and 64 bits DDR data widths set by a designparameter
  • Supports indeterminate burst length
  • Provides big-endian connections to memory devices
  • Supports multiple (up to 4) DDR memory banks.

DDR SDRAM Initialization

Prior to normal operation, DDR SDRAMs must be powered up and initialized in a predefined manner. Operational procedures, other than those specified, may result in undefined operation. To ensure device operation, the DRAM must be initialized as described in the following steps:
  1. Simultaneously apply power to VDD and VDDQ
  2. Apply VREF and then VTT power. VTT must be applied after VDDQ to avoid device latchup, which may cause permanent damage to the device. Exept for CKE, inputs are not recognized as valid until after VREF is applied.
  3. Assert and hold CKE at a LVCMOS logic LOW. Maintaining an LVCMOS LOW level on CKE during power-up is required to ensure that the DQ and DQS outputs will be in the High-Z state, where they will remain until driven in normal operation (by a read access).
  4. Provide stable clock signals.
  5. Wait at least 200μs.
  6. Bring CKE HIGH, and provide at least one NOP or DESELECT command. At this point, the CKE input changes from a LVCMOS input to a SSTL_2 input only and will remain a SSTL_2 input unless a power cycle occurs.
  7. For more information about the initialization see the DDR SDRAM data sheet.
Setting the initialization time

The OPB DDR block will insert a 200us delay before it asserts DDR_init_done (see waveform plot) to allow time for DDR SDRAM initialization to happen.

For simulation purpose only we can change that time by editing the wrapper file ddr_sdram_64mx32_wrapper.vhd.
Look for the line: C_SIM_INIT_TIME_PS => 200000000 and change it to
C_SIM_INIT_TIME_PS => 20000 (20ns).

C program

This program will write and read three addresses in the DDR SDRAM.

int main()

#define poke(addr,val)     (*(unsigned char*) (addr) = (val))
#define pokew(addr,val)    (*(unsigned*) (addr) = (val))
#define peek(addr)         (*(unsigned char*) (addr))
#define peekw(addr)        (*(unsigned*) (addr))


   unsigned char byte_of_data;
   unsigned      word_of_data;
   word_of_data = peekw(0x44000000);
   word_of_data = peekw(0x46000004);
   word_of_data = peekw(0x47fffffc);
    return 0;
Assembly code

  0:    3021fff0     addik   r1, r1, -16
   4:    fa61000c     swi     r19, r1, 12
   8:    12610000     addk    r19, r1, r0
   c:    3060ffff     addik   r3, r0, -1
  10:    b0004400     imm     17408
  14:    f8600000     swi     r3, r0, 0
  18:    b000aaaa     imm     -21846
  1c:    3060aaaa     addik   r3, r0, -21846
  20:    b0004600     imm     17920
  24:    f8600004     swi     r3, r0, 4
  28:    b0005555     imm     21845
  2c:    30605555     addik   r3, r0, 21845
  30:    b00047ff     imm     18431
  34:    f860fffc     swi     r3, r0, -4
  38:    b0004400     imm     17408
  3c:    e8600000     lwi     r3, r0, 0
  40:    f8730008     swi     r3, r19, 8
  44:    b0004600     imm     17920
  48:    e8600004     lwi     r3, r0, 4
  4c:    f8730008     swi     r3, r19, 8
  50:    b00047ff     imm     18431
  54:    e860fffc     lwi     r3, r0, -4
  58:    f8730008     swi     r3, r19, 8
  5c:    10600000     addk    r3, r0, r0
  60:    10330000     addk    r1, r19, r0
  64:    ea61000c     lwi     r19, r1, 12
  68:    30210010     addik   r1, r1, 16
  6c:    b60f0008     rtsd    r15, 8
  70:    80000000     or      r0, r0, r0

Simulation result

LED displays and push buttons

The LED displays (LED_Positions and LEDs_4Bit) and the push buttons are connected to the general purpose input/outputs and through the OPB General Purpose Input/Output (
GPIO) controller to the OPB bus.

  • OPB v2.0 bus interface with byte-enable support
  • Configurable as single or dual GPIO channel(s)
  • Number of GPIO bits configurable from 1 to 32 bits
  • Each GPIO bit dynamically programmable as input or output
  • Can be configured as inputs-only on a per channel basis to reduce resource utilization
  • Ports for both 3-state and non 3-state connections
  • Independent reset values for each bit of all registers
  • Optional interrupt request generation
Address ranges

0x40020000-0x4002ffff LEDs_Positions
0x40040000-0x4004ffff LEDs_4Bit
0x40000000-0x4000ffff Push_Buttons_Position

OPB GPIO Registers

There are four internal registers in the OPB GPIO design as shown in the table. These registers are implemented in the GPIO_CORE interface module. The memory map of the OPB GPIO design is determined by setting the C_BASEADDR parameter. The internal registers of the OPB GPIO are at a fixed offset from the base address.

 Register Name
 Description  OPB Address
 GPIO_DATA  Channel 1 OPB GPIO Data Register  C_BASEADDR + 0x00  Read/Write
 GPIO_TRI  Channel 1 OPB GPIO 3-state Register  C_BASEADDR + 0x04  Read/Write
 Channel 2 OPB GPIO Data register 
 C_BASEADDR + 0x08  Read/Write
 GPIO2_TRI  Channel 2 OPB GPIO 3-state Register

C program

int main()

#define poke(addr,val)     (*(unsigned char*) (addr) = (val))
#define pokew(addr,val)    (*(unsigned*) (addr) = (val))
#define peek(addr)         (*(unsigned char*) (addr))
#define peekw(addr)        (*(unsigned*) (addr))


   unsigned char byte_of_data;
   unsigned      word_of_data;
// Write to LEDs

// Read push buttons

word_of_data  = peek(0x40000000);
  word_of_data  = peek(0x40000008);
   return 0;

Assembly code

   0:    3021fff0     addik  r1, r1, -16
   4:    fa61000c     swi    r19, r1, 12
   8:    12610000     addk   r19, r1, r0
   c:    3060ffff     addik  r3, r0, -1
  10:    b0004002     imm    16386
  14:    f8600000     swi    r3, r0, 0
  18:    b0004002     imm    16386
  1c:    f8000004     swi    r0, r0, 4
  20:    b0003333     imm    13107
  24:    30603333     addik  r3, r0, 13107
  28:    b0004002     imm    16386
  2c:    f8600008     swi    r3, r0, 8
  30:    b0004002     imm    16386
  34:    f800000c     swi    r0, r0, 12
  38:    b0005555     imm    21845
  3c:    30605555     addik  r3, r0, 21845
  40:    b0004004     imm    16388
  44:    f8600000     swi    r3, r0, 0
  48:    b0004004     imm    16388
  4c:    f8000004     swi    r0, r0, 4
  50:    b0001111     imm    4369
  54:    30601111     addik  r3, r0, 4369
  58:    b0004004     imm    16388
  5c:    f8600008     swi    r3, r0, 8
  60:    b0004004     imm    16388
  64:    f800000c     swi    r0, r0, 12
  68:    3060ffff     addik  r3, r0, -1
  6c:    b0004000     imm    16384
  70:    f8600004     swi    r3, r0, 4
  74:    b0004000     imm    16384
  78:    e8600000     lwi    r3, r0, 0
  7c:    f8730008     swi    r3, r19, 8
  80:    3060ffff     addik  r3, r0, -1
  84:    b0004000     imm    16384
  88:    f860000c     swi    r3, r0, 12
  8c:    b0004000     imm    16384
  90:    e8600008     lwi    r3, r0, 8
  94:    f8730008     swi    r3, r19, 8
  98:    10600000     addk   r3, r0, r0
  9c:    10330000     addk   r1, r19, r0
  a0:    ea61000c     lwi    r19, r1, 12
  a4:    30210010     addik  r1, r1, 16
  a8:    b60f0008     rtsd   r15, 8
  ac:    80000000     or     r0, r0, r0

Simulation result

Embedded Test Controller

The Embedded Test Controller (ETC) is a custom IP that implements a 1149.1 complient JTAG tester. It can run JTAG test sequences on the board and/or the complete system during startup and normal operation.

ETC address map

Register/ Memory Name
Size Access Address
Control 32 Write 0x42a10000
32 Read 0x42a10004
Execute 32 Write 0x42a10008 
Debug  32 Read 0x42a1000c
Test program RAM
1Kx32 Write 0x42a08000 
Test result RAM
1Kx32  Read 0x42a09000 

C program

int main()

#define poke(addr,val)     (*(unsigned char*) (addr) = (val))
#define pokew(addr,val)    (*(unsigned*) (addr) = (val))
#define peek(addr)         (*(unsigned char*) (addr))
#define peekw(addr)        (*(unsigned*) (addr))


   unsigned char byte_of_data;
   unsigned      word_of_data;
// Write testprogram
// Write control register in ETC
// Enable TCK clock
// Read status register in ETC 
   word_of_data = peekw(0x42a10004); 
// Read debug register in ETC
   word_of_data = peekw(0x42a1000c);
// Start test program

Simulation result

Debugging the On-chip Peripheral Bus

When I started to debug the ETC IP I quickly found out that my implementation and the Xilinx implementations of the OPB interface differed.


Here is the IBM
On-Chip Peripheral Bus Architecture Specification and here is the Xilinx implementation

MicroBlaze write cycle.

Let's take a closer look at the OPB. Here are two plots showing all signals in the Xilinx implemantation of the OPB interface.

Here are all the input signals to the mb_opb block.

Here are all the output signals from the mb_opb block.

OPB signal description

Signal Description Width
 Used in ETC
OPB_ABus Address bus
OPB_BE Data byte enable
OPB_beAck  OPB byte enable acknowledge
OPB_beXfer OPB byte enable transfer
OPB bus arbitration lock  1
OPB_Dbus OPB Ddata bus
OPB_dwAck OPB doubleword acknowledge  1
OPB_dwXfer OPB doubleword transfer
OPB_errAck OPB error acknowledge  1
Yes, always = 0
OPB fullword acknowledge
Yes, always = 0
OPB fullword transfer
OPB halfword acknowledge
OPB halfword transfer
OPB master bus grant
OPB Master bus request
OPB pending master request
OPB read data bus
OPB bus cycle retry
Yes, always = 0
OPB read not write (write=L)
OPB reset
OPB select
OPB sequential address
OPB timeout error
OPB timeout suppress
Yes, always = 0
OPB write data bus
OPB transfer acknowledge

Final result

It took me a couple of days to sort out all issues around the ETC OPB interface. Here is what I found out. Right or wrong?
  • The read and write cycles can be two or more clock cycles long. The OPB interface can decide how long the read and write cycles will be by asserting the OPB_xferAck in the last clock cycle. I am using 3 clock cycles in the ETC OPB interface.
  • The fullword and halfword control signals are not implemented in the Xilinx version of OPB. Use the signal OPB_BE instead. OPB_BE = 4'b1111 enable all four bytes when reading and writing 32 bit words.
  • Always keep the read data bus low when no valid read cycle is taking place. Read data busses from all peripherals are or'ed together in the mb_opb block and only one peripheral at a time can drive the bus high. Important !!!
  • You don't have to implement the signals OPB_errAck, OPB_toutSup and OPB_retry. I have set them all low.
Here is my OPB interface to the ETC block. Comments and improvements are welcomed.

Top  Next  Previous

Posted at 20:55 by svenand

November 20, 2007   09:11 AM PST
Excellent work man, I will recommend this page to my students

Leave a Comment:


Homepage (optional)


Previous Entry Home Next Entry