I am liking the http://www.xmos.com chips but want to get a lower level understanding of what is going on. Basically assembler. I am trying to sort out something as simple as an led blinker, set the led, count to N clear the led, count to N, loop forever.
Sure I can disassemble a 10 line XC program, but if you have tried that you will see there is a lot of bloat in there that is in every program, what bits are to support the compiler output and what bits are actually setting up the gpio?
EDIT:
XC code
#include out port bled = PORT_BUTTONLED ; int main () { bled <: 0b0011 ; while (1) ; return 0; }
Commands to build
source SetEnv xcc bob.xc -target=XC-1A -o bob.xe xsim --max-cycles 2000 --vcd-tracing "-o bob.vcd -ports -cycles -threads -timers -instructions -functions" bob.xe
EDIT 5
Here is the answer
.globl _start _start: ldc r0,4 ldc r2,8 ldc r3,16 ldc r1, 100 notmain: sub r1,r1,1 bt r1, notmain ldap r11,constants set dp,r11 ldc r3, 0x6 setc res[r3], 0x8 setc res[r3], 0xf ldw r3,dp[0x0] setc res[r3],0x8 ldc r1,0x6 setclk res[r3],r1 top: ldc r0, 0x8 out res[r3], r0 bl delay ldc r0, 0x4 out res[r3], r0 bl delay ldc r0, 0x2 out res[r3], r0 bl delay ldc r0, 0x1 out res[r3], r0 bl delay ldc r0, 0x2 out res[r3], r0 bl delay ldc r0, 0x4 out res[r3], r0 bl delay bu top constants: .word 0x00040200 delay: ldc r2, 1000 da: ldc r1, 10000 db: sub r1,r1,1 bt r1, db sub r2,r2,1 bt r2, da retsp 0x0
building and loading the above assembler m.s:
xcc m.s -target=XC-1A -nostartfiles -o m.xe xrun m.xe
you can sim and look at the pads/pins of the chip if you get rid of the delays so that you can see something happen in a reasonable length sim
xsim --max-cycles 2000 --vcd-tracing "-o m.vcd -ports -cycles -threads -timers -instructions -functions -pads" m.xe
but gtkwave doesnt like the syntax so to view that m.vcd file with gtkwave I have to edit the .vcd file and
from: $var wire 1 paa10 0:X0D61 $end to: $var wire 1 paa10 X0D61 $end
Basically remove the 0: for all the paa variable definition lines.
With the above assembler x0d14, x0d15, x0d19, x0d20 are the pads that wiggle can see the connection from their documentation.
That magic number comes from an include file:
#define XS1_PORT_4C 0x40200
EDIT 6
Henk, thanks for jumping in to help. I was reviewing how far I had gotten and didnt understand the 0x6 and the setclk stuff and was going to have to re-ask a question or dig deeper. The code below does start to wiggle the port but then the xcore appears to do a thread swap and hang essentially, so it still isnt quite the simple program I was hoping for. And I understand this isnt a simple core (which is why I want to understand it at this level to make the most out of it).
.globl _start _start: ldc r1, 100 notmain: sub r1,r1,1 bt r1, notmain ldc r3,0x4020 shl r3,r3,4 setc res[r3],0x8 top: ldc r0, 0x8 out res[r3], r0 ldc r0, 0x4 out res[r3], r0 ldc r0, 0x2 out res[r3], r0 ldc r0, 0x1 out res[r3], r0 ldc r0, 0x2 out res[r3], r0 ldc r0, 0x4 out res[r3], r0 bu top
Post the assembly and I'll look through it for you. Sounds interesting.
Edit:
0x000100ac: 00 f0 45 58: ldw (lru6) r1, dp[0x5]
0x000100b0: d2 a6: mkmsk (rus) r0, 0x2
0x000100b2: c1 ae: out (r2r) res[r1], r0
I think this is the part that your looking for. I'll need to find an XMOS reference manual but based on the control-flow in main this must be the part that accesses the bled channel. To confirm it you could add a flag into the XC code and flip the LED in the while loop. This should add a similar access to the above into the assembly output.
According to the Instruction Set Reference (pg 123) the first operand for out is the port and the second is the data. The dp[0x5]
operand looks like it is taking the handle for the port out of some kind of global bank and then using to look up the associated resource.
A man in the know suggested to me that you try -O2 to clean up the code. If you're trying to follow what is going on I would skip all of the initialisation code, it is always a mess on most platforms. If you just concentrate on the lines between the main label and the next procedure (DoException
) then you should see a manageable amount of code that maps onto the part that you have written. The smaller btxx
labels are jump targets for control constructs (while loops, if statements).
Assuming you program the machine raw, you need to get the port ID, which you can find in the xs1.h include file in the tools.
Load that port ID in a register, then use SETC to switch the port on, and use OUT to drive a value onto the port. Setting the clock of the port should not be necessary. Assuming you are using port 0x10000 the following sequence should give you a very short pulse. Use a timer to get a longer pulse; if you use a loop, the actual time depends on the clock speed of the processor and the number of threads. The timer gives you real time.
ldc r0, 1
shl r0, r0, 16 // Makes 0x10000
setc res[r0], 8
ldc r1, 1
out res[r0], r1
ldc r1, 0
out res[r0], r1
Hope this helps...
Sorry, yes, you need to switch the reference clock block on and start it. So you need the three lines that I added to the program.
A resource of the form 0x00000y06 is clock block y, so 0x6 refers to clock block 0. setc 8 switches it on, setc 0xf sets the clock running. When the clock is "on" but not "running" (inbetween the setc 8 and setc 0xf) you can do things like change the divider setting. Uncomment the two lines to give the clock a divider, which will slow down the outs.
.globl _start
_start:
ldc r1, 100
notmain:
sub r1,r1,1
bt r1, notmain
ldc r3,0x4020
shl r3,r3,4
setc res[r3],0x8
ldc r1,0x6
setc res[r1],0x8
// ldc r2, 8
// setd res[r1], r2
setc res[r1],0xf
top:
ldc r0, 0x8
out res[r3], r0
ldc r0, 0x4
out res[r3], r0
ldc r0, 0x2
out res[r3], r0
ldc r0, 0x1
out res[r3], r0
ldc r0, 0x2
out res[r3], r0
ldc r0, 0x4
out res[r3], r0
bu top
Hope this helps.
Henk
PS - a list of SETC values is in page 172 of the XS1 Architecture Manual.
User contributions licensed under CC BY-SA 3.0