1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
|
;
; Автор: Авдюхин Алексей / clusterrr@clusterrr.com / http://clusterrr.com
; Специально для Mail.ru Group
;
; INES header
.inesprg 128 * 1024 ; 16 банков PRG
.ineschr 128 * 1024 ; 16 банков CHR
.inesmir 0 ; горизонтальный мирроринг
.inesmap 3914 ; маппер #3914 (кастомный)
PPUCTRL .equ $2000
PPUMASK .equ $2001
PPUSTATUS .equ $2002
OAMADDR .equ $2003
OAMDATA .equ $2004
PPUSCROLL .equ $2005
PPUADDR .equ $2006
PPUDATA .equ $2007
OAMDMA .equ $4014
.rsset $0020 ; адрес для переменных
COPY_SOURCE_ADDR .rs 2 ; исходный адрес для копирования данный
COPY_DEST_ADDR .rs 2 ; целевой адрес для копирования данный
FRAMES .rs 1 ; счётчик NMI
ACTIVE_BANK .rs 1 ; текущий PRG банк
CONSOLE_TYPE .rs 1 ; тип консоли
PAL_SOURCE_ADDR .rs 2 ; исходный адрес для загрузки палитры
PALETTE_CACHE .rs 16 ; кеш для временного хранения палитры
SPRITES_ENABLED .rs 1 ; включены ли спрайты
TEXT_SOURCE_ADDR .rs 2 ; исходный адрес текста
TEXT_LINE .rs 1 ; текущая строка текста на экране
TEXT_POS .rs 2 ; текущая позиция текста в строке
TEXT_NAMETABLE .rs 1 ; текущий nametable для текста
TEXT_SCROLL_STARTED .rs 1 ; флаг, что запущен автоскроллинг
SCROLL_POS .rs 1 ; текущая позиция скроллинга
SCROLL_NT .rs 1 ; текущий nametable скроллинга
SCROLL_TARGET_POS .rs 1 ; целевая позиция скроллинга
THE_END .rs 1 ; флаг, что пора зациклить
BUTTONS .rs 1 ; currently pressed buttons
BUTTONS_TMP .rs 1 ; temporary variable for buttons
LAST_KONAMI_BUTTON .rs 1 ; last button state for Konami Code check
KONAMI_CODE_STATE .rs 1 ; Konami Code state
KONAMI_CODE_TRIGGERED .rs 1 ; Konami Code triggered flag
SYMBOL_COUNTER .rs 1 ; счтётчик напечатанных символов
.rsset $0400
SPRITES .rs 256 ; тут хранятся спрайты
.bank 12 ; PRG банк #12, середина PRG
.org $9152
music:
.incbin "music.bin" ; Музыка
.bank 15 ; PRG банк #15, конец PRG
.org $FFFA ; Векторы прерываний
.dw NMI ; NMI вектор
.dw RESET ; Ресет вектор $FFFA
.dw IRQ ; IRQ
; Тут начинается наш код
.bank 15
.org $FD00
RESET:
; сразу же отключаем любые прерывания
sei
; обнуляем стек
ldx #$ff
txs
; обнуление переменных
clear_memory:
lda #$00
sta <COPY_SOURCE_ADDR
sta <COPY_SOURCE_ADDR+1
lda #0
ldy #$02
.memory_clean_loop:
sta [COPY_SOURCE_ADDR], y
iny
bne .memory_clean_loop
lda #BANK(main)/2
jsr select_prg_bank
jmp main
; основное прерывание по таймеру картриджа
IRQ:
php
pha
tya
pha
txa
pha
; вызываем код музыки из предпоследнего банка
; заодно это делает ack прерыванию
lda #BANK(music)/2
sta $6000
; играем музыку
jsr $A99C
; читаем контроллер
lda #BANK(read_controller)/2
sta $6000
jsr read_controller
; возвращаем назад активный банк
lda <ACTIVE_BANK
sta $6000
pla
tax
pla
tay
pla
plp
rti
; прерывание по vblank
NMI:
php
pha
tya
pha
txa
pha
inc <FRAMES
; запускаем таймер в картридже
lda <ACTIVE_BANK
ora #%10000000
sta $6000
pla
tax
pla
tay
pla
plp
rti
; субрутина выбора PRG банка
select_prg_bank:
sta <ACTIVE_BANK
sta $6000
rts
; субрутина для выбора CHR банка с автопереключением
select_chr_auto_bank:
ora #%10000000
sta $6001
rts
; субрутина для выбора CHR банка без автопереключения
select_chr_solid_bank:
sta $6001
rts
; инициализация музыки
init_music:
lda ACTIVE_BANK
pha
lda #BANK(music)/2
jsr select_prg_bank
; номер трека
lda <CONSOLE_TYPE
; в регистре X задаётся регион: PAL или NTSC
ldx <CONSOLE_TYPE
; инициализируем музыкальный проигрыватель
jsr $A999
pla
jsr select_prg_bank
rts
; далее пихаем код в нулевой банк
.bank 0
.org $8000
enable_ppu:
lda #%00001110
ldx <SPRITES_ENABLED
beq .sprites_disabled
ora #%00010000
.sprites_disabled:
sta PPUMASK
jsr wait_blank_simple
rts
disable_ppu:
lda #%10000000
sta PPUCTRL
lda #%00000000
sta PPUMASK
jsr wait_blank_simple
rts
; субрутина простого ожидания vblank
wait_blank_simple:
pha
lda <FRAMES
.loop:
cmp <FRAMES
beq .loop
pla
rts
; субрутина ожидания vblank
wait_blank:
pha
tya
pha
txa
pha
; скроллим, если нужно
lda <SCROLL_POS
cmp <SCROLL_TARGET_POS
beq .end_scroll
inc <SCROLL_POS
lda <SCROLL_POS
cmp #240
bne .end_scroll
lda #0
sta <SCROLL_POS
lda <SCROLL_NT
eor #1
sta <SCROLL_NT
.end_scroll:
bit PPUSTATUS
lda #0
sta PPUSCROLL
lda <SCROLL_POS
sta PPUSCROLL
lda <SCROLL_NT
bne .second_nt
lda #%10000000
jmp .write_ppuctrl
.second_nt:
lda #%10000010
.write_ppuctrl
sta PPUCTRL
jsr wait_blank_simple
pla
tax
pla
tay
pla
rts
wait_blank_x:
.loop:
jsr wait_blank
dex
bne .loop
rts
; загружаем nametable в $2000
; в A номер банка
; в COPY_SOURCE_ADDR - адрес данных
load_name_table:
tax
lda ACTIVE_BANK
pha
txa
jsr select_prg_bank
lda #$20
sta $2006
lda #$00
sta $2006
ldy #$00
ldx #$04
.loop:
lda [COPY_SOURCE_ADDR], y
sta $2007
iny
bne .loop
inc <COPY_SOURCE_ADDR+1
dex
bne .loop
pla
jsr select_prg_bank
rts
reset_scroll:
lda #0
sta <SCROLL_POS
sta <SCROLL_NT
sta <SCROLL_TARGET_POS
rts
; waiting for button release
wait_buttons_not_pressed:
jsr wait_blank ; waiting for v-blank
lda <BUTTONS
bne wait_buttons_not_pressed
rts
; waiting for any button pressed
wait_any_button:
jsr wait_blank ; waiting for v-blank
lda KONAMI_CODE_TRIGGERED
bne .end
lda <BUTTONS
beq wait_any_button
.end
rts
pause:
jsr wait_buttons_not_pressed
;ldx #150
;jsr wait_blank_x
jsr wait_any_button
rts
.include "main.asm"
.include "clean.asm"
.include "dimming.asm"
.include "text.asm"
.include "buttons.asm"
.bank 1
.org $A000
title_palette:
.incbin "title_palette_0.bin"
.incbin "title_palette_1.bin"
.incbin "title_palette_2.bin"
.incbin "title_palette_3.bin"
frame_0_palette:
.incbin "frame_0_palette_0.bin"
.incbin "frame_0_palette_1.bin"
.incbin "frame_0_palette_2.bin"
.incbin "frame_0_palette_3.bin"
frame_1_palette:
.incbin "frame_1_palette_0.bin"
.incbin "frame_1_palette_1.bin"
.incbin "frame_1_palette_2.bin"
.incbin "frame_1_palette_3.bin"
frame_2_palette:
.incbin "frame_2_palette_0.bin"
.incbin "frame_2_palette_1.bin"
.incbin "frame_2_palette_2.bin"
.incbin "frame_2_palette_3.bin"
credits_palette:
.incbin "credits_palette_0.bin"
.incbin "credits_palette_1.bin"
.incbin "credits_palette_2.bin"
.incbin "credits_palette_3.bin"
symbols_palette:
.incbin "symbols_palette.bin"
.incbin "warface_palette.bin"
.db 0, 0, 0, 0
.db 0, 0, 0, 0
text_0:
.incbin "text_0.bin"
text_1:
.incbin "text_1.bin"
text_2:
.incbin "text_2.bin"
text_3:
.incbin "text_3.bin"
.include "sprites.asm"
.include "nametables.asm"
.include "patterns.asm"
|