-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patharchie-verse.asm
615 lines (482 loc) · 13.2 KB
/
archie-verse.asm
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
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
; ============================================================================
; Archie-Verse: a Acorn Archimedes demo/trackmo framework.
; ============================================================================
; ============================================================================
; Defines for a specific build.
; ============================================================================
.equ _DEBUG, 1
.equ _SMALL_EXE, 0 ; TODO: Configure from Makefile?
.equ _SLOW_CPU, 0 ; ARM2 @ 8MHz. TODO: Set dynamically.
.equ _LOG_SAMPLES, (_SMALL_EXE && 1)
.equ _DEBUG_RASTERS, (_DEBUG && 1)
.equ _DEBUG_SHOW, (_DEBUG && 1)
.equ _CHECK_FRAME_DROP, (!_DEBUG && 0)
.equ _SYNC_EDITOR, (_DEBUG && 1) ; sync driven by external editor.
.equ DebugDefault_PlayPause, 1 ; play
.equ DebugDefault_ShowRasters, 0
.equ DebugDefault_ShowVars, 0 ; slow
; ============================================================================
; Includes.
; ============================================================================
.include "src/app_config.h.asm"
.include "lib/swis.h.asm"
.include "lib/lib_config.h.asm"
.include "lib/maths.h.asm"
.include "lib/macros.h.asm"
.include "lib/debug.h.asm"
; ============================================================================
; Code Start
; ============================================================================
.org 0x8000
; ============================================================================
; Main
; ============================================================================
Start:
main:
ldr sp, stack_p
; Claim the Event vector.
MOV r0, #EventV
ADR r1, event_handler
MOV r2, #0
SWI OS_Claim
; Claim the Error vector.
MOV r0, #ErrorV
ADR r1, error_handler
MOV r2, #0
SWI OS_Claim
; TODO: Do we need this outside of _DEBUG?
; Install our own IRQ handler - thanks Steve! :)
.if AppConfig_InstallIrqHandler
bl install_irq_handler
.else
mov r0, #OSByte_EventEnable
mov r1, #Event_VSync
SWI OS_Byte
.endif
; Generate sample data first?
.if AppConfig_UseArchieKlang
bl archieklang_init
.endif
; Library initialisation.
bl lib_init
; Returns R12=top of RAM used.
; Allocate and clear screen buffers etc.
bl app_init_video
; Initialise the music player etc.
; Param R12=top of RAM used.
bl app_init_audio
; EARLY INIT - LOAD STUFF HERE!
; Bootstrap the main sequence.
; Does one tick of the script!
bl sequence_init
; LATE INITALISATION HERE!
bl get_next_bank_for_writing ; NB. Replace with bl get_screen_addr to see font plotting.
; Can now write to the screen for final init.
ldr r12, screen_addr
bl app_late_init
; Enable key pressed event.
mov r0, #OSByte_EventEnable
mov r1, #Event_KeyPressed
SWI OS_Byte
; Play music!
QTMSWI QTM_Start
; Show whatever app_init set up as the first frame.
bl mark_write_bank_as_pending_display
; Reset vsync count.
ldr r0, vsync_count
str r0, last_vsync
main_loop:
; ========================================================================
; PREPARE
; ========================================================================
bl app_pre_tick_frame
.if _DEBUG
bl debug_do_key_callbacks
ldrb r0, debug_restart_flag
cmp r0, #0
blne debug_restart_sequence
ldrb r0, debug_main_loop_pause
cmp r0, #0
bne .3
ldrb r0, debug_main_loop_step
cmp r0, #0
beq main_loop_skip_tick
.3:
.endif
.if AppConfig_UseSyncTracks
bl sync_update_vars
.endif
; ========================================================================
; TICK
; ========================================================================
bl script_tick_all
.if LibConfig_IncludeMathVar
; Tick after script as this is where vars will be added/removed.
bl math_var_tick ; TODO: Here or app_tick or lib_tick?
; Tick before layers as this is where the vars will be used.
.endif
bl fx_tick_layers
; Update frame counter.
ldr r0, frame_counter
ldr r1, max_frames
add r0, r0, #1
cmp r0, r1
.if SeqConfig_EnableLoop
movge r0, #0
str r0, frame_counter
blge sequence_init
.else
str r0, frame_counter
bge exit
.endif
.if AppConfig_UseSyncTracks
ldr r0, frame_counter ; TODO: frames vs syncs.
bl sync_set_time
.endif
.if _DEBUG
mov r0, #-1
mov r1, #-1
QTMSWI QTM_Pos ; read position.
strb r1, music_pos+0
strb r0, music_pos+1
.endif
main_loop_skip_tick:
.if _DEBUG
mov r0, #0
strb r0, debug_main_loop_step
.endif
; ========================================================================
; VSYNC
; ========================================================================
; This will block if there isn't a bank available to write to.
bl get_next_bank_for_writing
; Useful to determine frame rate for debug or frame-rate independent animation.
ldr r1, last_vsync
ldr r2, vsync_count
sub r0, r2, r1
str r2, last_vsync
str r0, vsync_delta
.if _DEBUG
ldr r1, vsyncs_missed
sub r0, r0, #1
add r1, r1, r0
str r1, vsyncs_missed
.endif
; R0 = vsync delta since last frame.
.if _CHECK_FRAME_DROP
; This flashes if vsync IRQ has no pending buffer to display.
ldr r2, last_dropped_frame
ldr r1, last_last_dropped_frame
cmp r2, r1
moveq r4, #0x000000
movne r4, #0x0000ff
strne r2, last_last_dropped_frame
bl palette_set_border
.endif
; ========================================================================
; DRAW
; ========================================================================
; TODO: app_pre_draw_frame if needed.
bl fx_draw_layers
; show debug
.if _DEBUG
ldr r12, screen_addr
bl debug_plot_vars
.endif
; Swap screens!
bl mark_write_bank_as_pending_display
; repeat!
swi OS_ReadEscapeState
bcc main_loop ; exit if Escape is pressed
exit:
; Disable music
mov r0, #0
QTMSWI QTM_Clear
; Remove our IRQ handler
.if AppConfig_InstallIrqHandler
bl uninstall_irq_handler
.else
; Disable vsync event
mov r0, #OSByte_EventDisable
mov r1, #Event_VSync
swi OS_Byte
.endif
; Disable key press event
mov r0, #OSByte_EventDisable
mov r1, #Event_KeyPressed
swi OS_Byte
; Release our event handler
mov r0, #EventV
adr r1, event_handler
mov r2, #0
swi OS_Release
; Release our error handler
mov r0, #ErrorV
adr r1, error_handler
mov r2, #0
swi OS_Release
; Display whichever bank we've just written to
mov r0, #OSByte_WriteDisplayBank
ldr r1, write_bank
swi OS_Byte
; and write to it
mov r0, #OSByte_WriteVDUBank
ldr r1, write_bank
swi OS_Byte
; Flush keyboard buffer.
mov r0, #15
mov r1, #1
swi OS_Byte
.if AppConfig_UseQtmEmbedded
adr lr, .1
ldr pc, QtmEmbedded_Exit
.1:
.endif
; Goodbye.
SWI OS_Exit
; ============================================================================
; Debug helpers.
; ============================================================================
.if _DEBUG
debug_toggle_main_loop_pause:
ldrb r0, debug_main_loop_pause
eor r0, r0, #1
strb r0, debug_main_loop_pause
; Toggle music.
cmp r0, #0
.if AppConfig_UseQtmEmbedded
stmfd sp!, {r11,lr}
moveq r11, #QTM_Pause-QTM_SwiBase ; pause
movne r11, #QTM_Start-QTM_SwiBase ; play
mov lr, pc
ldr pc, QtmEmbedded_Swi
ldmfd sp!, {r11,lr}
.else
swieq QTM_Pause ; pause
swine QTM_Start ; play
.endif
.if AppConfig_UseSyncTracks
b sync_set_is_playing
.else
mov pc, lr
.endif
debug_restart_sequence:
; Start music again.
mov r0, #0
strb r0, debug_restart_flag
mov r1, #0
QTMSWI QTM_Pos
; Start script again.
b sequence_init
debug_skip_to_next_pattern:
mov r0, #-1
mov r1, #-1
QTMSWI QTM_Pos ; read position.
add r0, r0, #1
cmp r0, #SeqConfig_MaxPatterns
movge pc, lr
bl sequence_jump_to_pattern
mov r1, #0
QTMSWI QTM_Pos ; set position.
mov pc, lr
.endif
; ============================================================================
; System stuff.
; ============================================================================
stack_p:
.long stack_base_no_adr
screen_addr_input:
.long VD_ScreenStart, -1
last_vsync:
.long 0
vsync_delta:
.long 0
.if _DEBUG
vsyncs_missed:
.long 0
.endif
.if _CHECK_FRAME_DROP
last_dropped_frame:
.long 0
last_last_dropped_frame:
.long 0
.endif
frame_counter:
.long 0
max_frames:
.long SeqConfig_MaxFrames
.if _DEBUG
music_pos:
.long 0
.endif
; R0=event number
event_handler:
.if _DEBUG
cmp r0, #Event_KeyPressed
; R1=0 key up or 1 key down
; R2=internal key number (RMKey_*)
beq debug_handle_keypress
.endif
.if !AppConfig_InstallIrqHandler
cmp r0, #Event_VSync
bne event_handler_return
STMDB sp!, {r0-r1,r11-r12,lr}
b app_vsync_code
exitVs:
LDMIA sp!, {r0-r1,r11-r12,lr}
.endif
event_handler_return:
mov pc, lr
.if _DEBUG
b debug_handle_keypress
.else
mov pc, lr
.endif
mark_write_bank_as_pending_display:
; Mark write bank as pending display.
ldr r1, write_bank
; What happens if there is already a pending bank?
; At the moment we block but could also overwrite
; the pending buffer with the newer one to catch up.
; TODO: A proper fifo queue for display buffers.
.1:
ldr r0, pending_bank
cmp r0, #0
bne .1
str r1, pending_bank
; Convert palette buffer to VIDC writes here!
ldr r2, vidc_buffers_p
add r2, r2, r1, lsl #6 ; 64 bytes per bank
ldr r3, palette_array_p
cmp r3, #0
moveq r0, #-1 ; no palette to set.
streq r0, [r2]
beq .2
; TODO: Could think about a palette dirty flag.
mov r4, #0
.3:
ldr r0, [r3], #4 ; 0x00BbGgRr
; Convert from OSWORD to VIDC format.
mov r7, r0, lsr #20
and r7, r7, #0xf ; 0xB
mov r6, r0, lsr #12
and r6, r6, #0xf ; 0xG
mov r5, r0, lsr #4
and r5, r5, #0xf ; 0xR
orr r0, r5, r6, lsl #4
orr r0, r0, r7, lsl #8 ; 0xBGR
orr r0, r0, r4, lsl #26 ; VIDC_ColN = N << 26
str r0, [r2], #4
add r4, r4, #1
cmp r4, #16
blt .3
.2:
; Show pending bank at next vsync.
MOV r0, #OSByte_WriteDisplayBank
swi OS_Byte
mov pc, lr
get_next_bank_for_writing:
; Increment to next bank for writing
ldr r1, write_bank
add r1, r1, #1
cmp r1, #VideoConfig_ScreenBanks
movgt r1, #1
; Block here if trying to write to displayed bank.
.if VideoConfig_ScreenBanks > 1
.1:
ldr r0, displayed_bank
cmp r1, r0
beq .1
.endif
str r1, write_bank
; Now set the screen bank to write to
mov r0, #OSByte_WriteVDUBank
swi OS_Byte
get_screen_addr:
; Back buffer address for writing bank stored at screen_addr
adrl r0, screen_addr_input
adrl r1, screen_addr
swi OS_ReadVduVariables
mov pc, lr
error_handler:
STMDB sp!, {r0-r2, lr}
.if AppConfig_InstallIrqHandler
bl uninstall_irq_handler
.else
mov r0, #OSByte_EventDisable
mov r1, #Event_VSync
SWI OS_Byte
.endif
; Release event handler.
MOV r0, #OSByte_EventDisable
MOV r1, #Event_KeyPressed
SWI OS_Byte
MOV r0, #EventV
ADR r1, event_handler
mov r2, #0
SWI OS_Release
; Release error handler.
MOV r0, #ErrorV
ADR r1, error_handler
MOV r2, #0
SWI OS_Release
; Write & display current screen bank.
MOV r0, #OSByte_WriteDisplayBank
LDR r1, write_bank
SWI OS_Byte
; Do these help?
; QTMSWI QTM_Stop
LDMIA sp!, {r0-r2, lr}
MOVS pc, lr
; ============================================================================
; Core code modules
; ============================================================================
screen_addr:
.long 0 ; ptr to the current VIDC screen bank being written to.
init_screen_addr:
.long 0 ; ptr to the screen displayed during [long] init.
displayed_bank:
.long 0 ; VIDC sreen bank being displayed
write_bank:
.long 0 ; VIDC screen bank being written to
pending_bank:
.long 0 ; VIDC screen to be displayed next
vsync_count:
.long 0 ; current vsync count from start of exe.
palette_array_p:
.long 0 ; pointer to the palette array for this frame.
vidc_buffers_p:
.long vidc_buffers_no_adr - 64
.if _DEBUG
debug_main_loop_pause:
.byte DebugDefault_PlayPause
debug_main_loop_step:
.byte 0
debug_show_info:
.byte DebugDefault_ShowVars
debug_show_rasters:
.byte DebugDefault_ShowRasters
debug_restart_flag:
.byte 0
.p2align 2
.endif
; ============================================================================
; Support library code modules used by the FX.
; ============================================================================
.include "lib/debug.asm"
.include "lib/fx.asm"
.include "lib/script.asm"
.include "lib/sequence.asm"
.if AppConfig_UseSyncTracks
.include "src/sync.asm"
.endif
.include "src/app.asm"
.include "lib/lib_code.asm"
; ============================================================================
; DATA Segment
; ============================================================================
.include "src/data.asm"
; ============================================================================
; BSS Segment
; ============================================================================
.include "src/bss.asm"