Assembler Woes
Gerry Keely
Posts: 75
Hi
Attached is a contrived program for flashing a led on and off. I know there are much simpler ways of doing this but purpose of the exercise was to learn something about assembly language proramming and passing parameters.
The program works, but only comes alive after a few minutes. I suspect it is something to do with the system counter but not too sure. Any comments would be welcomed.
Note I'm using a DLP-Prop board which has a 6MHz clock.
Gerry
Attached is a contrived program for flashing a led on and off. I know there are much simpler ways of doing this but purpose of the exercise was to learn something about assembly language proramming and passing parameters.
The program works, but only comes alive after a few minutes. I suspect it is something to do with the system counter but not too sure. Any comments would be welcomed.
Note I'm using a DLP-Prop board which has a 6MHz clock.
Gerry
{{ Flash a led on pin 27 using 3 cogs , main + two assembly routines}} CON _clkmode = xtal1 + pll16x _xinfreq = 6_000_000 VAR long cmd0 long dly0 long cmd1 long dly1 PUB Main cmd0 := 0 cmd1 := 0 dira[noparse][[/noparse]27] := 1 cognew(@ASM0, @cmd0) 'start a new cog cognew(@ASM1, @cmd1) 'and again repeat Off(1,48_000_000) 'switch off On(2,48_000_000) 'switch on PUB Off(val,del) cmd0 := val dly0 := del repeat while cmd0 <> 0 'wait for asm0 to complete outa[noparse][[/noparse]27] := 0 PUB On(val,del) cmd1 := val dly1 := del repeat while cmd1 <> 0 'wait for asm1 to complete outa[noparse][[/noparse]27] := 1 DAT org 0 ASM0 mov tmpCmmd0, par mov tmpDelay0 , par add tmpDelay0, #4 WaitForCmd0 rdlong Delay0, tmpDelay0 rdlong Cmmd0, tmpCmmd0 tjz Cmmd0, #WaitForCmd0 CheckCmd0 cmp Cmmd0, #1 wz if_nz jmp #WaitForCmd0 mov Time0, cnt 'Get system counter 'add Time0 ,10 add Time0, Delay0 'Add delay waitcnt Time0, Delay0 wrLong zero0, tmpCmmd0 jmp #WaitForCmd0 tmpCmmd0 long 0 tmpDelay0 long 0 Cmmd0 long 0 zero0 long 0 Delay0 long 0 Time0 res 1 FIT 496 DAT org 0 ASM1 mov tmpCmmd1, par 'get command address mov tmpDelay1, par add tmpDelay1, #4 'get delay address WaitForCmd1 rdlong Delay1, tmpDelay1 'read the command rdlong Cmmd1, tmpCmmd1 'read the delay tjz Cmmd1, #WaitForCmd1 CheckCmd1 cmp Cmmd1, #2 wz if_nz jmp #WaitForCmd1 mov Time1, cnt 'Get system counter add Time1, Delay1 'Add delay waitcnt Time1, Delay1 wrLong zero1, tmpCmmd1 'clear the command jmp #WaitForCmd1 'repeat the dose ' ENDASM tmpCmmd1 long 0 tmpdelay1 long 0 Cmmd1 long 0 zero1 long 0 Delay1 long 0 Time1 res 1 FIT 496
Comments
Note: COGINIT/COGNEW are not instantaneous, it takes ~8000 cycles to copy the data from HUB to COG. So it is possible to modify the HUB data after COGNEW and have it show up in the COG.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Composite NTSC sprite driver: Forum
NTSC & PAL driver templates: ObEx Forum
OnePinTVText driver: ObEx Forum
If you don't mind some PASM pointers:
You use the line "mov tmpCmmd0, par". There are 2 ways to get around this. One is to simply use par instead of tmpCmmd0, as that register will remain the same value, but of course you lose readability that way. The second option is to set the value of tmpCmmd0 in Spin _before_ calling cognew. What happens is that tmpCmmd0 is a perfectly valid long variable declared in Hub RAM. So you can read its value or set its value from Spin...but it will only change the value of tmpCmmd0 in the Hub RAM, not in cog RAM. When you call cognew, it takes a starting address in Hub RAM and loads 496 consecutive longs from there into the cog which is about to be started. If you happen to have already updated the data that is sitting in Hub RAM before you call cognew, then the cog gets copied in the value that you already modified. So you could just say something like this:
I see you using this code:
This works just fine, but note that you could do:
This sets the zero flag iff Cmmd0 is zero, then if that flag is set, the jump occurs on the subsequent line. This is faster in the case that Cmmd0 is non-zero, because tjz (and all test & jump commands) take 4 clocks if they jump, and 8 clocks if the don't. The if_z modifier, on the other hand, will take only 4 clocks either way.
When you check your commands, there are 2 things you could do for readability. Instead of using #1 as the command you check against, you could either declare a constant in a CON block and use that (as long as it's < 512), or you could use a character which is a mnemonic for the action to be performed. For example, combining both suggestions (which is a bit silly [noparse][[/noparse]8^):
Your code is looking great, though! Please don't take these tiny suggestions as criticism.
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
Thank you for your quick response, Initalised dly0 and dly1 and that solved the problem.
Regards
A Grateful Gerry
I prefer using enums for that. YMMV.
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO
Good point, for multiple commands especially.
Jonathan
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
lonesock
Piranha are people too.
Thank you for your response and pointers, much appreciated and no I don't take what you say as any kind of critism.All help much appreciated.
Gerry
Post Edited (Gerry Keely) : 7/23/2009 1:16:01 PM GMT
I look at this communication-register (or byte or whatever length it is) a bit different.
If it would be strictly a command-register, only the master could write to it.
So I call it communication register. And both can read and write. But this is just a naming convention.
So that whole transaction can have different states like maybe:
SlaveIdle, SlaveBusy, ExecCmdThis, ExecCmdThat, SlaveError ...
With enums, you can also play tricks what bit to set (see manual for enums). But then you'd have to pay atention not to get overlaps.
Anyhow, this increases readability and is much easier to maintain should there be a need to add new states or remove unnecessary ones.
Just a little excursus on writing better code ("literate programming").
Nick
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Never use force, just go for a bigger hammer!
The DIY Digital-Readout for mills, lathes etc.:
YADRO