Merging BRAM Data Into Bitstreams
Introduction
This text is a short discussion of a way to merge BRAM initialization
data into bitstreams for Xilinx FPGAs. My intention was to avoid the
lengthy resynthesis plus P&R of whole designs when the software
code inside a BRAM has changed.
Browsing through the Xilinx flow docs revealed a tool called data2mem which promises to take BRAM
initialization data and merge this into a previously generated .bit
configuration file. Unfortunately, the available information is quite
brief so a couple of trial-and-error iterations had to be run through
until I got everything working as expected. Following you'll find some
notes about what I found out so far.
Starting Point
Everything below was done with Xilinx WebPACK 8.1-2, torturing a Spartan 3
device (xc3s1000-4-fg456 to be precise). The design contains a Z80
core (T80
from opencores.org) which
fetches its code from a 4 k ROM located at address 0x0000 on the
processor bus. For developing code, SDCC is in place while srecord is used to
postprocess the binary and hex files.
It has proven necessary to partition the 4 k ROM into two
RAMB16_S9 primitives instantiated directly in the VHDL design
hierarchy. Assigning them unambiguous instance names - here they will
be called rom_low_b and rom_high_b. I
didn't take measures to initialize them directly in the VHDL code. Just
for the reason to have a clean and empty configuration bit-file as a
starting point.
Preparing data2mem
Basically, one requires two inputs for data2mem:
- Initialization code in "MEM" format.
- A so called "BMM" file describing the internal memory layout.
First, I thought that converting my binaries or hex-files to this MEM
format might be the biggest obstacle. But soon I discovered that MEM
is simply the Verilog VMEM format, commonly used in the Verilog world
of designing. Glad to see that srecord supports this
format for reading and writing. So all that is needed fits in one
single command line:
$ srec_cat rom_code.bin
-binary -o rom_code.mem -vmem 8
It's maybe worth noting that rom_code.bin has been filled
to the full 4 k using srec_cat's -fill option.
Generating the BMM file resulted in a lot more guesswork because I
could not find an exhaustive documentation for these files.
Starting from data2mem -h, I experimented with the -mf
option until the tool produced something that looked reasonable.
$ data2mem -mf p z80map PPC405
0 \
a rom_code b 0x0000 8 \
s RAMB16 0x0800 8 rom_low_b \
s RAMB16 0x0800 8 rom_high_b \
-o p
rom_code.bmm
The result is
// BMM LOC
annotation
file.
//
// Release 8.1.02i - Data2MEM I.27, build 1.4.5 Jan 11, 2006
// Copyright (c) 1995-2006 Xilinx, Inc. All rights reserved.
//
// Created on 08/21/06 01:26 am
//
///////////////////////////////////////////////////////////////////////////////
//
// Processor 'z80map', ID 0, memory map.
//
///////////////////////////////////////////////////////////////////////////////
ADDRESS_MAP z80map PPC405 0
///////////////////////////////////////////////////////////////////////////////
//
// Processor 'z80map' address space 'rom_code'
0x00000000:0x00000FFF (4 KB).
//
///////////////////////////////////////////////////////////////////////////////
ADDRESS_SPACE rom_code COMBINED
[0x00000000:0x00000FFF]
///////////////////////////////////////////////////////////////////////////////
//
// Address range
0x00000000:0x000007FF (2 KB).
//
///////////////////////////////////////////////////////////////////////////////
ADDRESS_RANGE RAMB16
BUS_BLOCK
rom_low_b0 [7:0];
END_BUS_BLOCK;
END_ADDRESS_RANGE;
///////////////////////////////////////////////////////////////////////////////
//
// Address range
0x00000800:0x00000FFF (2 KB).
//
///////////////////////////////////////////////////////////////////////////////
ADDRESS_RANGE RAMB16
BUS_BLOCK
rom_high_b0 [7:0];
END_BUS_BLOCK;
END_ADDRESS_RANGE;
END_ADDRESS_SPACE;
END_ADDRESS_MAP;
Data2mem appends a 0 to the instance names which has to be removed before
adding the file to the ISE project. Bitgen is then supposed to annotate
the location of the two BRAMs to this file. In fact, bitgen copies the
contents of this file to rom_code_bd.bmm and inserts PLACED = X1Y6
attributes to the rom_low_b
lines. Unfortunately, bitgen annotates only the first instance and
skips rom_high_b for some reason.
After fiddeling with the file, I could find a combination that finally
works. Just merge the two separate ADDRESS_RANGE
definitions into a single one:
// BMM LOC
annotation
file.
//
// Release 8.1.02i - Data2MEM I.27, build 1.4.5 Jan 11, 2006
// Copyright (c) 1995-2006 Xilinx, Inc. All rights reserved.
//
// Created on 08/21/06 01:26 am
//
///////////////////////////////////////////////////////////////////////////////
//
// Processor 'z80map', ID 0, memory map.
//
///////////////////////////////////////////////////////////////////////////////
ADDRESS_MAP z80map PPC405 0
///////////////////////////////////////////////////////////////////////////////
//
// Processor 'z80map' address space 'rom_code'
0x00000000:0x00000FFF (4 KB).
//
///////////////////////////////////////////////////////////////////////////////
ADDRESS_SPACE rom_code COMBINED
[0x00000000:0x00000FFF]
///////////////////////////////////////////////////////////////////////////////
//
// Address range
0x00000000:0x000007FF (2 KB).
//
///////////////////////////////////////////////////////////////////////////////
ADDRESS_RANGE RAMB16
BUS_BLOCK
rom_low_b [7:0];
END_BUS_BLOCK;
///////////////////////////////////////////////////////////////////////////////
//
// Address range
0x00000800:0x00000FFF (2 KB).
//
///////////////////////////////////////////////////////////////////////////////
BUS_BLOCK
rom_high_b [7:0];
END_BUS_BLOCK;
END_ADDRESS_RANGE;
END_ADDRESS_SPACE;
END_ADDRESS_MAP;
Now bitgen assigns the locations properly to each of the RAMB16
instances:
rom_low_b [7:0] PLACED = X1Y6;
...
rom_high_b [7:0] PLACED = X1Y7;
Running data2mem
As written above, bitgen generates an annotated BMM file named rom_code_bd.bmm
that will be used for the further steps with data2mem. First, one can
inspect the initial bit-file and check the configuration contents of
the BRAMs in there:
$ data2mem -bm rom_code_bd.bmm
-bt design.bit -d > design.txt
The BRAMs identified by rom_code_bd.bmm will be marked
inside design.txt so it's easy to see their contents is
all 0 for now.
Finally merging rom_code.mem into the bit-file is a pice
of cake:
$ data2mem -bm rom_code_bd.bmm
-bt design.bit -bd rom_code.mem -o b final.bit
A quick check with data2mem -d on final.bit
reveals that the BRAMs contain the requested data. Done.
--
August 2006
Arnim Läuger
arnim.laeuger <at> gmx.net
Back
to main