TipsNTricks: Why JMP JMP JMP makes sense
MagIO2
Posts: 2,243
Hi all!
Maybe you already recognized that I'm a new member of this forum and new to the Propeller programming. Today I want to share a finding I made in PASM programming to other newbies. I made this finding when programming a driver for a IR receiver. Of course I found the IR module on the ObEx and tried it out and it worked. But when you are new in something you need to have goals. So I made reprogramming an IR driver my first goal. (In the end it should read and transmit any kind of IR codes from IR remote controls).
The driver can permanently stay in a COG and reads a buffer for commands.
First part of my driver has to detect the lenght of pulses and pauses, which is needed to find out which coding is used for a IR remote control. As the driver should not be blocking, it only waits a limited time for this measurement.
Soon I discovered that the loop for measuring the 1s and the one for measuring the 0s looked mostly identical. So I did the following to put these two parts together:
ir_trim_start·········· mov············ ir_time, cnt··········' initialize the wait
······················· add············ ir_time, ir_dt
······················· mov············ ir_trim_jump, ir_trim_jump1···' initialize the jump commands to the initial code-flow
······················· mov············ ir_trim_cjmp, ir_trim_cjmp1
······················· mov············ ir_trim_out, ir_trim_out1
ir_trim_lp1············ mov············ ir_count, ir_zero·············· ' start measurement of a 0 or a 1
ir_trim_lp2············ waitcnt········ ir_time, ir_dt················· ' no need to count faster for low frequency IR signal
······················· add············ ir_count, #1··················
······················· cmp············ ir_maxwait, ir_count WC········ ' if the maxwait has been reached
ir_trim_out·· if_c····· jmp············ #ir_loop_ret··················· ' we go back to ... well, that depends
······················· test··········· ir_mask, ina WZ················ ' now let's see if the IR-Pin has changed
ir_trim_cjmp· if_z····· jmp············ #ir_trim_lp2··················· ' flag depends on current loop-status
ir_trim_jump··········· jmp············ #ir_set_1······················ ' find max and min of 1s or 0s
ir_trim_jump1·········· jmp············ #ir_set_1······················ ' here we have a list of jump commands. One set for reading 1s
ir_trim_jump2·········· jmp············ #ir_set_0······················ ' and one set for reading 0s
ir_trim_cjmp1 if_z····· jmp············ #ir_trim_lp2
ir_trim_cjmp2 if_nz···· jmp············ #ir_trim_lp2
ir_trim_out1· if_c····· jmp············ #ir_loop_ret
ir_trim_out2· if_c····· jmp············ #ir_trim_done
ir_set_1··············· cmp············ ir_1_max, ir_count WC·········· ' find out the min and max duration
············· if_c····· mov············ ir_1_max, ir_count
······················· cmp············ ir_count, ir_1_min WC
············· if_c····· mov············ ir_1_min, ir_count
······················· mov············ ir_trim_jump, ir_trim_jump2···· ' and now switch to reading 1s
······················· mov············ ir_trim_cjmp, ir_trim_cjmp2
······················· mov············ ir_trim_out, ir_trim_out2
······················· jmp············ #ir_trim_lp1
ir_set_0··············· cmp············ ir_count, ir_0_max WC·········· ' and now switch to reading 0s
············· if_nc···· mov············ ir_0_max, ir_count
······················· cmp············ ir_0_min, ir_count WC
············· if_nc···· mov············ ir_0_min, ir_count
······················· mov············ ir_trim_jump, ir_trim_jump1
······················· mov············ ir_trim_cjmp, ir_trim_cjmp1
······················· mov············ ir_trim_out, ir_trim_out1
······················· jmp············ #ir_trim_lp1
ir_time······ long····· 0
ir_dt········ long····· 800
ir_maxwait··· long····· 200
ir_1_max····· long····· 0
ir_1_min····· long····· 0
ir_0_max····· long····· 0
ir_0_min····· long····· 0
ir_count····· long····· 0
ir_mask······ long····· %00000000_00000000_00000100_00000000
I know, there is still room for improvements - or better to say, I figured it out while writing this. Morphing code with the movs, movd and movi can be more effective (in terms of needed RAM), if only one part of the command needs to be changed - which is the case in my loop. But if you have to change condition flags AND the adress moving pre-compiled code is more effective.
Why do I write a thread for that? Today I was thinking about this while waiting for the train and I wondered why I did not do that before with other Controllers/CPUs. I programmed a lot of different processors in Assembly (6501, 68k, 80486, 8051, PIC, AVR, R8C). And the answer is:
1. Sometimes the code is in Flash and it is simply impossible
2. Harvard Architecture does not allow to change code
3. CPU's load code to different places, so the jumps are usually relative
By the way, this technique is also nice when reading commands from HUB, like a lot of drivers do it. Instead of MOVS and NOP (for pipeline delay) one can jump into a jump-table, which needs one command less. Of course there are other ways which use less RAM. Sounds like the YIN and YANG of programming ;o)
I'm very curious on what to find next.
Post Edited (MagIO2) : 3/20/2009 9:22:42 PM GMT
Maybe you already recognized that I'm a new member of this forum and new to the Propeller programming. Today I want to share a finding I made in PASM programming to other newbies. I made this finding when programming a driver for a IR receiver. Of course I found the IR module on the ObEx and tried it out and it worked. But when you are new in something you need to have goals. So I made reprogramming an IR driver my first goal. (In the end it should read and transmit any kind of IR codes from IR remote controls).
The driver can permanently stay in a COG and reads a buffer for commands.
First part of my driver has to detect the lenght of pulses and pauses, which is needed to find out which coding is used for a IR remote control. As the driver should not be blocking, it only waits a limited time for this measurement.
Soon I discovered that the loop for measuring the 1s and the one for measuring the 0s looked mostly identical. So I did the following to put these two parts together:
ir_trim_start·········· mov············ ir_time, cnt··········' initialize the wait
······················· add············ ir_time, ir_dt
······················· mov············ ir_trim_jump, ir_trim_jump1···' initialize the jump commands to the initial code-flow
······················· mov············ ir_trim_cjmp, ir_trim_cjmp1
······················· mov············ ir_trim_out, ir_trim_out1
ir_trim_lp1············ mov············ ir_count, ir_zero·············· ' start measurement of a 0 or a 1
ir_trim_lp2············ waitcnt········ ir_time, ir_dt················· ' no need to count faster for low frequency IR signal
······················· add············ ir_count, #1··················
······················· cmp············ ir_maxwait, ir_count WC········ ' if the maxwait has been reached
ir_trim_out·· if_c····· jmp············ #ir_loop_ret··················· ' we go back to ... well, that depends
······················· test··········· ir_mask, ina WZ················ ' now let's see if the IR-Pin has changed
ir_trim_cjmp· if_z····· jmp············ #ir_trim_lp2··················· ' flag depends on current loop-status
ir_trim_jump··········· jmp············ #ir_set_1······················ ' find max and min of 1s or 0s
ir_trim_jump1·········· jmp············ #ir_set_1······················ ' here we have a list of jump commands. One set for reading 1s
ir_trim_jump2·········· jmp············ #ir_set_0······················ ' and one set for reading 0s
ir_trim_cjmp1 if_z····· jmp············ #ir_trim_lp2
ir_trim_cjmp2 if_nz···· jmp············ #ir_trim_lp2
ir_trim_out1· if_c····· jmp············ #ir_loop_ret
ir_trim_out2· if_c····· jmp············ #ir_trim_done
ir_set_1··············· cmp············ ir_1_max, ir_count WC·········· ' find out the min and max duration
············· if_c····· mov············ ir_1_max, ir_count
······················· cmp············ ir_count, ir_1_min WC
············· if_c····· mov············ ir_1_min, ir_count
······················· mov············ ir_trim_jump, ir_trim_jump2···· ' and now switch to reading 1s
······················· mov············ ir_trim_cjmp, ir_trim_cjmp2
······················· mov············ ir_trim_out, ir_trim_out2
······················· jmp············ #ir_trim_lp1
ir_set_0··············· cmp············ ir_count, ir_0_max WC·········· ' and now switch to reading 0s
············· if_nc···· mov············ ir_0_max, ir_count
······················· cmp············ ir_0_min, ir_count WC
············· if_nc···· mov············ ir_0_min, ir_count
······················· mov············ ir_trim_jump, ir_trim_jump1
······················· mov············ ir_trim_cjmp, ir_trim_cjmp1
······················· mov············ ir_trim_out, ir_trim_out1
······················· jmp············ #ir_trim_lp1
ir_time······ long····· 0
ir_dt········ long····· 800
ir_maxwait··· long····· 200
ir_1_max····· long····· 0
ir_1_min····· long····· 0
ir_0_max····· long····· 0
ir_0_min····· long····· 0
ir_count····· long····· 0
ir_mask······ long····· %00000000_00000000_00000100_00000000
I know, there is still room for improvements - or better to say, I figured it out while writing this. Morphing code with the movs, movd and movi can be more effective (in terms of needed RAM), if only one part of the command needs to be changed - which is the case in my loop. But if you have to change condition flags AND the adress moving pre-compiled code is more effective.
Why do I write a thread for that? Today I was thinking about this while waiting for the train and I wondered why I did not do that before with other Controllers/CPUs. I programmed a lot of different processors in Assembly (6501, 68k, 80486, 8051, PIC, AVR, R8C). And the answer is:
1. Sometimes the code is in Flash and it is simply impossible
2. Harvard Architecture does not allow to change code
3. CPU's load code to different places, so the jumps are usually relative
By the way, this technique is also nice when reading commands from HUB, like a lot of drivers do it. Instead of MOVS and NOP (for pipeline delay) one can jump into a jump-table, which needs one command less. Of course there are other ways which use less RAM. Sounds like the YIN and YANG of programming ;o)
I'm very curious on what to find next.
Post Edited (MagIO2) : 3/20/2009 9:22:42 PM GMT