Stupid problems with autoread on hardware

Discussion of hardware and software development for Super NES and Super Famicom.

Moderator: Moderators

Forum rules
  • For making cartridges of your Super NES games, see Reproduction.
Post Reply
lidnariq
Posts: 9382
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Stupid problems with autoread on hardware

Post by lidnariq » Sat Jan 21, 2017 10:03 pm

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?

Revenant
Posts: 441
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: Stupid problems with autoread on hardware

Post by Revenant » Sat Jan 21, 2017 10:58 pm

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.)

lidnariq
Posts: 9382
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Stupid problems with autoread on hardware

Post by lidnariq » Sun Jan 22, 2017 12:01 am

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:

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
[/size]

User avatar
Memblers
Site Admin
Posts: 3832
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: Stupid problems with autoread on hardware

Post by Memblers » Sun Jan 22, 2017 12:27 am

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.

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

User avatar
koitsu
Posts: 4217
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Stupid problems with autoread on hardware

Post by koitsu » Sun Jan 22, 2017 1:27 am

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.)
Last edited by koitsu on Wed Aug 29, 2018 6:53 pm, edited 4 times in total.

User avatar
koitsu
Posts: 4217
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Stupid problems with autoread on hardware

Post by koitsu » Sun Jan 22, 2017 1:27 am

(2018/08/29 Edit: attachments removed.)
Last edited by koitsu on Wed Aug 29, 2018 6:53 pm, edited 1 time in total.

Revenant
Posts: 441
Joined: Sat Apr 25, 2015 1:47 pm
Location: FL

Re: Stupid problems with autoread on hardware

Post by Revenant » Sun Jan 22, 2017 8:42 am

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.

tepples
Posts: 21973
Joined: Sun Sep 19, 2004 11:12 pm
Location: NE Indiana, USA (NTSC)
Contact:

Re: Stupid problems with autoread on hardware

Post by tepples » Sun Jan 22, 2017 10:03 am

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.
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)
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.

User avatar
koitsu
Posts: 4217
Joined: Sun Sep 19, 2004 9:28 pm
Location: A world gone mad

Re: Stupid problems with autoread on hardware

Post by koitsu » Sun Jan 22, 2017 10:18 am

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.
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.

(2018/08/29 Edit: attachments removed.)
Last edited by koitsu on Wed Aug 29, 2018 6:53 pm, edited 1 time in total.

lidnariq
Posts: 9382
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Stupid problems with autoread on hardware

Post by lidnariq » Sun Jan 22, 2017 4:39 pm

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?
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.)

(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 126 times

nocash
Posts: 1210
Joined: Fri Feb 24, 2012 12:09 pm
Contact:

Re: Stupid problems with autoread on hardware

Post by nocash » Sun Jan 29, 2017 1:55 pm

From anomie's docs:

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.
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.

lidnariq
Posts: 9382
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Re: Stupid problems with autoread on hardware

Post by lidnariq » Sun Jan 29, 2017 2:09 pm

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!

Post Reply