-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathmemory.asm
490 lines (405 loc) · 12.5 KB
/
memory.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
; native assembly code. see memory.h for the C interface.
; .fopt compiler,"cc65 v 2.18 - Git 8b5a2f13"
.setcpu "65C02"
.smart on
.autoimport on
.case on
.debuginfo off
.importzp sp, sreg, regsave, regbank
.importzp tmp1, tmp2, tmp3, tmp4, ptr1, ptr2, ptr3, ptr4
.macpack longbranch
; import from lich king .c
; .import _some_variable
; export to lich king .c
.export _Memory_SwapInNewBank
.export _Memory_RestorePreviousBank
.export _Memory_GetMappedBankNum
; .export _Memory_Copy
; .export _Memory_CopyWithDMA
; .export _Memory_FillWithDMA
; .export _Memory_DebugOut
; ZP_LK exports:
.exportzp _zp_bank_slot
.exportzp _zp_bank_num
.exportzp _zp_old_bank_num
.exportzp _zp_to_addr
.exportzp _zp_from_addr
.exportzp _zp_copy_len
.exportzp _zp_phys_addr_lo
.exportzp _zp_phys_addr_med
.exportzp _zp_phys_addr_hi
.exportzp _zp_cpu_addr_lo
.exportzp _zp_cpu_addr_hi
.exportzp _zp_search_loc_byte
.exportzp _zp_search_loc_page
.exportzp _zp_search_loc_bank
.exportzp _zp_temp_1
.exportzp _zp_other_byte
.exportzp _zp_old_io_page
.exportzp _global_string_buffer
.exportzp _global_string_buffer2
; F256 DMA addresses and bit values
DMA_CTRL = $DF00 ; DMA Control Register
DMA_CTRL_START = $80 ; Start the DMA operation
DMA_CTRL_FILL = $04 ; Do a FILL operation (if off, will do COPY)
DMA_CTRL_2D = $02 ; Use 2D copy/fill
DMA_CTRL_ENABLE = $01 ; Enable the DMA engine
DMA_STATUS = $DF01 ; DMA status register (Read Only)
DMA_STAT_BUSY = $80 ; DMA engine is busy with an operation
DMA_FILL_VAL = $DF01 ; Byte value to use for fill operations
DMA_SRC_ADDR = $DF04 ; Source address (system bus - 3 byte)
DMA_DST_ADDR = $DF08 ; Destination address (system bus - 3 byte)
DMA_COUNT = $DF0C ; Number of bytes to fill or copy
.segment "ZEROPAGE" : zeropage
; -- ZEROPAGE starts at $10
_zp_bank_slot: .res 1 ; $10
_zp_bank_num: .res 1
_zp_old_bank_num: .res 1
_zp_to_addr: .res 3
_zp_from_addr: .res 3
_zp_copy_len: .res 3
_zp_phys_addr_lo: .res 1
_zp_phys_addr_med: .res 1
_zp_phys_addr_hi: .res 1
_zp_cpu_addr_lo: .res 1
_zp_cpu_addr_hi: .res 1 ; $20
_zp_search_loc_byte: .res 1
_zp_search_loc_page: .res 1
_zp_search_loc_bank: .res 1
_zp_temp_1: .res 1
_zp_other_byte: .res 1
_zp_old_io_page: .res 1 ;-- $26
_global_string_buffer: .res 2;
_global_string_buffer2: .res 2;
; ---------------------------------------------------------------
; uint8_t __fastcall__ Memory_SwapInNewBank(uint8_t the_bank_slot)
; ---------------------------------------------------------------
;// call to a routine in memory.asm that modifies the MMU LUT to bring the specified bank of physical memory into the CPU's RAM space
;// set zp_bank_num before calling.
;// returns the slot that had been mapped previously
.segment "CODE"
.proc _Memory_SwapInNewBank: near
.segment "CODE"
SEI ; disable IRQs just in case one hits in the middle if MMU mapping
TAX ; get the lut slot (0-7) we want to remap
.ifdef _SIMULATOR_ ; emulator seems to start with LUT0, but kernel on machine with lut3. not sure why emulator is different
LDA #$80 ; edit mode (bit 7) + edit lut #4 (bits 4-5 both on) + active lut stays as #4 (bits 0-1 on)
.else
LDA #$B3
.endif
STA $0000 ; make the change
LDA $0008,x ; before modifying the current map, get the current value of the bank we're about to remap
STA _zp_old_bank_num
LDA _zp_bank_num ; get the target physical bank # back
STA $0008,x ; Set the System bank to use for this bank
.ifdef _SIMULATOR_ ; emulator seems to start with LUT0, but kernel on machine with lut3. not sure why emulator is different
LDA #$00 ; Select LUT#0 as active, turn off editing
.else
LDA #$33 ; Select LUT#3 as active, turn off editing
.endif
STA $0000
; do the return. cc65 requires functions return a 16 bit value!
LDX #00
LDA _zp_old_bank_num
CLI ; safe to reenable IRQs now
RTS
.endproc
; ---------------------------------------------------------------
; void __fastcall__ Memory_RestorePreviousBank(uint8_t the_bank_slot)
; ---------------------------------------------------------------
;// call to a routine in memory.asm that modifies the MMU LUT to bring the back the previously specified bank of physical memory into the CPU's RAM space
;// relies on a previous routine having set ZP_OLD_BANK_NUM. Should be called after Memory_SwapInNewBank(), when finished with the new bank
.segment "CODE"
.proc _Memory_RestorePreviousBank: near
.segment "CODE"
SEI ; disable IRQs just in case one hits in the middle if MMU mapping
TAX ; get the lut slot (0-7) we want to remap
.ifdef _SIMULATOR_ ; emulator seems to start with LUT0, but kernel on machine with lut3. not sure why emulator is different
LDA #$80 ; edit mode (bit 7) + edit lut #4 (bits 4-5 both on) + active lut stays as #4 (bits 0-1 on)
.else
LDA #$B3
.endif
STA $0000 ; make the change
LDA _zp_old_bank_num ; get the previously mapped physical bank # back
STA $0008,x ; Set the System bank to use for this bank
.ifdef _SIMULATOR_ ; emulator seems to start with LUT0, but kernel on machine with lut3. not sure why emulator is different
LDA #$00 ; Select LUT#0 as active, turn off editing
.else
LDA #$33 ; Select LUT#3 as active, turn off editing
.endif
STA $0000
CLI ; safe to reenable IRQs now
RTS
.endproc
; ---------------------------------------------------------------
; uint8_t __fastcall__ Memory_GetMappedBankNum(void)
; ---------------------------------------------------------------
;// call to a routine in memory.asm that returns whatever is currently mapped in the specified MMU slot
;// set zp_bank_num before calling.
;// returns the slot that had been mapped previously
.segment "CODE"
.proc _Memory_GetMappedBankNum: near
.segment "CODE"
SEI ; disable IRQs just in case one hits in the middle if MMU mapping
TAX ; get the lut slot (0-7) we want to remap
.ifdef _SIMULATOR_ ; emulator seems to start with LUT0, but kernel on machine with lut3. not sure why emulator is different
LDA #$80 ; edit mode (bit 7) + edit lut #4 (bits 4-5 both on) + active lut stays as #4 (bits 0-1 on)
.else
LDA #$B3
.endif
STA $0000 ; make the change
LDA $0008,x ; get the current value of the bank we're about to remap
; do the return. cc65 requires functions return a 16 bit value!
LDX #00
CLI ; safe to reenable IRQs now
RTS
.endproc
; ---------------------------------------------------------------
; void __fastcall__ Memory_DebugOut(void)
; ---------------------------------------------------------------
;// call to a routine in memory.asm that writes an illegal opcode followed by address of debug buffer
;// that is a simple to the f256jr emulator to write the string at the debug buffer out to the console
;.segment "CODE"
;
;.proc _Memory_DebugOut: near
;
;.segment "CODE"
;
; .byte $FC ; illegal opcode that to Paul's JR emulator means "next 2 bytes are address of a string I should write to console"
; .byte $00;
; .byte $03; ; we're using $0300 hard coded as a location for the moment.
;
; RTS
;
;.endproc
; ---------------------------------------------------------------
; void __fastcall__ Memory_Copy(void)
; ---------------------------------------------------------------
;// call to a routine in memory.asm that copies specified number of bytes from src to dst
;// set zp_to_addr, zp_from_addr, zp_copy_len before calling.
;// credit: http://6502.org/source/general/memory_move.html
;.segment "OVERLAY_NOTICE_BOARD"
;
;.proc _Memory_Copy: near
;
;.segment "OVERLAY_NOTICE_BOARD"
;
;MOVEUP: LDX _zp_copy_len ; the last byte must be moved first
; CLC ; start at the final pages of FROM and TO
; TXA
; ADC _zp_from_addr+1
; STA _zp_from_addr+1
; CLC
; TXA
; ADC _zp_to_addr+1
; STA _zp_to_addr+1
; INX ; allows the use of BNE after the DEX below
; LDY _zp_copy_len+1
; BEQ MU3
; DEY ; move bytes on the last page first
; BEQ MU2
;MU1: LDA (_zp_from_addr),Y
; STA (_zp_to_addr),Y
; DEY
; BNE MU1
;MU2: LDA (_zp_from_addr),Y ; handle Y = 0 separately
; STA (_zp_to_addr),Y
;MU3: DEY
; DEC _zp_from_addr+1 ; move the next page (if any)
; DEC _zp_to_addr+1
; DEX
; BNE MU1
; RTS
;
;.endproc
; ---------------------------------------------------------------
; void __fastcall__ Memory_CopyWithDMA(void)
; ---------------------------------------------------------------
;// call to a routine in memory.asm that copies specified number of bytes from src to dst
;// set zp_to_addr, zp_from_addr, zp_copy_len before calling.
;// this version uses the F256's DMA capabilities to copy, so addresses can be 24 bit (system memory, not CPU memory)
;// in other words, no need to page either dst or src into CPU space
; status - 2024-03-17: DMA works (1 out of 5 or so times), but very unstable. others report same instability. commenting out until a more stable way can be identified.
;.segment "CODE"
;
;.proc _Memory_CopyWithDMA: near
;
;.segment "CODE"
;
; SEI ; disable interrupts
;
; ; Wait for VBlank period
;LINE_NO = 261*2 ; 240+21
; LDA #<LINE_NO
; LDX #>LINE_NO
;wait1:
; CPX $D01B
; BEQ wait1
;wait2:
; cmp $D01A
; CMP wait2
;
;wait3:
; CPX $D01B
; BNE wait3
;wait4:
; CMP $D01A
; BNE wait4
;
;
; STZ DMA_CTRL ; Turn off the DMA engine
;
; NOP ; random experimenting with trying to prevent timing issue
; NOP
; NOP
; NOP
; NOP
;
; ; Enable the DMA engine and set it up for a (1D) copy operation:
; LDA #DMA_CTRL_ENABLE
; STA DMA_CTRL
;
; NOP ; random experimenting with trying to prevent timing issue
; NOP
; NOP
; NOP
; NOP
;
; ;Source address (3 byte):
; LDA _zp_from_addr
; STA DMA_SRC_ADDR
; LDA _zp_from_addr+1
; STA DMA_SRC_ADDR+1
; LDA _zp_from_addr+2
; AND #$07
; STA DMA_SRC_ADDR+2
;
; ;Destination address (3 byte):
; LDA _zp_to_addr
; STA DMA_DST_ADDR
; LDA _zp_to_addr+1
; STA DMA_DST_ADDR+1
; LDA _zp_to_addr+2
; AND #$07
; STA DMA_DST_ADDR+2
;
; ; Num bytes to copy
; LDA _zp_copy_len
; STA DMA_COUNT
; LDA _zp_copy_len+1
; STA DMA_COUNT+1
; LDA _zp_copy_len+2
; STA DMA_COUNT+2
;
; ; flip the START flag to trigger the DMA operation
; LDA DMA_CTRL
; ORA #DMA_CTRL_START
; STA DMA_CTRL
; ; wait for it to finish
;
;wait_dma: LDA DMA_STATUS
; BMI wait_dma ; Wait until DMA is not busy
;
; NOP
; NOP
; NOP
; NOP
; NOP
;
; STZ DMA_CTRL ; Turn off the DMA engine
;
; NOP
; NOP
; NOP
; NOP
; NOP
;
; CLI ; re-enable interrupts
;
; RTS
;.endproc
; ---------------------------------------------------------------
; void __fastcall__ Memory_FillWithDMA(void)
; ---------------------------------------------------------------
;// call to a routine in memory.asm that fills the specified number of bytes to the dst
;// set zp_to_addr, zp_copy_len to num bytes to fill, and zp_other_byte to the fill value before calling.
;// this version uses the F256's DMA capabilities to fill, so addresses can be 24 bit (system memory, not CPU memory)
;// in other words, no need to page either dst into CPU space
;.segment "CODE"
;
;.proc _Memory_FillWithDMA: near
;
;.segment "CODE"
;
; SEI ; disable interrupts
;
;LINE_NO = 261*2 ; 240+21
; lda #<LINE_NO
; ldx #>LINE_NO
;wait1:
; cpx $D01B
; beq wait1
;wait2:
; cmp $D01A
; beq wait2
;
;wait3:
; cpx $D01B
; bne wait3
;wait4:
; cmp $D01A
; bne wait4
;
; STZ DMA_CTRL ; Turn off the DMA engine
;
; ; Enable the DMA engine and set it up for a FILL operation:
; LDA #DMA_CTRL_FILL | DMA_CTRL_ENABLE
; STA DMA_CTRL
;
; ; the fill value
; lda _zp_other_byte
; sta DMA_FILL_VAL
;
; ;Destination address (3 byte):
; LDA _zp_to_addr
; STA DMA_DST_ADDR
; LDA _zp_to_addr+1
; STA DMA_DST_ADDR+1
; LDA _zp_to_addr+2
; AND #$07
; STA DMA_DST_ADDR+2
;
; ; Num bytes to fill
; LDA _zp_copy_len
; STA DMA_COUNT
; LDA _zp_copy_len+1
; STA DMA_COUNT+1
; LDA _zp_copy_len+2
; STA DMA_COUNT+2
;
; ; flip the START flag to trigger the DMA operation
; LDA DMA_CTRL
; ORA #DMA_CTRL_START
; STA DMA_CTRL
; ; wait for it to finish
;
;wait_dma: LDA DMA_STATUS
; BMI wait_dma ; Wait until DMA is not busy
;
; NOP
; NOP
; NOP
; NOP
; NOP
; NOP
;
; NOP
; NOP
;
; NOP
; NOP
;
; CLI ; re-enable interrupts
;
; RTS
;.endproc