-- MathiasKreider - 07 May 2015

Getting Information about the Firmware on a device

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]));
}


Topic revision: r3 - 11 May 2015, MathiasKreider
This site is powered by FoswikiCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Foswiki? Send feedback