|
Post by ccovell on Feb 7, 2019 7:50:03 GMT
Does anyone know if there are any 6-button joypads that do not return the 2nd set of direction bits as %0000? Chris? I have only the one Avenue Pad 6, so I can't say.
|
|
|
Post by elmer on Feb 7, 2019 8:42:23 GMT
Which means, bits 0 & 2 (UP & DOWN) are just as valid a check as 1 & 3 (LEFT & RIGHT) -> That is, if it is a "normal" 2-button joypad, having both opposing directions held down simultaneously should be a physical impossibility. So when the 6-button joypad returns all zeroes, that's the sign that it's not a regular joypad. I think that you're missing the point that I was trying to make ... "yes" the code is definitely checking for an impossible combination of bits to see if there is a 6-button controller attached. But *why* check for just 2 bits, and *only* Up & Down, when that check involves using an AND and an OR instruction, and when you can just check for all 4 values being zero, which is a test for zero that doesn't involve any instructions at all ... it's free!!! That's what I want to know. Were Hudson reserving the ability to test for the "impossible" Left & Right combination for some other type of controller in the future ... or do all 6-button joypads always return all 4-bits as pressed? As far as I know, they all return zeroes on that scan, and I can't believe that any 6-button joypad would behave in any other way; they just took a shortcut in the detection code. As I mentioned, when I look at it, it's not a shortcut, it's actually a long-way-around (even if only 4-cycles-per-test). I'm not sure how you're getting it to be twice as fast, unless you're omitting the mandatory delay (hardware latency) between twiddling the control lines and waiting for the return signal... but as long as that is preserved, more power to you. Well, you have made things easy for me with the delay, since HuC's code uses a delay that is much longer than the 9 cycles that both the documentation recommends, and that most of the games that I've looked at actually use. Running a quick test ... HuC's code takes 2453 cycles for 5 pads, and my code takes 1272 cycles for 5 pads. Actually, it's only 1222 cycles, but I need to add an extra 50 cycles to keep HuC's distinction between JOYTRG and JOYBUF which I removed from my code. Here you go (please excuse the renaming of a couple of variables) ... read_joypads: tii joynow,joyold,5 ; Save the previous values. tii joy6now,joy6old,5
stz joy6now + 0 ; Clear the 6-btn bits in case stz joy6now + 1 ; the joypad was unplugged. stz joy6now + 2 stz joy6now + 3 stz joy6now + 4
bsr .read_once ; Read all the pads once. bsr .read_once ; Read again to get extra bits.
ldy #4 .calc_pressed: lda joy6now,y ; Calc which buttons have just eor joy6old,y ; been pressed. and joy6now,y ora joy6trg,y ; Unlike the System Card, here sta joy6trg,y ; the "trg" is cumulative and lda joynow,y ; must be cleared when used. eor joyold,y and joynow,y tax ora joytrg,y sta joytrg,y
cpx #$04 ; Detect the soft-reset combo. bne .calc_next lda joynow,y cmp #$0C bne .calc_next lda .pad_mask,y bit joyena beq .calc_next
.soft_reset: lda #$80 ; Disable the BIOS PSG driver. sta <$e7 jmp [$2284] ; Jump to the soft-reset hook.
.calc_next: dey bpl .calc_pressed rts
.pad_mask: .db $01,$02,$04,$08,$10
; Read the joypads from the multitap.
.read_once: lda #$01 ; CLR lo, SEL hi. sta joyport lda #$03 ; CLR hi, SEL hi, reset multitap. sta joyport
cly .get_pad: lda #$01 ; SEL hi for direction-pad. sta joyport pha ; Wait 1.25us (9 cycles). pla tsx lda joyport ; Read direction-pad bits. asl a asl a asl a asl a stz joyport ; SEL lo for buttons. bit #$50 ; Wait 1.25us (9 cycles). pha beq .got_pad6 ; 6-btn pad if UDLR all held. nop
.got_pad2: lda joyport ; Get buttons of 2-btn pad. and #$0F ora $2100,x eor #$FF sta joynow,y
.get_next: txs ; Get the next pad from the iny ; multitap. cpy #$05 bne .get_pad
rts
.got_pad6: lda joyport ; Get buttons of 6-btn pad. and #$0F eor #$8F ; Set bit-7 to show that a sta joy6now,y ; 6-button pad is present. bra .get_next
I'm also not sure whether there's an easy way to differentiate between those two devices (mouse and 6-button), but hopefully my answer above yields a hint. Nope, I'm afraid that I'm still stuck. I need to look at a few more of the existing games' mouse-detection functions.
|
|
|
Post by elmer on Feb 7, 2019 8:59:29 GMT
I'm not sure why Elmer is giving such an emphasis on "quick", because those checks should usually be done once per game when talking about such different devices (mouse vs. pad), I'd simply stop the game and ask for the player to reconnect the mouse or simply fall back to a controller when bad data suddenly starts showing up. I'm not fussing about the initial detection for the device types, I'm having difficulty coming up with efficient code to deal with both a mouse, and with the 6-button pad's uncertainty about whether you are reading the normal buttons, or the extra buttons, in any particular cycle through the multitap. Perhaps I'll dream up a solution while I sleep.
|
|
|
Post by theoldman on Feb 7, 2019 9:00:08 GMT
Ok. I was using a seperate supply for the pi, and driving the controller outputs via the GPIO lines. That allowed me to fake the 74HC157, using 4 outputs. Maybe that's not the way to do it.... Funny, that's what I thought as well. Under raspbian, it does.
But it boots at only 300Mhz. You have to change the processor flags, which you can only do in certain CPU modes to get the faster speed. I gave up trying to do all of that, since it involves things I really don't understand yet. (Enabling the data/instruction caches, dealing with the memory timing, setting up the address space, etc.) I believe it was the GPIO timing. I have no concrete proof of that (I'm not a hardware guy), but writing the 4th nibble of the controller would consistantly result in the PCE reading it as the 5th nibble. Oddly, the 6th nibble was usually fine, in part (I suspect) due to the longer wait for odd nibbles. But I don't have any proof, and can't come up with a good way to test it. GPIO on the pi is odd to me; to send a digital value requires 2 writes. One write sets the 0 bits, and a second write (to a different register) sets the 1 bits. It's actually not as simple as writing a 1 or a 0 (in fact, writing a 0 means no change) Doing the bits individually was too slow for sure, so I used block writes. Somewhere while doing this I read that the GPIO is actually controlled by another processor. I believe they were discusssing how fast you could just read the values for a software oscilloscope application. Somewhere in that thread, someone mentioned the GPIO timing, and that changing the outputs (on the standard boot setup) required 10ms. At that point, a simple project started becoming too complex to do the way it needed to be done. Maybe some day I'll come back to it.
|
|
|
Post by dshadoff on Feb 7, 2019 15:23:15 GMT
But *why* check for just 2 bits, and *only* Up & Down, when that check involves using an AND and an OR instruction, and when you can just check for all 4 values being zero, which is a test for zero that doesn't involve any instructions at all ... it's free!!! That's what I want to know. Were Hudson reserving the ability to test for the "impossible" Left & Right combination for some other type of controller in the future ... or do all 6-button joypads always return all 4-bits as pressed? If you've got a quick test program, I can verify that my Hori Fighting Commander PC does the same. As far as I know, they all return zeroes on that scan, and I can't believe that any 6-button joypad would behave in any other way; they just took a shortcut in the detection code. As I mentioned, when I look at it, it's not a shortcut, it's actually a long-way-around (even if only 4-cycles-per-test). Were they also doing it as you do - BIT #$50 ? I'm sure they were just looking for the minimum undefined scenario, rather than a specific scenario. I'm not sure how you're getting it to be twice as fast, unless you're omitting the mandatory delay (hardware latency) between twiddling the control lines and waiting for the return signal... but as long as that is preserved, more power to you. Well, you have made things easy for me with the delay, since HuC's code uses a delay that is much longer than the 9 cycles that both the documentation recommends, and that most of the games that I've looked at actually use. Cool ! We didn't have the documentation back when that was written; if memory serves, we were probably using the System Card as a model for the timing. The range of appropriate values for the delay weren't clear at first sight (seeing the delay at all was surprise enough) - it was obviously due to transition and settling time of the semiconductors; thee could be calculated from datasheets if mere 74LS157's were in place, but the multitap's VLSI-looking chip was a black box without an oscilloscope, so it's additive latency wasn't clear. We also didn't have resources to disassemble multiple games for more clues (and they realistically would have needed to be multitap-supporting games). That code looks good - but the imbalanced PHA caught my eye until I saw you were preserving/restoring the stack position from X. Ah, the good old days of programming.... Ok. I was using a seperate supply for the pi, and driving the controller outputs via the GPIO lines. That allowed me to fake the 74HC157, using 4 outputs. Maybe that's not the way to do it.... Yeah, it's not realistic to try to simulate strobe responses with GPIO, (unless they're driven by a programmable logic device). As elmer's code suggests, you have about a microsecond to detect, switch and latch values in response to the strobe. Probably less than that, since gate propagation inside of the PC Engine is also part of the overall latency. Dave
|
|
samiam
Punkic Cyborg
Posts: 100
|
Post by samiam on Feb 8, 2019 1:40:48 GMT
Hey elmer, did you ever check Battle Ace to see if it had any unused code for the SuperGrafx Power Console? For a refresher, here is a link to the translation I did of a magazine article about it, from before it was canned: www.pcenginefx.com/forums/index.php?topic=20883.0
|
|
|
Post by elmer on Feb 8, 2019 2:30:57 GMT
Hey elmer, did you ever check Battle Ace to see if it had any unused code for the SuperGrafx Power Console? Nope, I wouldn't have known what to look for. I probably have a slightly better idea now that I've looked at both the mouse code and the XHE-3 analog code. Unfortunately I'm *still* IP-address blocked from PCEFX by NW's childish little stunt, which he'll no doubt be happy to learn. Aaron hasn't cleared out the list of blocked IP addresses.
|
|
Deleted
Deleted Member
Posts: 0
|
Post by Deleted on Feb 8, 2019 3:11:45 GMT
Hey elmer, did you ever check Battle Ace to see if it had any unused code for the SuperGrafx Power Console? For a refresher, here is a link to the translation I did of a magazine article about it, from before it was canned: www.pcenginefx.com/forums/index.php?topic=20883.0You'll gotta have a deeper disassembly of Battle Ace for that I guess, since it was supposed to plug at the back (I think?). If it were a controller you'd just need to monitor $1000 reads and writes. And I'll second Elmer, I can see the public threads but not the one you linked so posting it here would be appreciated.
|
|
samiam
Punkic Cyborg
Posts: 100
|
Post by samiam on Feb 8, 2019 3:16:17 GMT
Unfortunately I'm *still* IP-address blocked from PCEFX by NW's childish little stunt, which he'll no doubt be happy to learn. Aaron hasn't cleared out the list of blocked IP addresses. I just sent him an email about that.
|
|
samiam
Punkic Cyborg
Posts: 100
|
Post by samiam on Feb 8, 2019 3:18:50 GMT
You'll gotta have a deeper disassembly of Battle Ace for that I guess, since it was supposed to plug at the back (I think?). If it were a controller you'd just need to monitor $1000 reads and writes. And I'll second Elmer, I can see the public threads but not the one you linked so posting it here would be appreciated. I think it was supposed to plug into the special I/O port that only the Supergrafx had, which is at the front right next to the main controller port. I'll copy in the translation soon.
|
|
|
Post by elmer on Feb 8, 2019 4:13:13 GMT
After seeing how different various games' mouse code is, I thought that it might be interesting to take a look at the XE-1AP/XE-1AJ analog stick support in Forgotten Worlds, and see if the code from a 1992 game was any different to punch 's disassembly from a 1990 game. Errrr, yep! Here it is ... ; *********************************************************** ; ; MENU CODE TO DETECT ANALOG PAD ; ; ($6A:417B in Forgotten Worlds) ;
lda <got_analog ; NZ if already detected. bne .already_found
jsr detect_analog ; Try once. jsr detect_analog ; Try again. bcs .not_found ; CC if detected.
inc <got_analog ; Set flag NZ.
; *********************************************************** ; ; ANALOG PAD DETECTION ROUTINE ; ; ($6A:5082 in Forgotten Worlds) ;
detect_analog: lda #$00 ; Initiate analog read sta joyport ; sequence.
pha ; Wait 1.25us (9 cycles). pla nop
lda #$02 ; Switch analog from sta joyport ; init to flags.
clx ; Initialize timeout counter. .wait_rdy_1st: dex beq .timeout ; Branch if timeout.
lda joyport ; Check the flags to see if the and #$03 ; 1st data nibble is ready. bne .wait_rdy_1st
lda #$03 ; Switch analog from sta joyport ; flags to data.
pha ; Wait 1.25us (9 cycles). pla nop
lda joyport ; Dummy read.
lda #$02 ; Switch analog from sta joyport ; data to flags.
pha ; Wait 1.25us (9 cycles). pla nop
clx ; Initialize timeout counter. .wait_rdy_2nd: dex beq .timeout ; Branch if timeout.
lda joyport ; Check the flags to see if the and #$03 ; 2nd data nibble is ready. cmp #$01 bne .wait_rdy_2nd
.found: clc ; Analogue Pad found! rts
.timeout: sec ; Analogue Pad missing! rts
; *********************************************************** ; ; UPDATE BIOS JOYPAD ; ; ($F8:3ECB in Forgotten Worlds) ; ; bit 0 (ie $01) = I ; bit 1 (ie $02) = II ; bit 2 (ie $04) = SELECT ; bit 3 (ie $08) = RUN ; bit 4 (ie $10) = UP ; bit 5 (ie $20) = RIGHT ; bit 6 (ie $40) = DOWN ; bit 7 (ie $80) = LEFT ;
read_joypad: lda <got_analog ; Are we using the analog pad? bne .got_analog
jmp ex_joysns ; If not, use the System Card routine.
.got_analog: jsr read_analog ; Read analog pad data.
lda joynow ; Save last joypad state. sta joyold
lda analog_now + 0 ; Map btn I = analog A or C lsr a ; Map btn II = analog B sta <temp lsr a lsr a and #$01 ora <temp and #$03 sta joynow
lda analog_now + 1 ; Map START & SEL btns. and #$03 asl a asl a ora joynow sta joynow
lda analog_trg + 0 ; Map btn I = analog A or C lsr a ; Map btn II = analog B sta <temp lsr a lsr a and #$01 ora <temp and #$03 sta joytrg
lda analog_trg + 1 ; Map START & SEL btns. and #$03 asl a asl a ora joytrg sta joytrg
ldy analog_now + 2 ; Map analog Y to digital. lda .y_spd_to_joy,y ora joynow sta joynow
ldy analog_now + 3 ; Map analog X to digital. lda .x_spd_to_joy,y ora joynow sta joynow
eor joyold ; Update dpad "just pressed". and joynow and #$F0 ora joytrg sta joytrg
rts
; Convert 4-bit analog values into digital values.
JOY_0 = $00 JOY_U = $10 JOY_R = $20 JOY_D = $40 JOY_L = $80
.y_spd_to_joy: db JOY_U, JOY_U, JOY_U, JOY_U, JOY_U, JOY_0, JOY_0, JOY_0 db JOY_0, JOY_0, JOY_0, JOY_0, JOY_D, JOY_D, JOY_D, JOY_D
.x_spd_to_joy: db JOY_L, JOY_L, JOY_L, JOY_L, JOY_L, JOY_0, JOY_0, JOY_0 db JOY_0, JOY_0, JOY_0, JOY_0, JOY_R, JOY_R, JOY_R, JOY_R
; *********************************************************** ; ; READ ANALOG PAD ; ; ($F8:3F5E in Forgotten Worlds) ; ; BIT 3 2 1 0 ; ; analog_now + 0 : A/A' B/B' C D ; analog_now + 1 : E1 E2 Strt Sel ; analog_now + 2 : Y7 Y6 Y5 Y4 ; analog_now + 3 : X7 X6 X5 X4 ; analog_now + 4 : T7 T6 T5 T4 ; analog_now + 5 : 0 0 0 0 ; ; analog_now + 6 : Y3 Y2 Y1 Y0 ; analog_now + 7 : X3 X2 X1 X0 ; analog_now + 8 : T3 T2 T1 T0 ; analog_now + 9 : 0 0 0 0 ; analog_now + A : A B A' B' ; analog_now + B : 1 1 1 1 ; ; Note : This code only reads the first 6 values. ;
analog_now: ds 6 analog_old: ds 2 analog_trg: ds 2
read_analog: lda #$00 ; Initiate analog read sta joyport ; sequence.
pha ; Wait 1.25us (9 cycles). pla nop
lda #$02 ; Switch analog from sta joyport ; init to flags.
; Read 1st 6 nibbles of data.
cly
.read_byte: ldx #$80 ; Initialize timeout counter. .wait_rdy_1st: dex beq .timeout ; Branch if timeout.
lda joyport ; Check the flags to see if the and #$03 ; 1st data nibble is ready. bne .wait_rdy_1st
jsr .read_nibble ; Read next nibble of data.
ldx #$80 ; Initialize timeout counter. .wait_rdy_2nd: dex beq .timeout ; Branch if timeout.
lda joyport ; Check the flags to see if the and #$03 ; 2nd data nibble is ready. cmp #$01 bne .wait_rdy_2nd
jsr .read_nibble ; Read next nibble of data.
cpy #6 bne .read_byte ; Read next byte of data.
; Check which btns have been pressed.
cly .pressed: lda analog_now,y ; Invert btn bits. eor #$0F sta analog_now,y eor analog_old,y ; Calc btn just pressed. and analog_now,y sta analog_trg,y lda analog_now,y ; Save old btn. sta analog_old,y iny cpy #$02 ; 2 nibbles of btn data. bcc .pressed
; Check for soft-reset.
lda analog_trg + 1 ; SEL btn just pressed? cmp #$01 bne .finished
lda analog_now + 1 ; SEL & START btn held? cmp #$03 bne .finished
jmp soft_reset ; SOFT-RESET
.finished: clc ; Signal Analog Pad found! rts
; Timeout while waiting for ready signal, pad missing.
.timeout: stz analog_now + 0 ; Reset current buttons. stz analog_now + 1 stz analog_trg + 0 ; Reset pressed buttons. stz analog_trg + 1
sec ; Signal Analog Pad missing! rts
; Read a nibble of analog data.
.read_nibble: lda #$03 ; Switch analog from sta joyport ; flags to data.
pha ; Wait 1.25us (9 cycles). pla nop
lda joyport ; Read the data nibble. and #$0F tax ; Remap it. lda .remap_tbl,x sta analog_now,y ; Store it. iny
lda #$02 ; Switch analog from sta joyport ; data to flags.
pha ; Wait 1.25us (9 cycles). pla nop rts
; Remap analog bits.
.remap_tbl: db $00, $01, $08, $09, $02, $03, $0A, $0B db $04, $05, $0C, $0D, $06, $07, $0E, $0F
|
|
|
Post by elmer on Feb 8, 2019 6:20:37 GMT
I have only the one Avenue Pad 6, so I can't say. Yeah, that's the only 6-button pad that I have, too. If you've got a quick test program, I can verify that my Hori Fighting Commander PC does the same. I'll put something together. Were they also doing it as you do - BIT #$50 ? The code in all of the games that I've looked at does the test much later (after the bits are inverted), with an AND #$50, CMP #$50 combination. We didn't have the documentation back when that was written; if memory serves, we were probably using the System Card as a model for the timing. ... We also didn't have resources to disassemble multiple games for more clues (and they realistically would have needed to be multitap-supporting games). Yep, it's SO much easier these days. I honestly don't know how you and the other pioneers got all of the wonderful things done that you did. That code looks good - but the imbalanced PHA caught my eye until I saw you were preserving/restoring the stack position from X. Ah, the good old days of programming.... Yep, it's nice to remember that we do have stack-addressing on the 6502 if we really want it ... it's just not usually worth the cost. In this case, I needed a temporary location, and the costs were almost-completely hidden by the delays that we need when accessing the joypad. Hey elmer, did you ever check Battle Ace to see if it had any unused code for the SuperGrafx Power Console? The S-EXP port is just an extension of the existing joypad port, with some extra bits ... so a game would access it with code that should look very similar to the normal joypad code, and so be easy to find. I just took a quick look, and I can't see any remnants of the Power Console code in there, sorry.
|
|
samiam
Punkic Cyborg
Posts: 100
|
Post by samiam on Feb 8, 2019 9:00:08 GMT
The S-EXP port is just an extension of the existing joypad port, with some extra bits ... so a game would access it with code that should look very similar to the normal joypad code, and so be easy to find. I just took a quick look, and I can't see any remnants of the Power Console code in there, sorry. Bummer! Well, thanks for looking. Battle Ace, and the SuperGrafx itself, came out in November 1989. In a retrospective published in June 1990, one developer said: Here is part of the translation I did before. Sorry about the Photobucket watermark. Battle Ace just had to have been designed to work with this thing, at least at some point. In the interview, they talk about encouraging/insisting that developers support it.
|
|
|
Post by ccovell on Feb 8, 2019 14:01:27 GMT
|
|
|
Post by elmer on Feb 9, 2019 4:17:35 GMT
So... I managed to write code for the controller on mednafen (that build of yours with the large font, elmer) but I have no idea how to compile it back, running make doesn't include my .cpps in the compiler/linker and there's a large amount of files in there. Yep, that's the joy of makefiles for you, you can't just add new files and have them automatically built and linked in. You'll need to either add your code into an existing file, or add an include for your file within an existing file, or edit the makefiles. If you're really getting that deep into modifying mednafen, then Dave may be able to help you get in touch with mednafen's authors. Or you can post on the mednafen forum. I'm also not sure whether there's an easy way to differentiate between those two devices (mouse and 6-button), but hopefully my answer above yields a hint. The only mouse-enabled game that I've looked at that actually works properly with a 6-button controller is "Princess Maker 2". All of the other games that I've checked think that the 6-button controller is a mouse (including Vasteel2). The detection code isn't very fast ... it takes approx 1/3s to run, but that's not too bad if you only run it once, when your game boots. Lemmings does a similar (slightly faster) check for a mouse, but it came out before 6-button pads existed, and it can't tell the difference.
|
|