User:Zzo38/Hardware NSF

From NESdev Wiki
< User:Zzo38
Revision as of 19:43, 3 September 2012 by Zzo38 (talk | contribs)
Jump to navigationJump to search

These are some of my ideas for hardware NSF.

Hardware

Memory from $4018-$403F would be filled by a 40-byte ROM used for an interrupt routine. (Famicom Disk System uses some of these addresses but NSF only uses the audio registers, not these ones.)

When the main routine is enabled, $8000-$BFFF is a single byte of RAM (used to store the current song number; mirrored) and $C000-$FFFF is ROM (also mirrored; not much ROM is needed).

Writing to $4018-$403F: If bit2 is set, the memory from $6000-$DFFF becomes read/write, otherwise it is read-only. If bit0 is set, VRC6 audio will play, otherwise it will be muted. If bit1 is set, VRC7 audio will play and otherwise is muted. If bit5 is set, Sunsoft 5B audio is played and is otherwise muted. Other bits (bit3, bit4, bit6, and bit7) are ignored.

Writing to $C000-$FFFF enables main routine ROM if the low bit of the data is set, and disables if the low bit is clear. Other bits are ignored.

The hardware generate IRQ at the rate specified in the NSF header. When IRQ is called, the IRQ vector should be read as $4018 whenever it is checked.

Another thing the hardware will do is convert the audio to digital and whenever the name tables are being accessed, make the pattern tables read as a waveform view of the music being played.

Main Routine

  • Disable IRQ.
  • Wait for PPU.
  • Write the starting song number (offset $07 of header) to $8000, and then decrement it.
  • Copy expansion chip byte (offset $7B of header) to $4018.
  • Set up palette.
  • Fill up the nametable with the title and so on from the NSF header, and with the current and maximum song number, and indicate the music is stopped.
  • Enable background.
  • Loop:
    • Update the display of the current song number.
    • If LEFT is pushed:
      • Decrement current song number. If it is zero it wraps around.
      • Wait for button is not pushed.
    • If RIGHT is pushed:
      • Increment current song number. If it is too high it wraps to zero.
      • Wait for button is not pushed.
    • If START is pushed:
      • Initialize the sound registers by writing $00 to $4000-$4013, $0F to $4015.
      • Initialize the frame counter to 4-step mode ($40 to $4017).
      • Write initial bank values to $5FF6-$5FFF.
      • Update display to indicate song is playing.
      • Load value at memory $8000 into the accumulator.
      • Load zero into the X register.
      • Jump to the start routine.
  • Stop routine:
    • Disable interrupts.
    • Turn off all audio.
    • Reset the stack pointer.
    • Update display to indicate song is stopped.
    • Go to main loop checking which button is pushed.

Interrupt Routine

  • Check if the A button is pushed.
  • If the A button is pushed (it should branch if button pushed rather than skip over if unpushed because this way uses less clock cycles):
    • Enable main routine ROM.
    • Jump to the stop routine.
  • Reset the stack pointer.
  • Call the play subroutine.
  • Enable interrupts.
  • Run an idle loop doing nothing.
  • Start routine:
    • Disable main routine ROM.
    • Call the init subroutine.
    • Enable interrupts.
    • Run an idle loop doing nothing.

Code (40 bytes, 30 clock):

        .ORG $4018
intr    LDX #1       ; 2/2 (X=1)
        STX $4016    ; 3/4 (strobe)
        DEX          ; 1/2 (X=0)
        STX $4016    ; 3/4 (allow buttons to be read)
        LDA $4016    ; 3/4 (read "A" button)
        BNE stopa    ; 2/2 (branch if button pushed)
        DEX          ; 1/2 (X=255)
        TXS          ; 1/2 (reset stack)
        JSR play     ; 3/6
        CLI          ; 1/2
wait    JMP wait     ; 3/- (wait)
stopa   STA $C000    ; 3/- (write 1 to $C000)
        JMP stop     ; 3/-
start   STX $C000    ; 3/- (write 0 to $C000)
        JSR init     ; 3/-
        CLI          ; 1/-
        JMP wait     ; 3/-