Stupid problems with autoread on hardware
Moderator: Moderators
Forum rules
- For making cartridges of your Super NES games, see Reproduction.
Stupid problems with autoread on hardware
I have two problems.
One: the programs I've written have horrible problems with button bounce, much bigger than anything I've written on the NES. Am I doing something wrong, or is this a known flaw?
Two: In trying to diagnose the above button bounce, I wrote a simple program (It's a simplified subset of tepples's spadtest, which does work on my hardware) that draws a series of lines (one pixel per button per vsync) corresponding to the buttons that are pressed. It works correctly in every emulator I've tried (including bsnes-plus but not higan), but not on hardware (always returning no-buttons-pressed). What could I be doing wrong?
One: the programs I've written have horrible problems with button bounce, much bigger than anything I've written on the NES. Am I doing something wrong, or is this a known flaw?
Two: In trying to diagnose the above button bounce, I wrote a simple program (It's a simplified subset of tepples's spadtest, which does work on my hardware) that draws a series of lines (one pixel per button per vsync) corresponding to the buttons that are pressed. It works correctly in every emulator I've tried (including bsnes-plus but not higan), but not on hardware (always returning no-buttons-pressed). What could I be doing wrong?
Re: Stupid problems with autoread on hardware
If you're only reading input from $421x instead of using the NES-style registers, are you remembering to wait for bit 0 of $4212 to be cleared before reading?
bsnes-plus still (incorrectly) treats auto joypad read as being instantaneous, but higan doesn't. (Consider that added to the TODO list, I guess.)
bsnes-plus still (incorrectly) treats auto joypad read as being instantaneous, but higan doesn't. (Consider that added to the TODO list, I guess.)
Re: Stupid problems with autoread on hardware
Yeah, there's a poll loop for not VBl, then for yes VBl, then for not autoread...
I probably should have just included the core loop in the first place:
[/size]
I probably should have just included the core loop in the first place:
Code: Select all
loop:
seta8
loop1:
bit VBLSTATUS ; Wait for NOT vblank
bmi loop1
loop2:
bit VBLSTATUS ; Wait for NEW vblank
bpl loop2
lda #$01
padwait:
bit VBLSTATUS ; wait for autoread done
bnz padwait
;; first we need to transform the count into a PPU address
;; kjihgfedcba (bits of count)
;; kjihgfed0cba
seta16
lda count
asl
and #$0FF0
clc
adc #56*16*2
sta temp
lda count
and #7
ora temp
sta temp
sta PPUADDR
seta8
lda JOY1CUR+1
stz PPUDATA+1
sta PPUDATA
seta16
lda temp
ora #8
sta PPUADDR
inc count
seta8
lda JOY1CUR
stz PPUDATA+1
sta PPUDATA
lda #$ff
sta PPUDATA+1
stz PPUDATA
jmp loop
Re: Stupid problems with autoread on hardware
Maybe NMIs need to be on? That's just a wild guess, based on nothing other than both those functions being enabled by the same register.
Here's what the code in my NSF player looks like, including the main loop.
Here's what the code in my NSF player looks like, including the main loop.
Code: Select all
...
lda #%10000001 ; enable controller and NMI
sta $4200
...
Code: Select all
;---------------------------------------------------
check_buttons:
-
lda $4212
and #%00000001
bne -
lda joy1
sta joy1old
lda joy1+1
sta joy1old+1
lda $4218
sta joy1
lda $4219
sta joy1+1
rts
;---------------------------------------------------
Code: Select all
;============================================
; Main loop
; waits for 60hz interrupt
; runs NES code
; runs graphics display code
; emulates 60hz length counter
; [runs temporary linear counter simulator]
; updates APU with NES register contents
; checks joypads and processes such
; resets $4016 (used by $4015 evaluator)
; go to beginning of main loop
;--------------------------------------------
wait:
wai
; jsr set_bg_nsf
jsl $7F5000 ; NSF play
phk
plb
jsr display_options
jsr detect_changes
; jsr emulate_sweep
jsr backup_regs
; jsr emulate_linear_counter
jsr emulate_length_counter
jsr triangle_tempfix
jsr update_dsp
jsr check_buttons
jsr proc_buttons
; jsr read_oam
lda #0
sta $7F4016
; jsr set_bg_black
jmp wait
Re: Stupid problems with autoread on hardware
The easy way:
1. Set bit 0 of $4200 (NMITIMEN) to 1. This makes the SNES automatically populate registers $4218-421f with joypad data "shortly" after VBlank (more on that in a second).
2. Wait for bit 0 of $4212 (HVBJOY) to be 0 before reading joypad data (registers $4218-421f); if bit 0 is 1, the joypads aren't ready to be read yet.
Alternately, if you're timing-focused, you can wait approximately 215 microseconds *from the beginning/start of VBlank* before reading the controller registers -- but IMO, just use the $4212 polling method described, it's reliable. It's common to stick some general purpose DMA at the start of VBlank, which often ends up taking more than 215 microseconds (depends on amount of data being transferred), so that's an alternate approach to the $4212 poll. But I still recommend just polling $4212. :-)
I've attached documentation referencing this timing (it's mentioned in 2 places) and all of the above. I may end up getting the files in the wrong order; if so, my apologies. I'll follow up with more attachments in a subsequent post (note to Memblers and/or Tepples: 3 attachments per post is annoying, can we bump that up to 5? I've run into this limit 2 or 3 times in the past couple months).
The superfamicom.org wiki actually covers all of this pretty well (including dealing with held vs. tapped buttons) -- this is not a resource I commonly refer to, but in this case it's great! https://wiki.superfamicom.org/snes/show ... ller+Input
Some additional things:
This is a 65816: you can read $4218 with a 16-bit register and it'll read both $4218 and $4219 (all buttons/directions for joypad #1) in a single lda/ldx/ldy. It's weird that both of you read these registers with 8-bit registers -- maybe habits from 6502/NES days? While I'm on that subject...
The SNES has registers $4016 and $4017 which are NES-compatible for joypad reads (the only read-1-bit-at-a-time method). If you choose to use it, you need to make sure bit 0 of $4200 is set to 0, after which you can just read $4016/4017 like on the NES. And also when bit 0 of $4200 is 0: bit 0 of $4016 *on a read* acts as an indicator to tell you if the joypad is connected or not (I've never actually used this myself, I just always assume joypads are connected, but the code for detection makes sense); see the final attachment describing the registers.
There is a weird "edge case" for controller input (this would be of interest to the hardware folks, as it pertains to level vs. edge detection) _if_ you ever disable joypad reading after enabling it. If you want those details, including code, I can provide it -- just ask.
Edit: few edits to clarify additional points, and fix a register typo.
(2018/08/29 Edit: attachments removed.)
1. Set bit 0 of $4200 (NMITIMEN) to 1. This makes the SNES automatically populate registers $4218-421f with joypad data "shortly" after VBlank (more on that in a second).
2. Wait for bit 0 of $4212 (HVBJOY) to be 0 before reading joypad data (registers $4218-421f); if bit 0 is 1, the joypads aren't ready to be read yet.
Alternately, if you're timing-focused, you can wait approximately 215 microseconds *from the beginning/start of VBlank* before reading the controller registers -- but IMO, just use the $4212 polling method described, it's reliable. It's common to stick some general purpose DMA at the start of VBlank, which often ends up taking more than 215 microseconds (depends on amount of data being transferred), so that's an alternate approach to the $4212 poll. But I still recommend just polling $4212. :-)
I've attached documentation referencing this timing (it's mentioned in 2 places) and all of the above. I may end up getting the files in the wrong order; if so, my apologies. I'll follow up with more attachments in a subsequent post (note to Memblers and/or Tepples: 3 attachments per post is annoying, can we bump that up to 5? I've run into this limit 2 or 3 times in the past couple months).
The superfamicom.org wiki actually covers all of this pretty well (including dealing with held vs. tapped buttons) -- this is not a resource I commonly refer to, but in this case it's great! https://wiki.superfamicom.org/snes/show ... ller+Input
Some additional things:
This is a 65816: you can read $4218 with a 16-bit register and it'll read both $4218 and $4219 (all buttons/directions for joypad #1) in a single lda/ldx/ldy. It's weird that both of you read these registers with 8-bit registers -- maybe habits from 6502/NES days? While I'm on that subject...
The SNES has registers $4016 and $4017 which are NES-compatible for joypad reads (the only read-1-bit-at-a-time method). If you choose to use it, you need to make sure bit 0 of $4200 is set to 0, after which you can just read $4016/4017 like on the NES. And also when bit 0 of $4200 is 0: bit 0 of $4016 *on a read* acts as an indicator to tell you if the joypad is connected or not (I've never actually used this myself, I just always assume joypads are connected, but the code for detection makes sense); see the final attachment describing the registers.
There is a weird "edge case" for controller input (this would be of interest to the hardware folks, as it pertains to level vs. edge detection) _if_ you ever disable joypad reading after enabling it. If you want those details, including code, I can provide it -- just ask.
Edit: few edits to clarify additional points, and fix a register typo.
(2018/08/29 Edit: attachments removed.)
Last edited by koitsu on Wed Aug 29, 2018 6:53 pm, edited 4 times in total.
Re: Stupid problems with autoread on hardware
(2018/08/29 Edit: attachments removed.)
Last edited by koitsu on Wed Aug 29, 2018 6:53 pm, edited 1 time in total.
Re: Stupid problems with autoread on hardware
Another thought: are you initializing $2115?
Since you're always writing the high byte of PPUDATA first, 00 is the value it seems like it should have, but if you're assuming it has that state on powerup then it might explain why there are problems in higan and on the real hardware.
Since you're always writing the high byte of PPUDATA first, 00 is the value it seems like it should have, but if you're assuming it has that state on powerup then it might explain why there are problems in higan and on the real hardware.
Re: Stupid problems with autoread on hardware
The PNG file states that it takes 576 slow cycles to finish reading. This is just barely more than the time to send an entire 544-byte display list to OAM using a DMA copy.
The standard controller does in fact return all 1's after the report (8-bit for NES or 16-bit for Super NES), and my controller detection demo for NES currently relies on this. But I've seen third-party NES controllers that instead return all 0's, particularly the U-Force.koitsu wrote:bit 0 of $4016 *on a read* acts as an indicator to tell you if the joypad is connected or not (I've never actually used this myself, I just always assume joypads are connected, but the code for detection makes sense)
Re: Stupid problems with autoread on hardware
I honestly couldn't give less of a shit about licensed third-party controllers, especially garbage like the UForce, but your point about $4016 behaviour is obviously is still valid. This comment now forces me to post the timing thing I mentioned. I don't know whether or not it's relevant to this situation, however. I've pieced together the relevant bits into a single picture.tepples wrote:The standard controller does in fact return all 1's after the report (8-bit for NES or 16-bit for Super NES), and my controller detection demo for NES currently relies on this. But I've seen third-party NES controllers that instead return all 0's, particularly the U-Force.
(2018/08/29 Edit: attachments removed.)
Last edited by koitsu on Wed Aug 29, 2018 6:53 pm, edited 1 time in total.
Re: Stupid problems with autoread on hardware
Only because I'm splitting the data across two tiles. Doing it in two 8-bit accesses made more sense to me than relaying the 16-bit value via RAM and then handling it separately. (I've tried the latter and it failed in the same way.)koitsu wrote:This is a 65816: you can read $4218 with a 16-bit register and it'll read both $4218 and $4219 (all buttons/directions for joypad #1) in a single lda/ldx/ldy. It's weird that both of you read these registers with 8-bit registers -- maybe habits from 6502/NES days?
(I've handled all the other things you mention as common pitfalls)
Well, I've cleaned up the full source a little bit. Maybe someone else can figure out what I'm doing wrong ... or at least establish whether it also fails on their hardware.
- Attachments
-
- buttonlog-20170122.7z
- (13.16 KiB) Downloaded 189 times
Re: Stupid problems with autoread on hardware
From anomie's docs:
So waiting for "begin of vblank", does somehow ensure that your code will collide with autoread.
Even if you've tested the joypad busy bit to be cleared - it will be set shortly thereafter.
Code: Select all
When enabled, the SNES will read 16 bits from each of the 4 controller port
data lines into registers $4218-f. This begins between H=32.5 and H=95.5 of
the first V-Blank scanline, and ends 4224 master cycles later. Register $4212
bit 0 is set during this time.
Even if you've tested the joypad busy bit to be cleared - it will be set shortly thereafter.
Re: Stupid problems with autoread on hardware
Ohhhhhhhhhhhhhhhhh. That tiny delay between vblank starting and autoread starting is just enough CPU cycles to screw everything up.
So evidently I can just poll for "autoread" then "not autoread" and always end up a few scanlines into vblank.
That you so much!
So evidently I can just poll for "autoread" then "not autoread" and always end up a few scanlines into vblank.
That you so much!