Using FlexProp to help convert Spin2 to assembly
Converting this OLED code to inline assembly and came to this:PinWrite(D0_pin..D7_pin, d)
Started thinking about how to do this in assembly and not seeing an easy way to do it when D0_pin and D7_pin are arbitrary. (I should probably force the data bus to have a base pin that is multiple of 8 to make things simple.) But, was wondering if I was missing something...
Occurred to me that I can just use FlexProp to compile this line and see what it makes in the pasm file it generates...
Just made this simple .spin2 file:
CON 'Testing
PUB main()|d
d:=8
PinWrite (7..0, d)
Compiled, and it worked. Now, I see the "__system___pinwrite" function is about as complex as I imagined. No shortcuts. Not sure how 7..0 becomes #448 or how the code works, but now I know that I definitely need to restrict pins to basepin, multiple of 8, this is just too much...
' PUB main()|d
_main
' d:=8
' PinWrite (7..0, d)
mov arg01, #448
mov arg02, #8
call #__system___pinwrite
_main_ret
ret
hubexit
jmp #cogexit
__system___pinwrite
mov _var01, arg01
and _var01, #31
test arg01, #32 wz
shr arg01, #6
bmask arg01, arg01
shl arg01, _var01
shl arg02, _var01
if_e jmp #LR__0001
or dirb, arg01
mov _var01, outb
andn _var01, arg01
and arg02, arg01
or _var01, arg02
mov outb, _var01
jmp #LR__0002
LR__0001
or dira, arg01
mov _var01, outa
andn _var01, arg01
and arg02, arg01
or _var01, arg02
mov outa, _var01
LR__0002
__system___pinwrite_ret
ret
Comments
Realized I can't move data bus to multiple of 8 very easily in my setup...
https://forums.parallax.com/discussion/175283
But, this does the trick:
testb d,#7 wc drvc #D7_pin testb d,#6 wc drvc #D6_pin testb d,#5 wc drvc #D5_pin testb d,#4 wc drvc #D4_pin testb d,#3 wc drvc #D3_pin testb d,#2 wc drvc #D2_pin testb d,#1 wc drvc #D1_pin testb d,#0 wc drvc #D0_pin
When I want to translate Spin2 straight PASM2 I look in the PNut compiler which Chip includes in the download. In some cases he uses skip sequences, but comments in the code make those easy to sort out when instructions are tightly wound. For pinwrite(), it has its own routine which is setup to work with outa or outb registers (I think I tested and it does not work across the p31/p32 boundary).
pinw_ ror y,#6 wc 'y=pins, w=val (begins at pop2 in LUT) bitc pinw_reg,#9 'select outa/outb for writing bmask v,y 'make mask rol y,#6 rol v,y 'justify mask rol w,y 'justify val setq v 'mux val into outa/outb using mask pinw_reg muxq outa,w _ret_ dirh y 'enable outputs
Of course, if you're writing to a fixed set of outputs, you can simplify, I did a quick test using P59..56 on the Eval board.
pub write4(value) | m org mov m, #%1111 ' 4-bit mask shl m, #(56-32) ' align with lsb andn outb, m ' clear old outputs and value, #%1111 ' truncate to 4 bits shl value, #(56-32) ' align with lsb or outb, value ' output new bits or dirb, value end
The P2 deals with pin groups, so 7..0 is the same as 0 addpins 7 which is 0 + (7 << 6) which is 448.
While a tad longer, the advantage of your testb/drvc code is that it works across the P31/P32 boundary.