User:TakuikaNinja/Code snippets

From NESdev Wiki
< User:TakuikaNinja
Revision as of 06:34, 6 July 2024 by TakuikaNinja (talk | contribs) (Optimise 8-bit PRNG routine.)
Jump to navigationJump to search

This page contains various code snippets intended for use in future articles. Snippets without explicit mentions of being used in commercial games are considered to have no licenses, and may be used freely.

BCD byte to binary

This takes in a packed BCD byte and converts it to binary form. The result is also a valid base 100 value.

; Parameter: A = BCD value to decode
; Stores the hexadecimal value in Res
; Returns the hexadecimal value in A
; (result is also a valid base 100 value)
BCDToByte:
  pha ; save value for later
  and #$F0 ; letting x = 10's digit, convert 16x to 10x
  lsr a
  sta Res ; 16x/2
  lsr a
  lsr a ; 16x/8
  adc Res ; 16x/8 + 16x/2
  sta Res ; = 10x
  pla ; retrieve and add low nybble to result
  and #$0F
  adc Res ; carry is always clear
  sta Res
  rts

8-bit PRNG

This is an LCG of the form x = (5x + 1) % 256, ported from Z80 code. It is fairly small and simple but has terrible entropy. It may be useful if you need random outcomes for infrequent/unimportant events.

; Crude 8-bit PRNG, exits with output in A
; Seed is both input/output, should be in zeropage for best performance
rand8:
  lda Seed
  asl Seed
  asl Seed
  sec
  adc Seed
  sta Seed
  rts

If you want something with higher quality output, consider using this 8-bit PRNG routine instead.

MMC3 scanline counter init

Commercial MMC3 games contain code to manually clock the scanline counter in the reset handler (after waiting for the PPU to warm up) by toggling PPU A12. This likely prevents undesirable behaviour caused by reloading the counter on consecutive scanlines. This snippet is present verbatim in most commercial games:

  bit $2002
  lda #$10
  tax
@loop:
  sta $2006
  sta $2006
  eor #$10
  dex
  bne @loop

The following snippet does the minimum amount of toggles required, and uses a ring counter to reduce the code size and cycle count. A12 is set to 0, 1, 0, 1, 0.

  bit $2002
  lda #%00001010
@loop:
  sta $2006
  sta $2006
  asl a
  bcc @loop

This unrolled snippet does the minimum amount of toggles required (similar code appears in Super Mario Bros. 3):

  bit $2002
  lda #$00
  sta $2006
  sta $2006
  lda #$10
  sta $2006
  sta $2006
  lda #$00
  sta $2006
  sta $2006
  lda #$10
  sta $2006
  sta $2006