Shop OBEX P1 Docs P2 Docs Learn Events
Sharing my ps4 ds4 controller hack and asm debug — Parallax Forums

Sharing my ps4 ds4 controller hack and asm debug

IncVoidIncVoid Posts: 40
edited 2016-03-09 15:26 in Propeller 1
Long Story short, make sure your pasm variables are initialized to some value, or else the PC compile time assembly pointer doesn't get incremented, respect the special register's S-field behavior versus D-field behavior, update your constants when you feature creap.


Bought a "remap ffc" from amazon, and had a prop mini and 4 way. So my wires popping off the pcb pads wasnt' an issue anymore. Made this abomination.
In hindsite I should of did ffc to ffc soldering and it would of been a lot thinner, and not as wide due to half the IDE cable not being used. and mounting the 4way stick on top made it hard to solder neighboring pins, should of did a rotary encoder or two, the stick's axis is mapped to adding or subtracting to values that get added to phsa based on the high bit, kinda jumping time, probably should of just compared versus cnt but ohwell.
4MYiYuF.jpg

I did similar with a 4d microsystems uoled with a prop in it for my 360 years ago. Don't know if that forum made the migration but its around somewhere.

I was brainstorming the code and staring at it for days before the 8th, when Tom Clancy's The Division launched. Googled Phil's tricks and traps to double check my assembly. I had a couple hardware/software issues, such as I soldered to the same legs of a switch so that one switch was always locked on, label'ing, uninitialized data and using registers in D-field when they should of been in the S-field, as well as a bad array length in my constants.

I pass parameters to a function that are to be moved into the S and D field of a rdlong instruction.
I figure why move them into a register only to move them into the S and D field, so I opted out of using inline parameters to pasm funtions to make it easier to read for me, I kept getting confused, so instead of pass parameters via the "trick and traps" way:
CALL #Subroutine
 LONG Arg1
 LONG Arg2
 ..
Subroutine MOVS :GetArg1,Subroutine_ret
 ADD Subroutine_ret,#1
:GetArg1 MOV :Arg1,0-0
 MOVS )GetArg2,Subroutine_ret
 ADD Subroutine_ret,#1
:GetArg2 MOV :Arg2,0-0
 ..
 JMP Subroutine_ret
:Arg1 LONG 0-0
:Arg2 LONG 0-0
Subroutine_ret RET

I tried this, dref just takes a register label/address and puts the contents of that register back into D
garr          'd_register,pointer to hub memory,count
              mov d,garr_ret 
              add garr_ret,#1        'inc addr
              call #dref             'd contains inline[0]=#masks
              movd :loop,d      ':loop d = inline[0]

              mov d,garr_ret
              add garr_ret,#1
              call #dref        'd contains inline[1]=#bufp
              call #dref        'd contains the address inside bufp
              movs :loop,d 

              mov d,garr_ret 'address of inline 2         
              add garr_ret,#1
              call #dref
              mov :loopc,d 'loop count
              
:loop         rdlong 0-0, #0-0 'literal hard address
              add :loop,d1s4
              djnz :loopc, #:loop '+4
              jmp garr_ret
:loopc        long 0-0
garr_ret ret 'we got all parameters

Later I made an easier to read and less generalized function checking buttons using an array masks and whether the button is active low or high,because I knew I'd be using the same arrays #masks #action
everytime so I embedded the parameters inside the function. and let the movd and movs instructions do it for me. I used TD and TS, because earlier version of the function were using another array and instructions. So I was using the same values many times and it was easier to reuse, plus I'd have to shift the index over to add to the D field instead of s-field if I did't use temporary holders.
cb            mov td,#masks
              
              add td,index
              
              mov ts,#action
              add ts,index
              
              movd :c_pin,td 'modify all the next instructions
              movd :c_sig,td
              movs :c_sig,ts
              

:c_pin        test 0-0,ina wz 'is one of A-D pressed
:c_sig        test 0-0,0-0 wc 'is it the correct signal
cb_ret        ret

Pretty sure my problem was where I defined ts and td:
ts            long
td            long
d1      long $200       'one to the d-field
d1s4    long $204
ts,td,d1 all pointed to the same register, if my knowledge of the data section is correct. I'm still not sure if this is what was happening. But maybe that is why the res instruction is required to increment the PC compile time assembly pointer because empty labels do not?
so td and ts were both #action+index, luckily I never used d1, I only used d1s4 above. Easily fixed by giving it a 0 value.
So I wasn't testing INA with the proper mask, instead its active low/high signal. I know my buttons are active low, so the c_pin test would be testing against an all zero value, which would always set the 0 flag,
again test for an all zero value in the c_sig op, no carry. So I ALWAYS got zero set, carry cleared.
and of course since the flags aren't equal the following code would always call #pb, which is why my buttons were locked on (disregarding the one button that was physically soldered the wrong way)
mov f_c,#3 'buttons 3,2,1. 0 is handled separately 
:f            mov index,f_c
              call #cb


[b]if_z_ne_c[/b]     call #pb  'press remapped         'if the pin matches required signal
if_z_eq_c     call #rb  'release remapped       'make sure released
              djnz f_c,#:f 'next button

the #pb function was written higher level like, which kinda saved me because at least it was working
pb            mov d,#map   'D for data :)
              add d,index
              call #dref        
              mov mindex,d      'mindex=map[index]

              mov d,#masks
              add d,mindex      
              call #dref        
              mov m,d           'm=masks[mindex]
              or dira,m         'set the output of pin
              
pb_ret        ret

How I found my errors were a lil brute forcy

since my jmps were fine and it wasn't executing data or being super random, I was able to insert wrlong instructions to copy the registers out to a literal address in hub ram. the end of the array that I originally passed it. In fact this is where I found my array length was wrong, cause I had it write the array it stored, back to hub ram, and I serial'd that out and hand checked it in the Parallax Serial Terminal and saw it wasn't what I expected, off by one, I had added another remapped button and added one more element to the arrays mask/action/pin number. The middle array was all wrong (where the ts td yielded its head), which lead me to my array garr function (get array) and I checked the registers. line by line by adding "mov d,(register to check)" around to check my operations then discovered hmm. if I check td up here its one thing, but down here after ts was manipulated, I get something else.
wb        movs :loop,bufp
              add  :loop,#(eof)
              nop                             
:loop         wrlong d,#0-0                                
wb_ret        ret

after all that only one button was locked on so I went to the multi-meter and checked the switch legs fixed that and the might prop is providing me accessibility functions, albeit trivial ones that could of been handled normally with just wiring but still, fun exercise.


Sign In or Register to comment.