One led per core/thread

All technical discussions and projects around startKIT
dwelch67
Member++
Posts: 22
Joined: Thu Jun 16, 2011 9:01 pm

Post by dwelch67 »

kep still doesnt appear to matter, it never gets called anyway? (and, why would waiteu, waiting on an event, cause a kernel call).


Code: Select all

_start:

    ldc r0,0
    ldc r1,0
    ldc r2,0
    ldc r3,0
    ldc r4,0
    ldc r5,0
    ldc r6,0
    ldc r7,0
    ldc r8,0
    ldc r9,0
    ldc r10,0
    ldc r11,0

    ldc r11,0x00B
    get r10,ps[r11]     # get ram base
    ldc r11,0x10B
    set ps[r11],r10     # set vector base (to match ram base)

    ldc  r11, 0x6       # the I/O ports need a clock
    setc res[r11], 0x8  # setci
    setc res[r11], 0xf  # setci

    ldap r11,kep_handler
    set kep,r11

    # define XS1_PORT_32A 0x200000
    ldc r8,0x2000
    shl r8,r8,8
    setc res[r8],0x8    # turn the port on
    ldc r1,0x6          # give it a clock
    setclk res[r8],r1


setup_resources:
    getr r3,1           # define XS1_RES_TYPE_TIMER 0x1

    ldap r11,tmr_vec
    setv res[r3],r11

    ldc r10,256
    setd res[r3],r10
    setc res[r3],0x9    # define XS1_SETC_COND_AFTER 0x9

    setc res[r3],0x2    # define XS1_SETC_IE_MODE_EVENT 0x2

    ldc r0,0x1234

    clre
    eeu res[r3]
    waiteu


tmr_vec:
    ldc r10,0xABCD
    out res[r8],r10
    freer res[r3]
    ldc r0,0
    clre
    waiteu

    .align 0x20
kep_handler:
    clre
    waiteu
in xc generated code kep is set to _TrapHandler which branches to _DoException which is a clre/waiteu

I used freer, clre, waiteu at the end of my event handler to simply stop simulator output, let it run into max cycles.

The reason why I keep asking about this operating system call thing is because it keeps coming out of the simulator at the time of the event. with r0 set to 0x1234 as above then you get unimplemented OS call '4660'

Code: Select all

tile[0]@0- -A-.----00010000 (_start              +  0) : ldc     r0(0x0), 0x0 @5
tile[0]@0- -A-.----00010002 (_start              +  2) : ldc     r1(0x0), 0x0 @9
tile[0]@0- -A-.----00010004 (_start              +  4) : ldc     r2(0x0), 0x0 @13
tile[0]@0- -A-.----00010006 (_start              +  6) : ldc     r3(0x0), 0x0 @17
tile[0]@0- -A-.----00010008 (_start              +  8) : ldc     r4(0x0), 0x0 @21
tile[0]@0- -A-.----0001000a (_start              +  a) : ldc     r5(0x0), 0x0 @25
tile[0]@0- -A-.----0001000c (_start              +  c) : ldc     r6(0x0), 0x0 @29
tile[0]@0- -A-.----0001000e (_start              +  e) : ldc     r7(0x0), 0x0 @33
tile[0]@0- -A-.----00010010 (_start              + 10) : ldc     r8(0x0), 0x0 @37
tile[0]@0- -A-.----00010012 (_start              + 12) : ldc     r9(0x0), 0x0 @41
tile[0]@0- -A-.----00010014 (_start              + 14) : ldc     r10(0x0), 0x0 @45
tile[0]@0- -A-.----00010016 (_start              + 16) : ldc     r11(0x0), 0x0 @49
tile[0]@0- -A-.----00010018 (_start              + 18) : ldc     r11(0xb), 0xb @53
tile[0]@0- -A-.----0001001a (_start              + 1a) : get     r10(0x10000), ps[r11(0xb)] @57
tile[0]@0- -A-.----0001001e (_start              + 1e) : ldc     r11(0x10b), 0x10b @65
tile[0]@0- -A-.----00010022 (_start              + 22) : set     ps[r11(0x10b)], r10(0x10000) @73
tile[0]@0- -A-.----00010026 (_start              + 26) : ldc     r11(0x6), 0x6 @77
tile[0]@0- -A-.----00010028 (_start              + 28) : setc    res[r11(0x6)], 0x8 @81
tile[0]@0- -A-.----0001002a (_start              + 2a) : setc    res[r11(0x6)], 0xf @85
tile[0]@0- -A-.----0001002c (_start              + 2c) : ldap    r11(0x10080), 0x29 @89
tile[0]@0- -A-.----0001002e (_start              + 2e) : set     kep(0x10080), r11(0x10080) @93
tile[0]@0- -A-.----00010030 (_start              + 30) : ldc     r8(0x2000), 0x2000 @97
tile[0]@0- -A-.----00010034 (_start              + 34) : shl     r8(0x200000), r8(0x2000), 0x8 @101
tile[0]@0- -A-.----00010036 (_start              + 36) : setc    res[r8(0x200000)], 0x8 @105
tile[0]@0- -A-.----00010038 (_start              + 38) : ldc     r1(0x6), 0x6 @109
tile[0]@0- -A-.----0001003a (_start              + 3a) : setclk  res[r8(0x200000)], r1(0x6) @113
tile[0]@0- -A-.----0001003e (setup_resources     +  0) : getr    r3(0x1), 0x1 @117
tile[0]@0- -A-.----00010040 (setup_resources     +  2) : ldap    r11(0x10058), 0xb @121
tile[0]@0- -A-.----00010042 (setup_resources     +  4) : setv    res[r3(0x1)], r11(0x10058) @125
tile[0]@0- -A-.----00010044 (setup_resources     +  6) : ldc     r10(0x100), 0x100 @129
tile[0]@0- -A-.----00010048 (setup_resources     +  a) : setd    res[r3(0x1)], r10(0x100) @133
tile[0]@0- -A-.----0001004a (setup_resources     +  c) : setc    res[r3(0x1)], 0x9 @137
tile[0]@0- -A-.----0001004c (setup_resources     +  e) : setc    res[r3(0x1)], 0x2 @141
tile[0]@0- -A-.----0001004e (setup_resources     + 10) : ldc     r0(0x1234), 0x1234 @145
tile[0]@0- -A-.----00010052 (setup_resources     + 14) : clre     @149
tile[0]@0- -A-.----00010054 (setup_resources     + 16) : eeu     res[r3(0x1)] @153
tile[0]@0-P-A-.----00010056 (setup_resources     + 18) : waiteu   @157
tile[0]@0Event caused by res 0x00000001, V=0x00010058, EV=0x00000001 @1285
xsim: error: C31182: unimplemented OS call '4660'
I certainly understand that could be a symptom not the problem...I still dont understand where this operating system is and why isnt it xcore instructions? It still has the taste of the code is running into some system call to the simulator.

The two loads makes sense, do both loads live in flash and there is some mechanism (in hardware) that loads and runs the first one then stops, loads the second one and resets the pc to run it? Or is the second load something done with code from the first or something along those lines?

Thanks,
David


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

Post by segher »

dwelch67 wrote:kep still doesnt appear to matter, it never gets called anyway?  (and, why would waiteu, waiting on an event, cause a kernel call).
Exceptions use KEP as well (KEP+0x40). The required alignment
is 64 as well btw.

Code: Select all

tile[0]@0Event caused by res 0x00000001, V=0x00010058, EV=0x00000001 @1285
xsim: error: C31182: unimplemented OS call '4660'
Reading the log carefully this time (sorry!), it is clear that
the simulator did take the event you wanted it to take, and
then tried to emulate a system call. This is explained in
https://www.xmos.com/download/public/ap ... rc0.a).pdf, but that doc also
seems to say that it detects KCALL by looking if you jumped
to where the handler normally is (instead of just looking
at the instruction that causes it)?!

It seems you found a bug in the simulator. Joy.
The two loads makes sense, do both loads live in flash and there is some mechanism (in hardware) that loads and runs the first one then stops, loads the second one and resets the pc to run it?  Or is the second load something done with code from the first or something along those lines?
When you use JTAG to run your code, nothing lives in flash.
When you boot from SPI, different code is run to do the
setup and distribute all the program images to the processors.
That code is written by xflash.
dwelch67
Member++
Posts: 22
Joined: Thu Jun 16, 2011 9:01 pm

Post by dwelch67 »

kep wasnt needed to make the simulator run. didnt know the alignment, in an xcc generated binary it was at 0x10080, I made mine match. tried setting cp and dp and sp, nothing helped until I added

Code: Select all

#_DoSyscall: #.word 0x77C0A6D0
_DoSyscall:
    mkmsk r0,0x20
    retsp 0x0
Actually with further experiments, the code after that _DoSyscall label doesnt seem to matter

Code: Select all

_DoSyscall:
    bu _DoSyscall
Simply adding _DoSyscall makes the sim happy.

Thanks for all the help! In theory I have all the pieces and parts to see something (what I started on with this thread) happen in sim and then move to silicon, and hopefully that is a smooth transition.

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

Post by segher »

Ah cool! So it looks like it actually detects _DoSyscall, and
only when that symbol does not exist it does strange things.

Great to hear you're making real progress now, have a lot
of fun,

Segher
dwelch67
Member++
Posts: 22
Joined: Thu Jun 16, 2011 9:01 pm

Post by dwelch67 »

This appears to be working...one thread owns the resource for port 32a. In this case four other threads use their own timers to ask thread0 to change one of the bits (a different bit for each thread), giving the illusion (real via a proxy) that the four threads each are controlling one of the por32a bits (one led per thread).

Code: Select all

_start:

    ldc r0,0
    ldc r1,0
    ldc r2,0
    ldc r3,0
    ldc r4,0
    ldc r5,0
    ldc r6,0
    ldc r7,0
    ldc r8,0
    ldc r9,0
    ldc r10,0
    ldc r11,0

    ldc r11,0x00B
    get r10,ps[r11]     # get ram base
    ldc r11,0x10B
    set ps[r11],r10     # set vector base (to match ram base)

    ldc  r11, 0x6       # the I/O ports need a clock
    setc res[r11], 0x8  # setci
    setc res[r11], 0xf  # setci

    clre

    getr r1,0x3         # get a synchronizer

    #-------------
    getst r0,res[r1]    # allocate a thread
    ldap r11,slave    # get address for the code for new thread
    init t[r0]:pc,r11   # set pc for new thread

    getr r2,2           # allocate a channel end for thread 0
    getr r3,2           # allocate a channel end for thread 1
    setd res[r2],r3     # point one end at the other
    setd res[r3],r2     # point one end at the other
    set t[r0]:r6,r3     # set a thread register with one end
    ldc r10,0x58
    set t[r0]:r4,r10
    ldc r10,0x0001
    set t[r0]:r10,r10
    ldap r11,t0hand
    setv res[r2],r11
    mov r11,r2
    setev res[r2],r11
    eeu res[r2]         # wake up on this resources event
    #-------------


    #-------------
    getst r0,res[r1]    # allocate a thread
    ldap r11,slave    # get address for the code for new thread
    init t[r0]:pc,r11   # set pc for new thread

    getr r2,2           # allocate a channel end for thread 0
    getr r3,2           # allocate a channel end for thread 1
    setd res[r2],r3     # point one end at the other
    setd res[r3],r2     # point one end at the other
    set t[r0]:r6,r3     # set a thread register with one end
    ldc r10,0x50
    set t[r0]:r4,r10
    ldc r10,0x0010
    set t[r0]:r10,r10
    ldap r11,t0hand
    setv res[r2],r11
    mov r11,r2
    setev res[r2],r11
    eeu res[r2]         # wake up on this resources event
    #-------------


    #-------------
    getst r0,res[r1]    # allocate a thread
    ldap r11,slave    # get address for the code for new thread
    init t[r0]:pc,r11   # set pc for new thread

    getr r2,2           # allocate a channel end for thread 0
    getr r3,2           # allocate a channel end for thread 1
    setd res[r2],r3     # point one end at the other
    setd res[r3],r2     # point one end at the other
    set t[r0]:r6,r3     # set a thread register with one end
    ldc r10,0x48
    set t[r0]:r4,r10
    ldc r10,0x0100
    set t[r0]:r10,r10
    ldap r11,t0hand
    setv res[r2],r11
    mov r11,r2
    setev res[r2],r11
    eeu res[r2]         # wake up on this resources event
    #-------------


    #-------------
    getst r0,res[r1]    # allocate a thread
    ldap r11,slave    # get address for the code for new thread
    init t[r0]:pc,r11   # set pc for new thread

    getr r2,2           # allocate a channel end for thread 0
    getr r3,2           # allocate a channel end for thread 1
    setd res[r2],r3     # point one end at the other
    setd res[r3],r2     # point one end at the other
    set t[r0]:r6,r3     # set a thread register with one end
    ldc r10,0x40
    set t[r0]:r4,r10
    ldc r10,0x1000
    set t[r0]:r10,r10
    ldap r11,t0hand
    setv res[r2],r11
    mov r11,r2
    setev res[r2],r11
    eeu res[r2]         # wake up on this resources event
    #-------------

    msync res[r1]       # start all allocated threads

    # define XS1_PORT_32A 0x200000
    ldc r8,0x2000
    shl r8,r8,8
    setc res[r8],0x8    # turn the port on
    ldc r1,0x6          # give it a clock
    setclk res[r8],r1
    ldc r2,0
    out res[r8],r2

    waiteu              # wait for an event to happen, then go to the handler

t0hand:
    get r11,ed
    mov r5,r11
    in r10,res[r5]
    xor r2,r2,r10
    out res[r8],r2
    outct res[r5],1     # send control token
    waiteu


slave:
    getr r2,0x1         # get a timer resource handle
    setc res[r2],0x1    # set to UNCOND (COND_NONE)
    in r3,res[r2]       # get current count, does not wait in this mode
    setc res[r2],0x9    # switch to AFTER mode (COND_AFTER)
sloop:
    add r3,r3,r4        # compute next timeout value
    setd res[r2],r3     # set the timeout value
    in r7,res[r2]       # wait for timeout value
    out res[r6],r10     # send something to thread 0
    chkct res[r6],1     # wait for control token
    bu sloop


# Any instance of _DoSyscall seems to make the simulator happy when
# using waiteu.  I still dont know why waiteu matters and not kcall
# or dcall
#_DoSyscall: #.word 0x77C0A6D0
#_DoSyscall:
#    mkmsk r0,0x20
#    retsp 0
_DoSyscall:
    bu _DoSyscall
User avatar
segher
XCore Expert
Posts: 844
Joined: Sun Jul 11, 2010 1:31 am
Contact:

Post by segher »

That looks all correct. Did you try it on hardware?
dwelch67
Member++
Posts: 22
Joined: Thu Jun 16, 2011 9:01 pm

Post by dwelch67 »

Yep, works great, changed the bits and the timeouts, otherwise unmodified, and ran it on a startKIT.

Thanks again, happy new year.
Post Reply