It is currently Mon Dec 18, 2017 7:58 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 64 posts ]  Go to page 1, 2, 3, 4, 5  Next
Author Message
 Post subject: the Power Glove
PostPosted: Sat Dec 19, 2009 8:17 am 
Offline
User avatar

Joined: Fri Sep 26, 2008 7:55 pm
Posts: 105
Location: Montreal
So I've acquired access to the use of a power glove, and I've decided to research its operation, since I can't find proper documentation on it. I mean, there's all sorts of stuff out on the internal functioning, but not from a NES programmer's point of view. What interests me the most is the games that (apparently) send their own custom configuration to the glove, separate from the 14 preprogrammed settings; the only one I know of being Bad Street Brawler. As I type this I realize I should probably be dowloading and disassembling the rom and looking for code around $4016/7 accesses but it might not be that simple. Any suggestions for writing a Power Glove test ROM?


Top
 Profile  
 
 Post subject:
PostPosted: Sat Dec 19, 2009 4:48 pm 
Offline
Formerly Fx3
User avatar

Joined: Fri Nov 12, 2004 4:59 pm
Posts: 3076
Location: Brazil
http://nesdev.com/bbs/viewtopi ... =6736#6736


Top
 Profile  
 
 Post subject:
PostPosted: Sun Dec 20, 2009 9:24 am 
Offline
User avatar

Joined: Fri Sep 26, 2008 7:55 pm
Posts: 105
Location: Montreal
and why does the NES controller port pinout on the wiki redirect to itself?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Dec 20, 2009 11:04 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19356
Location: NE Indiana, USA (NTSC)
Oops, my bad. Fixed.


Top
 Profile  
 
 Post subject: seriously...
PostPosted: Tue Jan 19, 2010 3:03 pm 
Offline
User avatar

Joined: Fri Sep 26, 2008 7:55 pm
Posts: 105
Location: Montreal
can anyone help me figure out what this chart means? you can skip the basics, I just want to figure out how to use this information.
Image


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jan 19, 2010 3:23 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19356
Location: NE Indiana, USA (NTSC)
"LATCH" is the last value WRITTEN to D0 of $4016.
"CLOCK" pulses happen whenever $4016 is READ. At that point, the CPU samples the state of lines D0, D3, and D4 from the controller; do you have traces of those?
For a standard controller, LATCH goes 1 then 0, followed by 8 clocks, as seen in the data packet.
But what's happening in this init sequence is the NES sending data to the controller.

A bit deletion due to DPCM on this sort of stream would be a pain.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 21, 2010 8:21 am 
Offline
User avatar

Joined: Fri Sep 26, 2008 7:55 pm
Posts: 105
Location: Montreal
tepples wrote:
A bit deletion due to DPCM on this sort of stream would be a pain.


That's good to know...if I ever plan to use the glove beyond visual-only programs, I'll remember to take caution with the DPCM channel or not use it at all. Do you think it's necessary to wait the exact number of microseconds as specified in the diagram, or am I not understanding it correctly? Could it just be a measurement of some natural function of the NES, or some arbitrary measurement from a specific game?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 21, 2010 8:26 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19356
Location: NE Indiana, USA (NTSC)
The -LATCH pulses with duration on the order of 10000 µs are probably a wait just less than a frame, as 16640 µs = 1 NTSC NES frame. The +LATCH pulses on the order of 1000 µs are probably just a couple thousand CPU cycles, just long enough to show that it's not a regular controller.

It'd be possible to make a timing circuit to clean up clock signal distortions caused by the DPCM channel's DMA unit, much like the timing circuit in the MMC3's scanline counter that spreads A12 pulses. I wonder whether the glove has one.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Mar 18, 2012 6:48 pm 
Offline

Joined: Mon Jul 07, 2008 7:40 pm
Posts: 61
OMG necrobump! (sorry, mods)

Did this exploration ever turn into anything? I'm contemplating poking around with a Power Glove myself, and while other sources like http://textfiles.fisher.hu/programming/gla-91o and http://wiki.hak5.org/index.php?title=Episode_2x03 do support the idea that the output of the glove is deterministic and meaningful and that the startup sequence is reproducible, those time delays do seem both arbitrary and difficult to get out of a NES.

I would accept that the init sequence listens for 4 clocks, then a low->high->low latch followed by 7 bytes of data and a final latch hold/release, and I would accept that the hardware in the glove may only buffer 8 bytes at a time and thus require 2 frames to fully deliver a packet. I'm curious what the tolerances are on those 7212µs, 2260µs and 892µs waits are, though. Specific times keyed to some timer in the glove? Just arbitrary values someone pulled with a scope from Super Glove Ball representing the particular code that game ran? If I were to just NMIwait a full frame for each, would it still work, or are instruction-timing loops to precise µs values really needed?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Mar 23, 2012 7:43 pm 
Offline

Joined: Mon Jul 07, 2008 7:40 pm
Posts: 61
Quote:
*crickets chirp*


Okay. I'll take that as a "no."

I'm still going to take a swing at it, and I might as well throw my thoughts here.

From an interface perspective, I'm guessing the design was not SO pathological as to require cycle-precise timing to initialize the glove. Worst-case scenario I may need to disassemble Super Glove Ball and just yank its code between those first 4 $4016 reads and wherever I can pin down the end of that sequence being, but...

From an electrical engineering perspective, I doubt that initial latch low/high hold is being timed explicitly on the glove. Building in timing hardware specifically to prevent people who didn't know to wait precisely 7212µs / 2260µs would be pathological and expensive and easily defeated by some college kid with a good scope. I suspect this is just a function of the setup code of whatever game the trace was recorded from, and for my first pass, I plan to just 4-clock, NMIwait, latch up, NMIwait, latch down and go. If that fails, I can always add code. Having some pause in there is probably a good thing- crunchy semi-analog electronics are likely to need some time to warm up or enter steady-state after being activated, but I will be surprised and depressed if the precise wait times are really required. Also, those first 4 clocks? I'm guessing that's the game "asking" whatever's connected whether it's a Glove. This would make more sense if, say, regular pads returned up/down/left/right bits first and the game could check whether, say, up and down were simultaneously held (if so, probably not a regular pad), but even so, who holds A+B+Start+Select at startup? This may still be what was showing up on the trace, we'll never know what the game was doing with the returned bits. If so, it may not even be a required part of the init- the init may begin with the long hold of the latch, or even with the first clock/poll that (unusually) occurs with the latch still raised.

From a low-level architectural programming perspective, the poster in that newsgroup snapshot who states
Quote:
Well, if anyone is interested, the 7 bytes sent to init the glove seem
to be: 0x06, 0xC1, 0x08, 0x00, 0x02, 0xFF, 0x01

probably has the right idea, and even the right interpretation of the bytes. My 2 cents as to how that message breaks down is not that it's a "program" per se, but rather a configuration, bookended with the sorts of things you'd want as a Glove-side engineer to verify the message was correct. To wit, I would propose
$06: "6 bytes of data will be included in this packet"
$C1 $08 $00 $02: "go into manual-override mode and start sending me packets conforming to these parameters:..." (no clue what each byte individually represents... $08 may be bits-precision-on-position, $C1 may be as simple as "12-position angular resolution, data returned in steps of 1", but really I'm just taking stabs in the dark. the $C may also refer to 12 bytes of data in the return packet, or the $8 may be requesting 8-ish bytes of non-"junk" data in the return. $00 $02 may be 2's complement on the position data with 0 as center. The world may never know.)
$FF: "here's an easily-identifiable stop-byte. Message ends."
$01: "The message I sent should have checksum $01, if it doesn't you missed something" (or, meh, this may be real data on the order of $FF-range precision in units of $01, or in $01 byte per axis)

If I'm on the right track, posterity may just need to sit back and accept the 2-frame 12-byte packets half full of "junk" because I have no thoughts on what the checksum algo might be (other than that it can probably be computed sequentially bit by bit and take up no more than 1 byte of Glove-side memory. Could it be as simple as an odd/even sum result of the pre-stopbyte bytes? Or an odd/even count of 1s in the bitstream?) Anyway, without cracking the checksum, the Glove would probably reject any variation to the 4 real parameters.

And the "junk" bytes in the return packet? Probably not strictly junk. It would be appallingly wasteful to force NES developers to take a 50% hit in sampling rate when all the "good" data is in the first 8 bytes. I think the newsgroup also observed the last byte seems to correlate to whether or not the glove is pointed at the speaker array. If it's something as crazy-straightforward as the levels/timings the mics are detecting, it really would look kinda like noise and be ultimately unuseful save in some explicitly designed cases. It may also be that the data packet in "hi-res" mode is 12 bytes always regardless, and the particular hi-res configuration sent to the glove only uses 6-7 of them, with the rest reserved in case of later need. If the return packet isn't fixed-at-12-bytes because of potential data usage, the only other explanation I can think of is that the glove itself needs X amount of time to sample its hardware and may force the NES dev to poll it a few extra times before it's required to return real data just so it has time to get its bits in order. Glove-side register timing is one likely candidate for that blatant vblank wait after the first 8 bytes- if the glove has only 8 regs lined up for data output, it probably needs a breather to shift the remaining 4 bytes in. Still, if I get as far as seeing any data out of the glove, I'll probably test it with the delay and with trying to grab all 12 bytes in one frame.
OR we could turn the Glove-needs-time hypothesis inside out and posit that perhaps the 12-byte return is an artifact rather than an intent: it may be that the glove takes Xµs to get a new frame of data any which way, whether it's polled 8 times, 12 times, or 100 times in the interim, and at that wonderful timing everyone's reproduced from that trace diagram, there just happen to be 11 samples between the header byte marking the start of real data and the header byte marking the next start of real data. This would be consistent with observations on the newsgroup that the first bytes out of the glove came from the middle of the "packet": Glove don't care. Glove gonna put Glove's data on the line when Glove's ready, regardless of what big Mr. NES coder's timeline is. It's the game's job to listen for the header byte and jump into the datastream when Glove says so.

But until I get my just-ordered flashcart and start dumping some builds to hardware, I won't really know a thing. And when/if I do get data off the glove onto the NES, I'll try to keep the board updated.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 24, 2012 4:20 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19356
Location: NE Indiana, USA (NTSC)
LoneKiltedNinja wrote:
From an electrical engineering perspective, I doubt that initial latch low/high hold is being timed explicitly on the glove..

True, the Super NES Mouse is widely thought to require somewhat specific timing: 16 bits fast, then a delay, than 16 bits slow, to match what Mario Paint does. But it's just an SPI device like any other Super NES controller, and it accepts any reasonable timing. Thwaite works fine even though it reads 8 bits, then pause, then 24 bits.

On the other hand, the 6-button controller for the Sega Genesis treats a long period without a reread and a short period without a reread as different commands. Short means toggle between sets of buttons; long (over 10 ms or so) means reset back to the first set.

Quote:
From an electrical engineering perspective, I doubt that initial latch low/high hold is being timed explicitly on the glove.

Unless it's waiting to be sure that some analog to digital conversion has completed, like the 555-timed counter in a Vaus controller. You recognized that:
Quote:
the only other explanation I can think of is that the glove itself needs X amount of time to sample its hardware


Quote:
but even so, who holds A+B+Start+Select at startup?

Imagine a multicart where A+B+Select+Start is the command to switch games. Game Boy games and Nintendo's falling block games for NES tend to use this chord as reset.

Quote:
But until I get my just-ordered flashcart and start dumping some builds to hardware, I won't really know a thing. And when/if I do get data off the glove onto the NES, I'll try to keep the board updated.

And even once you do release docs and demos, don't expect people to jump to buy a $100 Power Glove to make and test games.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 24, 2012 9:18 am 
Offline

Joined: Mon Jul 07, 2008 7:40 pm
Posts: 61
tepples wrote:
True, the Super NES Mouse is widely thought to require somewhat specific timing: 16 bits fast, then a delay, than 16 bits slow, to match what Mario Paint does. But it's just an SPI device like any other Super NES controller, and it accepts any reasonable timing. Thwaite works fine even though it reads 8 bits, then pause, then 24 bits.

On the other hand, the 6-button controller for the Sega Genesis treats a long period without a reread and a short period without a reread as different commands. Short means toggle between sets of buttons; long (over 10 ms or so) means reset back to the first set.


Interesting to know there is that degree of subtlety going on. Still, I can hold out hope that if the Glove differentiates between "long" and "short" holds, it at least doesn't differentiate between "long" and "very long."

Quote:
Unless it's waiting to be sure that some analog to digital conversion has completed, like the 555-timed counter in a Vaus controller.

Not familiar with that one. But again, a delay to sample or reach steady-state or reach timer completion wouldn't throw me. It's a delay with both lower AND upper bounds that would be a pain.

Quote:
Imagine a multicart where A+B+Select+Start is the command to switch games. Game Boy games and Nintendo's falling block games for NES tend to use this chord as reset.

I concede there are scenarios that use button chords as triggers, but in those cases it's something the player is instructed to do. My only point is that in a game where the player was not expected to hold particular buttons at startup, but which may or may not be played with the Glove, it would be convenient for the Glove to return some known unusual button combo at first poll. The Glove Ball manual points out that the game will know a glove is plugged in as soon as it starts up, and even flash the screen until the glove is calibrated and pointed at the speaker rig, which lends credence to the first poll being a detection and some return byte containing "is the world sane?" data.

Quote:
...And even once you do release docs and demos, don't expect people to jump to buy a $100 Power Glove to make and test games.

Touché :) But actually, while I'm not planning a game, I wouldn't be surprised if what I am planning ends up selling a few Power Gloves to the right sorts of people if it works...

This weekend I plan to rough out a test ROM to try the init routine and display whatever data comes back. Hopefully the flashcart arrives this week, and I can spend next weekend fiddling with the test ROM until useful data comes out of the Glove. Once I have X, Y, rotation and button data reliably, it will hopefully be only one more weekend before I have a proper release.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 31, 2012 2:21 pm 
Offline

Joined: Mon Jul 07, 2008 7:40 pm
Posts: 61
Round 1 tests:

* Super Glove Ball can flash the glove into high-res mode even after it's been initialized into low-res mode to operate a flashcart bootloader. Thus, the timing of the initialization relative to system start appears immaterial.

* in a first round of tests with purely arbitrary init pauses... a) my graphics went totally fubar because I was trying to fit glove init code in around arbitrary graphics init without NMI waits, but b) I seem to have... gotten the Glove's attention. Not flashed it, but got its attention. If I plug it in mid-runtime and then hit reset so my test rom picks it up, it goes straight into controller-emulation buttons-only without the usual need to press Start.

* This thing either has some massive electric fields stored in it, or else has some way to write back to the CPU through the controller port O_O; The first half-dozen times I started up with it plugged in, I got absolute rainbow scanline garbage. Unplug it, NES boots fine. Plug it in, finally I start getting some games coming up, but they're moderately tile-garbaged. More unplugs/replugs/jiggles, and finally I can boot cleanly. I just need to remember to flex my fingers and disable A/B autofire before pressing Start because it seems to like booting with those on :P

Next round: new test rom, taking my time to init the graphics, and then possibly throwing actual timing loops for the long waits.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 31, 2012 4:31 pm 
Offline

Joined: Mon Jul 07, 2008 7:40 pm
Posts: 61
Round 2 test:

* Initialization successful. Or... at least I got it to beep at me and go into crazy-LED-flicker mode, but I really think the init message got through. My timing on the polling to get data out is still way off- when they say "22µs between clocks" they apparently really f'real MEAN "22µs between clocks," and right now that screws up my inline-graphics-write timing, but I can do things which cause promisingly deterministic changes in the screen-garbage I am seeing, so I really think it's just down to timing my reads right and being a little more professional with my PPU work.

The init code as such:
Code:
; [various other code omitted]
nmiVectorPointsHere:
   ; cache regs
 sta nmi_acache
 stx nmi_xcache
 sty nmi_ycache
 lda $2002   ; clear vblank interrupt
 lda #$00
 sta $2000   ; reset vblank interrupt generation
 lda #$80   
 sta $2000   ; re-set vblank interrupt generation
 
 inc timerlow      ; increase the timer every frame
 bne nmi_no_inchi   ; if timer lobyte is 0
 inc timerhi         ; then inc the hibyte
nmi_no_inchi:

 inc nmi_count
   ; uncache regs
 lda nmi_acache
 ldx nmi_xcache
 ldy nmi_ycache

 rti

; waits a number of 1/60 second NMI-clocked frames, then returns
waitloop:
 lda waitdelay   ; load the number of frames to wait
 clc
 adc timerlow   ; calculate an exit time
 waitloop_innerloop:
 cmp timerlow
 bne waitloop_innerloop   ; loop until we reach the exit time
 rts
 
; waits for a NMI
waitNMI:
 lda #0
 sta nmi_count
waitNMI_loop
 cmp nmi_count
 beq waitNMI_loop
 rts
 
    ; Mein Timingfheurer says clocks need to come at 22microsecond intervals
    ; or, per calculations below, 39.38 cycles.  Call it 39 for convenience.
    ; lda [absolute] takes 4 cycles, so pad with 35 cycles
    ; since we'll be doing this oh-so-many times, make it a routine.  jsr/rts soak cycles nicely anyway.
    ; after jsr and rts, we only need 22 cycles.  2 10s and a 2.
waitGloveClock:
    ; jsr soaks 6 cycles
 ldx #2 ; 2 cycles
waitGloveClockDelay:
 iny ; 2 cycles, dummy op
 dey ; 2 cycles, dummy op
 dex ; 2 cycles
 bne waitGloveClockDelay ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 ldx #0 ; 2 cycles to absorb the lack of branch
 
 rts ; 7 cycles
 
    ; Mein Timingfheurer also says bytes need to be spaced by 96microseconds
    ; or, per calculations below, 171.84 cycles.  Call it 173 for convenience.
    ; since we'll be doing this oh-so-many times, make it a routine.  jsr/rts soak cycles nicely anyway.
    ; after jsr and rts, we need 160 cycles.  16 10s.
waitGloveByte:
    ; jsr soaks 6 cycles
 ldx #16 ; 2 cycles
waitGloveByteDelay:
 iny ; 2 cycles, dummy op
 dey ; 2 cycles, dummy op
 dex ; 2 cycles
 bne waitGloveByteDelay ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 ; usual wait-2 here is soaked by the initial ldx.
 
 rts ; 7 cycles

startVectorPointsHere:
; [graphics setup code omitted]

glovePing:
    ; per The Infallable Trace Diagram, at startup
    ; knock knock
 lda #1
 sta $4016
 lda #0
 sta $4016
 
 lda $4016
 jsr waitGloveClock
 lda $4016
 jsr waitGloveClock
 lda $4016
 jsr waitGloveClock
 lda $4016
 jsr waitGloveClock
    ; who's there?  I don't care; I declare it to be a Power Glove
    ; the actual return bits suggesting this to be a Power Glove are left as an exercise to posterity.
   
gloveFlag:
    ; we "need" to wait 7212 microseconds
    ; at 1.79MHz, 1 cycle is about .559 microseconds
    ; meaning we need to burn 12909.48 cycles.  Call it 12910.
    ; so construct a quick 10-cycle loop and run it 1291 times. 
    ; Or how abut 1290, since there are a few other extraneous instructions being thrown about?
   
 ldx #0 ; 1-byte immediate = 2 cycles load->store EXTRA
 
gloveFlagDelay1: ; 10-cycle 256-loop
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveFlagDelay1 ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
gloveFlagDelay2: ; 10-cycle 256-loop
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveFlagDelay2 ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
gloveFlagDelay3: ; 10-cycle 256-loop
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveFlagDelay3 ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
gloveFlagDelay4: ; 10-cycle 256-loop
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveFlagDelay4 ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
gloveFlagDelay5: ; 10-cycle 256-loop
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveFlagDelay5 ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
    ; at this point we have only 10 more loops to go, so
 ldx #10 ; 2 cycles EXTRA
 
gloveFlagDelay6: ; 10-cycle 10-loop
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveFlagDelay6 ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
 
    ; now that we've done some stuff for 7212 microseconds or close-e-dang-nuff
    ; start a nice wide latch pulse to let the Glove know config data is coming
 lda #1
 sta $4016
 
 
gloveInit:
    ; we "need" to wait 2260 microseconds
    ; at 1.79MHz, 1 cycle is about .559 microseconds --== NOTE: PAL SYSTEMS RUN AT 1.66! ==--
    ; meaning we need to burn 4045.4 cycles.  Call it 4045.
    ; so construct a quick 10-cycle loop and run it 404.5 times. 
    ; Or how abut 404, since there are a few other extraneous instructions being thrown about?
   
 ldx #0 ; 1-byte immediate = 2 cycles load->store EXTRA
 
gloveInitDelay1:
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveInitDelay1 ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
    ; only need 148 more, so
 ldx #148 ; 2 cycles EXTRA
 
gloveInitDelay2:
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveInitDelay2 ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
    ; now that we've done some more stuff for "2260" microseconds
   
    ; "yo, Glove, listen up"
 lda #0
 sta $4016
    ; pad a few cycles, maybe not the full 5micro, but give it some time
    ; besides, this will make switching the latch faster
    ldx #0
    ldy #1
 
    ; 0x06, 0xC1, 0x08, 0x00, 0x02, 0xFF, 0x01 - a magic spell?
   
   
   
    ; $06 = %00000110 ?= "hey Glove, listen for 6 bytes of data"
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 sty $4016
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 jsr waitGloveClock
 stx $4016
 lda $4016 ; 0
 
 jsr waitGloveByte
 
    ; $C1 = %11000001 ?= ... no clue. $C byte return packets?
 sty $4016
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 jsr waitGloveClock
 stx $4016
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 sty $4016
 lda $4016 ; 1
 
 jsr waitGloveByte
 
    ; $08 = %00001000 ?= ... no clue. $08 bit precision?
 stx $4016
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 sty $4016
 lda $4016 ; 1
 jsr waitGloveClock
 stx $4016
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 
 jsr waitGloveByte
 
    ; $00 = %00000000 ?= ... no clue
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 
 jsr waitGloveByte
 
    ; $02 = %00000010 ?= ... no clue
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 sty $4016
 lda $4016 ; 1
 jsr waitGloveClock
 stx $4016
 lda $4016 ; 0
 
 jsr waitGloveByte
 
    ; $FF = %11111111 ?= "stopbyte- message ends"
 sty $4016
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 jsr waitGloveClock
 lda $4016 ; 1
 
 jsr waitGloveByte
 
    ; $01 = %00000001 ?= "have a checksum!"
 stx $4016
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 lda $4016 ; 0
 jsr waitGloveClock
 sty $4016
 lda $4016 ; 1
 
 
    ; 892 microseconds is 1596.68 cycles
    ; that's ~like~ 1600, or 160 10-loops
 ldx #160 ; 2 cycles EXTRA
 
gloveClearDelay:
 iny ; 2 cycles, dummy op
 iny ; 2 cycles, dummy op
 dex ; 2 cycles
 bne gloveClearDelay ; branch takes 2 cycles to load/compare, and an additinal 2 if the branch is taken
 iny ; 2 cycle dummy to absorb the 2 cycles of not-branching
 
    ; aaaaand clear.  Finally.
 stx $4016
 
 lda #3
 sta waitdelay
    ; go make a sandwich (for something like 40000 microseconds.  Honestly, if it cares at this point, I will be sad.)
 jsr waitloop
 
 jmp main_loop


What's that? "How did I find the exact cycle-count for instructions"? By putting a frelling 6502 together in Verilog some 7 years ago as a class project :P And keeping mercifully good notes on the architectural state machine I derived, which iirc matched someone else's cycle-count chart which I appear to have lost. If this site is still taking docs, I might be able to dig up and submit anything useful I still have around.

edit: n/m- found it. Cycle counts were also staring me in the face on a chart I wasn't looking for them on.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Mar 31, 2012 9:56 pm 
Offline

Joined: Mon Jul 07, 2008 7:40 pm
Posts: 61
Round 3 test:

* First piece of new NES software to successfully use the PowerGlove hi-res mode in... 20 years? First piece of new PG code on any platform in... 10? Anyway, I've cracked it.

* Secret PowerGlove mantra? "Slow the fsck down." Performance only improved/stabilized the more room I gave it around clocks & latches. Now that I've got a stable demo, I can start pulling the small delays and see whether all of them are ~really~ needed, but at very least you need to give it time to capture its data. 2 60Hz frames to stream out a packet, and 2 more before you ask it again.

* the "header" byte seems to uniformly be %01011111 ($5F). You should key into this, because if you don't give the glove quite enough time between polls, or if you make it compute too much at once (e.g. by closing a fist to trigger all finger sensors while moving/rotating), the packet does seem to drift a few bytes. Give it time to relax again and it seems to straighten itself out.

* the buttons byte is in an odd format, not the usual NES 1-bit-per-button. I'll post a full breakdown at some point, but in general the indications are one button at a time is available on any given sample, stored as a numeric code in the 4 lowbits. Either Start or Select also shows up in bit 7 (high). Bits 6-4 seem to be 1 when any button is down, 0 otherwise.

* bytes are returned high bit to low bit, in case there was any question

* Z (screen-depth) position seems to maybe be absolute, X and Y seem to reset with the Center button (although holding Center is one of those taxing things that will throw your packet timing off). Haven't gone into values in depth, but they do appear to be 2's complement, and they also appear amazingly stable. Not rock-solid, but better than the impression I got from the newsgroup thread.

* rotation is in something like clock-hour increments, as reported elsewhere. The high 4 bits are 1s, the low bits register at very most 16 positions, but 12 or 8 wouldn't surprise me on closer investigation.

This code will get you values out of the glove, but I don't yet promise it's optimal.

Code:

main_loop:
 
 jsr waitNMI
 
; [ppu code omitted]
 
 
 ldx #0 ; byte index
glovePollLoop1Byte:
 ldy #0 ; bit counter
    ; latch - 5microseconds = ~9 cycles
 lda #1
 sta $4016 ; 4 cycles
 inx ; 2 cycle dummy
 dex ; 2 cycle undo-dummy
 lda #0 ; 2 cycles
 sta $4016 ; 4 cycles
 inc temp0 ; 6 cycles dummy
 
glovePollLoop1Bit:
 lda $4016 ; 4 cycles
 lsr A ; 2 cycles
 ; rol gloveData,X ; 6 cycles
 .db $36,$20 ; stupid nesasm
    ; and with the bne, that's 20 cycles of the 39 we "need"
    ; for now, I'm going to cross my fingers.
    ; ... or not
 inc temp0 ; 6 cycles dummy
 dec temp0 ; 6 cycles dummy
 inc temp0 ; 6 cycles dummy
 cmp #0 ; 2 cycles dummy
 iny ; 2 cycles
 cpy #8 ; 2 cycles
 bne glovePollLoop1Bit ; 4 cycles when we care
 
 stx temp0 ; waitGloveByte makes x 0
 jsr waitGloveByte
 ldx temp0
 
 inx
 cpx #8
 bne glovePollLoop1Byte
 

    ; in this respect, I'll believe The Infallible Trace Diagram, at least for now
    ; a 64-bit shift register would have been prime hardware, and 96-bits would
    ; have been just plain odd.  Probably the Glove does need time to shift in
    ; the remaining 4 bytes.
 
 jsr waitNMI
 
; [ppu code omitted]
 
    ; and we're back.
 ldx #8 ; byte index
 glovePollLoop2Byte:
 ldy #0 ; bit counter
    ; latch - 5microseconds = ~9 cycles
 lda #1
 sta $4016 ; 4 cycles
 inx ; 2 cycle dummy
 dex ; 2 cycle undo-dummy
 lda #0 ; 2 cycles
 sta $4016 ; 4 cycles
 inc temp0 ; 6 cycles dummy
 
glovePollLoop2Bit:
 lda $4016 ; 4 cycles
 lsr A ; 2 cycles
 ; rol gloveData,X ; 6 cycles
 .db $36,$20 ; stupid nesasm
    ; and with the bne, that's 20 cycles of the 39 we "need"
    ; for now, I'm going to cross my fingers.
    ; ... or not
 inc temp0 ; 6 cycles dummy
 dec temp0 ; 6 cycles dummy
 inc temp0 ; 6 cycles dummy
 cmp #0 ; 2 cycles dummy
 iny ; 2 cycles
 cpy #8 ; 2 cycles
 bne glovePollLoop2Bit ; 4 cycles when we care
 
 stx temp0 ; waitGloveByte makes x 0
 jsr waitGloveByte
 ldx temp0
 
 inx
 cpx #12
 bne glovePollLoop2Byte
 
    ; and that's a wrap

    ; and in closing, yes, it really does need 2 full 60Hz frames
    ; to get its bits together for the next poll.  15fps updates ftw.
 jsr waitNMI
 jsr waitNMI

 jmp main_loop   ; loop


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 64 posts ]  Go to page 1, 2, 3, 4, 5  Next

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group