yandagui 发表于 2023-7-16 20:13:54

[FC][Mapper5][IRQ学习源码]

;
;FlameCyclone 20230710

;文件头
;======================================================================
.INESPRG 4                                              ;16KB PRG 数量
.INESCHR 1                                             ;8KB CHR 数量
.INESMAP 5                                                   ;mapper 5
.INESMIR 1                                 ;命名表镜像 0水平 1垂直

;必要条件
;1.持有CHR ROM
;2.背景Tile和精灵Tile必须使用不同的图案表, 如背景图案$0000, 精灵图案$1000
;3.精灵内存(OAM)不为空

;==================================================
;NES端口常量
PPU_CTRL                =   $2000   ;PPU控制寄存器
PPU_MASK                =   $2001   ;PPU掩码寄存器
PPU_STATUS            =   $2002   ;PPU状态寄存器:读取后PPU_SCROLL和PPU_ADDRESS被复位,下一个写到PPU_SCROLL的数据是水平的,写到PPU_ADDRESS的数据是高位
PPU_OAM_ADDR            =   $2003   ;精灵RAM地址:用来设置通过PPU_OAM_DATA访问的256字节精灵RAM地址。每次访问PPU_OAM_DATA后该地址增加1
PPU_OAM_DATA            =   $2004   ;精灵RAM数据:用来读/写精灵内存。地址通过PPU_OAM_ADDR来设置,每次访问后地址增加1
PPU_SCROLL            =   $2005   ;屏幕滚动偏移:第一个写的值会进入垂直滚动寄存器(若>239,被忽略)。第二个值出现在水平滚动寄存器
PPU_ADDRESS             =   $2006   ;VRAM地址:设置PPU_DATA访问的VRAM地址。第一个写地址的高6位。第二个写低8位。每次访问PPU_DATA后地址增加
PPU_DATA                =   $2007   ;VRAM数据:用来访问VRAM数据,通过PPU_ADDRESS设置的地址在每次访问之后会增加1或32
OAM_DMA               =   $4014   ;DMA访问精灵RAM:通过写一个值xx到这个端口,引起CPU内存地址为$xx00-$xxFF的区域传送到精灵内存
APU_STATUS            =   $4015   ;声音通道切换
JOY1_FRAME            =   $4016   ;手柄1 + 选通
JOY2_FRAME            =   $4017   ;手柄2 + 选通

;==================================================
;MMC5端口常量
MMC5_PRG_MODE               =   $5100; 0: 32KB 1: 16KB * 2 2: 16KB + 8 * 2 3: 8*4
MMC5_CHR_MODE               =   $5101; 0: 8KB 1: 4KB * 2 2: 2KB * 4 3: 1KB * 8
MMC5_PRG_RAM_PROTECT_1      =   $5102;
MMC5_PRG_RAM_PROTECT_2      =   $5103;
MMC5_EX_RAM_MODE            =   $5104; 0: Write Only 1: Write Only 2: RW 3:R
MMC5_NT_MAPPING             =   $5105;
MMC5_FILL_MODE_TILE         =   $5106
MMC5_FILL_MODE_COLOR      =   $5107

MMC5_PRG_BANK_6000          =   $5113
MMC5_PRG_BANK_8000          =   $5114
MMC5_PRG_BANK_A000          =   $5115
MMC5_PRG_BANK_C000          =   $5116
MMC5_PRG_BANK_E000          =   $5117
   
MMC5_CHR_BANK_0000          =   $5120
MMC5_CHR_BANK_0400          =   $5121
MMC5_CHR_BANK_0800          =   $5122
MMC5_CHR_BANK_0C00          =   $5123
MMC5_CHR_BANK_1000          =   $5124
MMC5_CHR_BANK_1400          =   $5125
MMC5_CHR_BANK_1800          =   $5126
MMC5_CHR_BANK_1C00          =   $5127

MMC5_CHR_BANK_0000_1000   =   $5128
MMC5_CHR_BANK_0400_1400   =   $5129
MMC5_CHR_BANK_0800_1800   =   $512A
MMC5_CHR_BANK_0C00_1C00   =   $512B
   
MMC5_CHR_BANK_UPPER         =   $5130
MMC5_V_SPLIT_MODE         =   $5200
MMC5_V_SPLIT_SCROLL         =   $5201
MMC5_V_SPLIT_BANK         =   $5202
   
MMC5_IRQ_SCAN_CMP         =   $5203
MMC5_IRQ_STATUS             =   $5204
MMC5_MULTIPLIER_A         =   $5205
MMC5_MULTIPLIER_B         =   $5206
   
MMC5A_CL3_SL3_DATA          =   $5207
MMC5A_CL3_SL3_STATUS      =   $5208
MMC5A_IRQ_TIMER_LSB         =   $5209
MMC5A_IRQ_TIMER_MSB         =   $520A

;==================================================
;程序块配置
BANK_DATA_MASK          = $07
;--------------------------------------------------
RESET_BANK            = $07
RESET_ADDR            = $FC00

;==================================================
;图像块配置
CHR_DATA_BANK         = $08

;==================================================
;零页内存地址配置
Use_Ram_Addr            = $80
PPU_Ctrl_Buf            = Use_Ram_Addr
PPU_Msak_Buf            = PPU_Ctrl_Buf + $01
PPU_Scroll_H            = PPU_Msak_Buf + $01
PPU_Scroll_V            = PPU_Scroll_H + $01
FC_Data_L               = PPU_Scroll_V + $01
FC_Data_H               = FC_Data_L + $01
FC_Data_Buf             = FC_Data_H + $01
;==================================================

GAMEPAD_MERGE_FLAG = $04

Gamepad_Keep            =       FC_Data_Buf + 1
Gamepad_Once            =       Gamepad_Keep + 2
Gamepad_Temp            =       Gamepad_Once + 2
                              
Gamepad_0_State         =       Gamepad_Temp + 2
Gamepad_1_State         =       Gamepad_0_State + 1
Gamepad_0_Value         =       Gamepad_1_State + 1
Gamepad_1_Value         =       Gamepad_0_Value + 1
Gamepad_Port_Value      =       Gamepad_1_Value + 1
Gamepad_Merge         =       Gamepad_Port_Value + 1

;==================================================
IRQ_Index               =       Gamepad_Merge + $01
;==================================================

;CHR图形数据
;==================================================
.BANK CHR_DATA_BANK
.INCBIN "chr_bank/chr_data.chr"

.BANK RESET_BANK & BANK_DATA_MASK
.ORG RESET_ADDR

;--------------------------------------------------
Attributes_Data
;命名表属性
.DB $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00
.DB $50,$50,$50,$50,$50,$50,$50,$50,$FF,$FF,$FF,$FF,$BB,$AA,$AA,$AA
.DB $0F,$0F,$0F,$0F,$0B,$0A,$0A,$0A,$AA,$AA,$AA,$AA,$AA,$AA,$AA,$AA
.DB $AA,$AA,$AA,$AA,$AA,$AA,$AA,$55,$55,$55,$55,$55,$55,$55,$55,$55
;--------------------------------------------------
;调色板数据
Palette_Data
.DB $0F,$27,$20,$0F,$0F,$24,$20,$0F,$0F,$21,$20,$0F,$0F,$25,$20,$0F
.DB $0F,$24,$20,$0F,$0F,$24,$20,$0F,$0F,$24,$20,$0F,$0F,$24,$20,$0F

;==================================================
;命名表初始化
Init_Name_Table
LDA #$20
STA PPU_ADDRESS
LDA #$00
STA PPU_ADDRESS
LDA #$00
LDY #$00
LDX #$10
Init_Name_Table_Write
STA PPU_DATA
INY
BNE Init_Name_Table_Write
DEX
BNE Init_Name_Table_Write
RTS

;==================================================
;调色板初始化
Init_Palette
BIT PPU_STATUS
LDA #$3F
STA PPU_ADDRESS
LDA #$00
STA PPU_ADDRESS
LDX #$00
Init_Palette_Write
LDA Palette_Data,X
STA PPU_DATA
INX
CPX #$20
BCC Init_Palette_Write
RTS

;==================================================
;设置命名表属性
Init_NameTable_Attributes
BIT PPU_STATUS
LDA #$23
STA PPU_ADDRESS
LDA #$C0
STA PPU_ADDRESS
LDX #$00
Init_NameTable_Attributes_Write
LDA Attributes_Data,X
STA PPU_DATA
INX
CPX #$40
BCC Init_NameTable_Attributes_Write
RTS

;==================================================
;初始化命名表文本
Init_Name_Table_Text
BIT PPU_STATUS
LDA #$20
STA PPU_ADDRESS
LDA #$00
STA PPU_ADDRESS
LDA #$00
STA FC_Data_Buf
LDY #30
Init_Name_Table_Text_Write
LDX #32
Init_Name_Table_Text_Write_Char
LDA #'0'
CLC
ADC FC_Data_Buf
STA PPU_DATA
DEX
LDA #$14
STA PPU_DATA
DEX
BNE Init_Name_Table_Text_Write_Char
INC FC_Data_Buf
DEY
BNE Init_Name_Table_Text_Write
RTS

;==============================
Init_OAM_Ram;初始化精灵内存
LDX #$00
LDA #$00
STA PPU_OAM_ADDR
LDA #$F8
Init_OAM_Ram_Write
STA PPU_OAM_DATA
INX
BNE Init_OAM_Ram_Write
RTS

GamepadProcess;手柄处理
JSR GamepadDatacan
LDA <Gamepad_0_Value
STA <Gamepad_0_State
LDA <Gamepad_1_Value
STA <Gamepad_1_State
JSR GamepadDatacan
LDX #$01
GamepadMergeCheck;合并手柄输入检查
LDA <Gamepad_0_Value,X
CMP <Gamepad_0_State,X
BEQ GamepadMergeInput
LDA <Gamepad_Temp,X
STA <Gamepad_0_Value,X
GamepadMergeInput;合并手柄输入
DEX
BPL GamepadMergeCheck
LDA <Gamepad_Merge
AND #GAMEPAD_MERGE_FLAG
BNE GamepadStateProcess
LDA <Gamepad_0_Value
ORA <Gamepad_1_Value
STA <Gamepad_0_Value
GamepadStateProcess;手柄状态处理
LDX #$01
GamepadStateSave;手柄状态保存
LDA <Gamepad_0_Value,X
TAY
EOR <Gamepad_Temp,X
AND <Gamepad_0_Value,X
STA <Gamepad_Once,X
STY <Gamepad_Keep,X
STY <Gamepad_Temp,X
DEX
BPL GamepadStateSave
RTS

GamepadDatacan;手柄数据扫描
LDX #$01
STX $4016
DEX
STX $4016
LDY #$08
GamepadPortScan;手柄端口扫描
LDA $4016
STA <Gamepad_Port_Value
LSR A
ORA <Gamepad_Port_Value
LSR A
ROL <Gamepad_0_Value
LDA $4017
STA <Gamepad_Port_Value
LSR A
ORA <Gamepad_Port_Value
LSR A
ROL <Gamepad_1_Value
DEY
BNE GamepadPortScan
RTS

;==================================================
;PPU处理
PPU_Process
LDA #$00
STA PPU_MASK

BIT PPU_STATUS
LDA #$20
STA PPU_ADDRESS
LDA #$00
STA PPU_ADDRESS

STA PPU_SCROLL
STA PPU_SCROLL

LDA PPU_Msak_Buf
STA PPU_MASK

RTS

;==============================
Time_For_Vblank;延时等待
LDA PPU_STATUS
BPL Time_For_Vblank
RTS

;==================================================
;初始化MMC5
Init_MMC5

;设置一下6000-7FFF的RAM
LDA #$00
STA MMC5_PRG_BANK_6000

;开启 PRG RAM 写入
LDA #$02
STA MMC5_PRG_RAM_PROTECT_1
LDA #$01
STA MMC5_PRG_RAM_PROTECT_2

;启用 1KB 扩展RAM ($5C00-$5FFF)
LDA #$02
STA MMC5_EX_RAM_MODE

;设置 CHR
LDA #$00
STA MMC5_CHR_BANK_0000
LDA #$01
STA MMC5_CHR_BANK_0400
LDA #$02
STA MMC5_CHR_BANK_0800
LDA #$03
STA MMC5_CHR_BANK_0C00
LDA #$04
STA MMC5_CHR_BANK_1000
LDA #$05
STA MMC5_CHR_BANK_1400
LDA #$06
STA MMC5_CHR_BANK_1800
LDA #$07
STA MMC5_CHR_BANK_1C00

;设置屏幕镜像
LDA #$50
STA MMC5_NT_MAPPING

;禁用IRQ
LDA #$00
STA MMC5_IRQ_SCAN_CMP
STA MMC5_IRQ_STATUS

RTS

;==================================================
;重置中断处理
ResetProgram
SEI
CLD
LDA #$00
STA PPU_CTRL
STA PPU_MASK
STA PPU_STATUS
STA JOY2_FRAME
STA APU_STATUS

LDA #$C0
STA JOY2_FRAME

;等待vblank
LDX #$02
Vblank_Wait_1
BIT PPU_STATUS
BPL Vblank_Wait_1
Vblank_Wait_2
BIT PPU_STATUS
BMI Vblank_Wait_2
DEX
BNE Vblank_Wait_1

LDX #$FF
TXS

;初始化MMC5
JSR Init_MMC5

;==============================
;RAM初始化
Nes_Ram_Init
LDY #$00
LDX #$08
LDA #$00
STA <$00
STA <$01
Nes_Ram_Init_Write
STA [$00],Y
INY
BNE Nes_Ram_Init_Write
INC <$01
DEX
BNE Nes_Ram_Init_Write

;初始化命名表
JSR Init_Name_Table

;初始化调色板
JSR Init_Palette

;初始化命名表属性
JSR Init_NameTable_Attributes

;初始化精灵内存
JSR Init_OAM_Ram

;在屏幕上写点东西
JSR Init_Name_Table_Text

JSR Time_For_Vblank
;开启PPU控制
LDA #$88
STA PPU_Ctrl_Buf
STA PPU_CTRL

;开启PPU显示
LDA #$1E
STA PPU_Msak_Buf

CLI
JMP Loop

;==============================
;死循环, 等待NMI中断
Loop
JMP Loop

;==================================================
;NMI中断处理
NmiProgram
PHA
TXA
PHA
TYA
PHA

BIT PPU_STATUS

;启动IRQ中断, 第16条扫描线触发
LDA #16
STA MMC5_IRQ_SCAN_CMP
LDA #$80
STA MMC5_IRQ_STATUS
CLI

;关闭PPU控制
LDA #$00
STA PPU_CTRL

;处理PPU
JSR PPU_Process

;开启PPU控制
LDA PPU_Ctrl_Buf
STA PPU_CTRL

;手柄处理
JSR GamepadProcess

LDA #$00
STA IRQ_Index

PLA
TAY
PLA
TAX
PLA
RTI

;==================================================
;IRQ中断处理
IrqProgram
PHA
TXA
PHA
TYA
PHA

;确认IRQ
LDA MMC5_IRQ_STATUS

;允许下个IRQ触发
LDA #$80
STA MMC5_IRQ_STATUS

;IRQ处理, 每隔16条扫描线触发
LDA <IRQ_Index
CLC
ADC #$02
ASL A
ASL A
ASL A
ASL A
STA MMC5_IRQ_SCAN_CMP

LDA <IRQ_Index
BNE * + 4
INC <PPU_Scroll_H

;设置屏幕滚动
LDA <IRQ_Index
AND #$01
BEQ Irq_Scroll_Right

Irq_Scroll_Left
BIT PPU_STATUS
LDA <PPU_Scroll_H
STA PPU_SCROLL
STA PPU_SCROLL
JMP Irq_Scroll_Over

Irq_Scroll_Right
SEC
SBC <PPU_Scroll_H
STA PPU_SCROLL
STA PPU_SCROLL
Irq_Scroll_Over

INC <IRQ_Index

LDA <IRQ_Index
CMP #14
BCC * + 5
;关闭IRQ
LDA #$00
STA MMC5_IRQ_STATUS

IrqProgramEnd
PLA
TAY
PLA
TAX
PLA
RTI

;==================================================
;中断表
.ORG $FFFA
.WORD NmiProgram
.WORD ResetProgram
.WORD IrqProgram
页: [1]
查看完整版本: [FC][Mapper5][IRQ学习源码]