Skip to content

Instantly share code, notes, and snippets.

@taotao54321
Created December 6, 2024 01:42
Show Gist options
  • Save taotao54321/22fe89edf7539032e98a4a3b0037dd88 to your computer and use it in GitHub Desktop.
Save taotao54321/22fe89edf7539032e98a4a3b0037dd88 to your computer and use it in GitHub Desktop.
6502 の除算ルーチンに時々見られる誤りの検証 (NES 用)
MEMORY {
INES: start=0, size=$10, fill=yes, fillval=0, file=%O;
PRG: start=$C000, size=$4000, fill=yes, fillval=0, file=%O;
}
SEGMENTS {
INES: load=INES, type=ro;
PRG: load=PRG, type=ro;
VECTORS: load=PRG, type=ro, start=$FFFA;
}
VRAM_MIRROR_H = 0 << 0
VRAM_MIRROR_V = 1 << 0
;---------------------------------------------------------------------
MAPPER = 0
VRAM_MIRROR = VRAM_MIRROR_H
PRG_COUNT = 1
CHR_COUNT = 0
.segment "INES"
.literal "NES", $1A
.byte PRG_COUNT
.byte CHR_COUNT
.byte VRAM_MIRROR | (MAPPER << 4)
.byte MAPPER & $F0
.PHONY: all verify clean
CMP := cmp
CA65 := ca65
LD65 := ld65
MKDIR := mkdir
OUT_DIR := build
OUT_NES := $(OUT_DIR)/division.nes
OUT_DBG := $(OUT_DIR)/division.dbg
OUT_LBL := $(OUT_DIR)/division.lbl
LD65_SCRIPT := division.ld65
OBJS := \
$(OUT_DIR)/ines.o \
$(OUT_DIR)/prg.o
all: $(OUT_NES)
$(OUT_NES): $(LD65_SCRIPT) $(OBJS)
$(LD65) --config $(LD65_SCRIPT) --dbgfile $(OUT_DBG) -Ln $(OUT_LBL) -o $@ $(OBJS)
$(OUT_DIR)/%.o: %.s65 | $(OUT_DIR)/.
$(CA65) --debug-info -o $@ $<
$(OUT_DIR)/.:
$(MKDIR) -p $@
clean:
-$(RM) -r $(OUT_DIR)
;=====================================================================
; 6502 の除算ルーチンに時々見られる誤りの検証
;=====================================================================
; 全ての除算ルーチンは以下のインターフェースを持つ:
;
; 引数
; lhs_quot 左辺 (u16le)
; rhs 右辺 (u8)
;
; 戻り値
; lhs_quot 商 (u16le)
; rem 余り (u8)
;
; 左辺と商については同一のメモリ領域を使い回している。
lhs_quot := $00
rhs := $02
rem := $03
;---------------------------------------------------------------------
.segment "PRG"
;---------------------------------------------------------------------
;;; RESET ハンドラ。
Reset:
@LHS = $8000
@RHS = $81
lda #<@LHS
sta lhs_quot
lda #>@LHS
sta lhs_quot+1
lda #@RHS
sta rhs
jsr DivCorrect
lda #<@LHS
sta lhs_quot
lda #>@LHS
sta lhs_quot+1
lda #@RHS
sta rhs
jsr DivWrongA
lda #<@LHS
sta lhs_quot
lda #>@LHS
sta lhs_quot+1
lda #@RHS
sta rhs
jsr DivWrongB
@loop_forever:
jmp @loop_forever
;;; 正しい u16 / u8 除算。
DivCorrect:
lda #0
sta rem
ldx #16
asl lhs_quot
rol lhs_quot+1
@loop:
; rem がオーバーフローしたら rhs を減算。
rol rem
bcs @subtract
; rem >= rhs ならば rhs を減算。
lda rem
cmp rhs
bcc @next
@subtract:
; ここでは常にキャリーフラグが真。
lda rem
sbc rhs
sta rem
sec ; rem がオーバーフローした場合、これが必要。
@next:
rol lhs_quot
rol lhs_quot+1
dex
bne @loop
rts
;;; 正しくない u16 / u8 除算 (余りのオーバーフローを考慮していない)。
DivWrongA:
lda #0
sta rem
ldx #16
asl lhs_quot
rol lhs_quot+1
@loop:
; XXX: ここでのオーバーフローを考慮していない!
rol rem
lda rem
cmp rhs
bcc @next
@subtract:
; ここでは常にキャリーフラグが真。
lda rem
sbc rhs
sta rem
@next:
rol lhs_quot
rol lhs_quot+1
dex
bne @loop
rts
;;; 正しくない u16 / u8 除算 (余りのオーバーフロー時、減算後にキャリーフラグをセットしていない)。
DivWrongB:
lda #0
sta rem
ldx #16
asl lhs_quot
rol lhs_quot+1
@loop:
rol rem
bcs @subtract
lda rem
cmp rhs
bcc @next
@subtract:
; ここでは常にキャリーフラグが真。
lda rem
sbc rhs
sta rem
; XXX: sbc で必ずキャリーフラグが真になると仮定しているが、rem がオーバーフローした場合これは成り立たない!
@next:
rol lhs_quot
rol lhs_quot+1
dex
bne @loop
rts
Nmi:
Irq:
rti
;---------------------------------------------------------------------
.segment "VECTORS"
;---------------------------------------------------------------------
VECTORS:
.addr Nmi
.addr Reset
.addr Irq
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment