XE Files and parsing for boot loading

Technical questions regarding the XTC tools and programming with XMOS.
GerhardNorkus
Active Member
Posts: 55
Joined: Wed Jan 05, 2011 2:15 pm

XE Files and parsing for boot loading

Post by GerhardNorkus »

Hi All,

I have an SU1 device. I read the instructions in the Tools Developer Guide (1.0) regarding the XMOS XE File Format. I am successfully parsing and loading data into memory. When I attempt to process a Call or Goto sector, I have noticed a few interesting things....

1. Almost every xe file I create has code that seems to be the same as an initializing set of code. The length is 376 bytes and contains procedure calls to progSwitchRegBlind and _DoSyscall. When I load that code and jump to it's initial address it always hangs, repeatedly calling the _DoSyscall. This section of code is always the Loadable 1 for tile[0]. It's call/goto sector header does not properly spell out the jump address. It is always 0, whereas the load address is always 0x00010000, which is correct.

2. The code I have complied appears in Loadable 2 for tile[0]. The code runs, and I can do a debug halt on it and inspect the registers. When I am done loading it into memory, I calculate it's CRC and it matches the sector CRC. It actually runs, too, but I can't get the USB to enumerate.

The code I am trying to launch is a USB set of firmware. It enumerates properly when put into flash memory, or when launched via xgdb. However, when I copy the code into memory, and verify that the CRC matches what was stored, the SU1 device does not enumerate.

ANY CLUES AS TO THE FIRST LOADABLE and why it doesn't run properly? Can anyone describe to me the function of that First Loadable code?

ANY CLUES AS TO WHY MY USB program WILL NOT ALLOW THE ENUMERATION OF THE DEVICE?


Thanks,
GJN


User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Hi Gerhard,

The images in a XE file are those that you run if starting
your program via JTAG; normal boot uses different code
(created by xflash) that initialises everything from the boot
CPU. The images in a XE file are meant to start every CPU
separately.

I've never seen a XE file that has a wrong call/jump address.
Have a look at my runxe code to see if you maybe
parse something wrong? Or maybe it is the newest tools that
have a bug; or maybe I never noticed because I use the ELF
entry point instead. Dunno. Or maybe it only happens with
images for SU devices, I've never used those.

This first image sets up the network, that is, the links and
the routing table etc. One thing it does _not_ do, and what
probably is why USB won't work for you, is set up the PLL.
Writing to the PLL config resets the chip; that's why you
generally want to do that before starting the first image.
See runxe for an example what to do and where to find the
settings for your board (in the XE file).

If anything is not clear just ask :-)
GerhardNorkus
Active Member
Posts: 55
Joined: Wed Jan 05, 2011 2:15 pm

Post by GerhardNorkus »

Segher,

Thanks for your reply. You are correct in that this seems to be in the SU1 arena only at the moment. To see what I am talking about, create an empty project for the SU1, put a simple main() in it, and just do an xobjdump --sector-info yourfile.xe. You will see that the load address and the call address for the first sector and the first call do not match (load is 0x0001000 call is 0x00000000).

I received information from Henk Muller, and this has helped me get it working. He told me to ignore the first 376 byte loadable segment and put the PLL/USB Tile linking code into my 1 stage of my boot loader. Below is a copy of it. Simply create a normal XC project for an SU1 product with an Empty XC file and copy the code. No special compilation flags are needed. The uBinArr contains a binary that does the actual boot loading and is compiled to start at a higher address in memory. Also, the --nostdlib and --bootable flags in the mapper flags need to be set. My loader parses an xe file that has either been compiled with the --bootable flag, or has had xobjdump --strip executed on it. This gives only binary sectors, as I do not yet know how to parse ELF sectors (See the XMOS document "Tools Developer Guide" section 3.1.2).

This can be used to load literally from any device hooked up to an XMOS. Yeah, a little work is needed to make sure that all cores can be loaded properly, but I think anyone experienced with this (not me) will be able to make necessary changes...

My boot loader is loading from an 8 bit flash device. AND IT IS WORKING! : ) I can update my flash device at will and it takes the changes...

First Stage Boot Loader
YourLoader.xc

Code: Select all

// XMOS USB high memory bootloader and code injection manager…
// By Gerhard Norkus and Henk Muller
// Copyright 2013, Envisic LLC

#include <xs1.h>
#include "copycode.h"

// Injection code to be put at a high level in memory.  These bytes are the second stage
// boot loader.
unsigned short uBinArr[1616] = { 0x7741,...,0x0001};

long SetPLLFreq()
{
    unsigned int pllCtrlReadData;
    unsigned int tile_id = get_local_tile_id();

    // Henk recommended that the tile_id be hardwired to 0 for the 
    // SU1 devices.  
    read_sswitch_reg(tile_id, XS1_L_SSWITCH_PLL_CTL_NUM, pllCtrlReadData);
    if (pllCtrlReadData != 0x00007C02)
        write_sswitch_reg(tile_id, XS1_L_SSWITCH_PLL_CTL_NUM, 0x00007C02);
    write_sswitch_reg(tile_id, XS1_L_SSWITCH_REF_CLK_DIVIDER_NUM, 4);
    
    // Added code from Henk Muller here!
    write_sswitch_reg(0, 0x85, 0xc0019832);    // Enable USB tile link
    write_sswitch_reg(0, 0x85, 0xc1019832);    // Say hello
    write_sswitch_reg(1, 0x80, 0xc1000000);    // Make back link say hello
    write_sswitch_reg(1, 0x51, 0x18);          // Program 24 MHz in USB tile speed

    return 1 ;
}

int main(void)
{
    unsigned long t ;

    SetPLLFreq();
    CopyCode(0x1c000, 1616, uBinArr);
    while (1)
    {
    }
    return 0 ;
}
Binary Copy and Call Code
CopyCode.S (make sure the 'S' is capitalized!)

Code: Select all

// Copy binary executable and call code
// By Gerhard Norkus
// Copyright 2013, Envisic LLC 
       .text
       .align 2
// Contents of CopyCode.S
      .globl  CopyCode
        .align  2
        .type   CopyCode,@function
        .set    CopyCode.nstackwords,0
        .globl  CopyCode.nstackwords
        .cc_top CopyCode.function
CopyCode:
    entsp 0

        sub r1, r1, 1
        ld16s r3, r2[r1]
        st16 r3, r0[r1]
        bt r1, CopyCode

        bla r0
        retsp 0
        .cc_bottom CopyCode.function



Binary Copy and Call Code header
CopyCode.h

Code: Select all

// Copy binary executable and call code
// By Gerhard Norkus
// Copyright 2013, Envisic LLC 
#ifndef _copycode_h
#define _copycode_h

#ifdef __XC__
void CopyCode(int nJumpLoc, int nCodeLen, unsigned short uBinArr[]);
#else
void CopyCode(int nJumpLoc, int nCodeLen, unsigned short *uBinArr);
#endif

#endif
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am

Post by segher »

Ah yes, you need to put the USB tile in the network as well :-)
Congratulations that it is working now!

About your asm... You do "entsp 0", which doesn't do anything;
which is good, because you put it inside the loop. Oops.
Then you do a "bla" followed by "retsp 0", which means that
last instruction will behave like "bu .", likely not what you
had in mind, although that is exactly what the code you want
to return to will do! Usual code would be "entsp 1"/"retsp 1",
with the entsp outside of the loop.
GerhardNorkus
Active Member
Posts: 55
Joined: Wed Jan 05, 2011 2:15 pm

Post by GerhardNorkus »

Doh.
Yeah. Just put in a different loop label just after tge entsp