--
MathiasKreider - 07 May 2015
Firmware IDs
The eb-info tool was used to read out the build-id ROM, providing information on the device's gateware.
The build process and eb-info have been extended to provide the same service for firmware as well.
At compilation time, information on the firmware are gathered and compiled into the binary at a fixed offset.
The format is a zero terminated ASCII string.
Field |
UserLM32 |
Project |
Version |
Platform |
Build Date |
Prepared by |
Prepared on |
OS Version |
GCC Version |
CFLAGS |
Build-ID will contain |
Description |
Magic Word |
project name |
version x.y.z |
FPGA |
"" |
user & email |
computer name |
"" |
"" |
compiler flags |
Last 5 Git commits |
memory map of the LM32 ram
address |
section |
description |
size (Byte) |
0x0 |
.boot |
LM32 bootcode |
256 |
0x100 |
.buildid |
build information of the program loaded in memory |
1024 |
0x500 |
.shared |
user specific shared section |
x |
0x500 + x |
.text |
program code |
y |
For more details on how to read out a Firmware ID with the Etherbone Library,
have a look at the source code of the
eb-info tool.
How to use eb-info
The parameter to show also firmware IDs is -w
Here is part of example output:
~/$ eb-info -w dev/ttyUSB0
...
Detecting Firmwares ... Found 4 RAMs, 4 holding a Firmware ID
RAM @ 0x00320000:
UserLM32
Project : ftm
Version : 1.0.0
Platform :
Build Date : Wed May 06 10:32:25 CEST 2015
Prepared by : mkreider Mathias Kreider <m.kreider@gsi.de>
Prepared on : Starburst
OS Version : Ubuntu 13.04 Linux 3.8.0-30-generic x86_64
GCC Version : lm32-elf-gcc (GCC) 4.5.3
CFLAGS : -I../../../modules/ftm/ftmfw -mmultiply-enabled -mbarrel-shift-enabled -Os -DUSRCPUCLK=125000 -I../../../modules/lm32-include -I../../../ip_cores/wrpc-sw/include -I../../../ip_cores/wrpc-sw/pp_printf -std=gnu99
Build-ID will contain:
c01a8c2 ftm: Changed firmware to newest dev version
8ff6d81 ftm: Added build config for FTM (syn/top)
e889dc7 scu_sw: irq endpoints now found by cpu id and number of msi endpoints
1ceebb4 build-process: Made all toplevel Manifests compatible with new versions of hdlmake
0c23477 lm32-cluster, build-process: added framework for fw ID block and new SDBs
...
Indidualized SDBs
SDBs for the LM32 periphery
There are now five new SDB tags available, distinctively marking important User-LM32 components. The new tags are:
Name |
Vendor |
Device |
Description |
LM32-CB-Cluster |
0x00000651 |
0x10041000 |
The main crossbar of the User-LM32 cluster |
LM32-RAM-Shared |
0x00000651 |
0x81111444 |
Shared Memory in the cluster for all user LM32s |
LM32-RAM-User |
0x00000651 |
0x54111351 |
Memory of a single user LM32 |
LM32-IRQ-EP |
0x00000651 |
0x10050083 |
An MSI endpoint of a user LM32 |
Cluster-Info-ROM |
0x00000651 |
0x10040086 |
ROM containing information about the cluster layout |
How do I find the right RAM for CPU m?
CPUs are enumerated 0..M-1. In order to find the RAM of a certain CPU,
you need a list of all User-LM32 RAMs. The indices of the SDBs in the
resulting array correspond to the CPU indices.
Here is an example of how to find the address of the RAM for CPU 2.
...
#define GSI_ID 0x651
#define RAM_ID 0x54111351
#define MAX_RAMS 10
struct sdb_device sdb[MAX_RAMS];
...
c = MAX_RAMS;
unsigned char theCpuIseek = 2;
//find all User-LM32 rams
if ((status = eb_sdb_find_by_identity(device, GSI_ID, RAM_ID, &sdb[0], &c)) != EB_OK)
die("eb_sdb_find_by_identity", status);
if(theCpuIseek < c) printf("RAM %u @ 0x%08x: \n\n", theCpuIseek, (unsigned int)sdb[i].sdb_component.addr_first);
else printf("Sorry, only found %u RAMs\n", c);
How do I find the right MSI endpoints for CPU m?
From the outside world:
It is important to know the cluster configuration first.
For this purpose, every
UserLM32 cluster has a unique wishbone device, the Cluster-Info-ROM.
In here, information on the layout is available can be used to sort through the cluster periphery.
Cluster-Info-ROM, VenID 0x651, DevID 0x10040086 |
Addr |
Content |
0x00 |
Number of LM32 cores |
0x04 |
Number of MSI endpoints per core |
0x08 |
Memory space per core (byte) |
0x10 |
Shared cluster memory space (byte) |
0x14 |
Configured as DataMaster (1 yes/0 no) |
The MSI endpoints are enumerated per core. If you search for the MSI Endpoints,
you will find them more than once in different crossbars. This is normal and nothing to worry about.
The order in which they will be retrieved is according to the core order and is the same for
all crossbars the MSI endpoints appear in.
M Number of cores
N Number of MSIs
m Core index 0..M-1
n MSI index 0..N-1
This means, if the number of cores is
M=2 and the number of MSIs is
N=3, eb_sdb_find_by_identity will return the following order:
ArrayIdx |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
Core |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
... |
MSI |
0 |
1 |
2 |
0 |
1 |
2 |
1 |
... |
IdxMSI(m,n) = m · N + n
Example: The third MSI endpoint (n=2) of the second core (m=1) can be found at Array Index 5
m · N + n = 1 · 3 + 2 = 5
From inside an LM32:
This can be done easily in a similar way as from outside.
The necessary information is also available in ROM for each CPU, providing its index and number of MSI endpoints.
CPU-Info-ROM, VenID 0x651, DevID 0x10040085 |
Addr |
Content |
0x00 |
CPU ID. bits 31..8 ID string, bits 7..0 Index |
0x04 |
Number of MSI endpoints |
0x08 |
Memory space (byte) |
0x10 |
Part of a cluster (1 yes / 0 no) |
IdxMSI(m,n) = m · N + n
If an LM32 needs to find it's own endpoints, it can use its own index from the CPU Info ROM.
If it needs to target another core, the targeted core index
mmust be provided by the programmer.
Example from SCU Function Generator firmware on how to discover an LM32's MSI endpoints:
...
cpu_info_base = (unsigned int*)find_device_adr(GSI, CPU_INFO_ROM);
find_device_multi(&found_sdb[0], &clu_cb_idx, 20, GSI, LM32_CB_CLUSTER); // find location of cluster crossbar
find_device_multi_in_subtree(&found_sdb[0], lm32_irq_endp, &lm32_endp_idx, 10, GSI, LM32_IRQ_EP); // list irq endpoints in cluster crossbar
if(cpu_info_base) {
mprintf("CPU ID: 0x%x\n", cpu_info_base[0]);
mprintf("number of MSI endpoints: %u\n", cpu_info_base[1]);
} else
mprintf("no CPU INFO ROM found!\n");
}
endp_idx = (cpu_info_base[0] & 0xff) * cpu_info_base[1]; // calculate start index from CPU Idx and number of endpoints
mprintf("number of lm32_irq_endpoints found: %d\n", lm32_endp_idx);
for (i=endp_idx; i < endp_idx + cpu_info_base[1]; i++) {
mprintf("my irq_endp[%d] is: 0x%x\n",i, getSdbAdr(&lm32_irq_endp[i]));
}