1 |
#define MICRODISC_LOADER |
2 |
#include "disk_info.h" |
3 |
#include "defines.h" |
4 |
|
5 |
#define COLOR(color) pha:lda #16+(color&7):sta $bb80+40*27:pla |
6 |
#define STOP(color) pha:lda #16+(color&7):sta $bb80+40*27:jmp *:pla |
7 |
|
8 |
.zero |
9 |
|
10 |
*=loader_zp_start |
11 |
|
12 |
retry_counter .dsb 1 ; Number of attempts at loading data (ie: not quite clear what happens when this fails...) |
13 |
sectors_to_go .dsb 1 ; How many sectors do we still need to load for this file |
14 |
current_track .dsb 1 ; Index of the track being loaded |
15 |
current_sector .dsb 1 ; Index of the sector being loaded |
16 |
current_side .dsb 1 ; Has the bit 4 set to 0 or 1 to be used as a mask on the Microdisc control register (other bits have to be set to zero) |
17 |
irq_save_a .dsb 1 ; To preserve the accumulator value in the IRQ code |
18 |
|
19 |
; Unpack test |
20 |
ptr_source .dsb 2 ; Packed source data adress |
21 |
ptr_destination .dsb 2 ; Destination adress where we depack |
22 |
ptr_destination_end .dsb 2 ; Point on the end of the depacked stuff |
23 |
ptr_source_back .dsb 2 ; Temporary used to hold a pointer on depacked stuff |
24 |
offset .dsb 2 |
25 |
mask_value .dsb 1 |
26 |
nb_dst .dsb 1 |
27 |
|
28 |
.text |
29 |
|
30 |
*=location_loader |
31 |
|
32 |
; |
33 |
; This is called from the bootsectors with the X register containing the fdc offset; |
34 |
; +$00 = Microdisc |
35 |
; +$e4 = Jasmin |
36 |
; |
37 |
Initialize |
38 |
;jmp Initialize |
39 |
jmp StartUp |
40 |
|
41 |
#define LOADER |
42 |
|
43 |
; This file is generated by the floppy builder |
44 |
#include "floppy_description.h" |
45 |
|
46 |
; Some local variables we need |
47 |
fdc_register_offset .dsb 1 |
48 |
|
49 |
StartUp |
50 |
stx fdc_register_offset ; Store the FDC offset value |
51 |
|
52 |
#ifdef ENABLE_VIP_INTRO |
53 |
; Load the intro part |
54 |
ldx #LOADER_INTRO |
55 |
jsr LoadData |
56 |
jsr __auto_execute_address |
57 |
#endif |
58 |
|
59 |
#ifdef ENABLE_TECH_TECH |
60 |
; Load the tech tech part |
61 |
ldx #LOADER_TECHTECH |
62 |
jsr LoadData |
63 |
jsr __auto_execute_address |
64 |
#endif |
65 |
|
66 |
; Give control to the application and hope it knows what to do |
67 |
__auto_execute_address |
68 |
jmp $a000 |
69 |
|
70 |
|
71 |
IrqHandler |
72 |
sta irq_save_a |
73 |
pla |
74 |
pha |
75 |
and #%00010000 ; Check the saved B flag to detect a BRK |
76 |
bne from_brk |
77 |
|
78 |
from_irq |
79 |
#ifdef LOADER_SHOW_DEBUGINFO |
80 |
lda $bfdf |
81 |
eor #1 |
82 |
ora #16 |
83 |
sta $bfdf |
84 |
#endif |
85 |
lda irq_save_a |
86 |
bit $304 |
87 |
IrqDoNothing |
88 |
rti |
89 |
|
90 |
from_brk |
91 |
lda #16+1 |
92 |
sta $bb80+40*27 |
93 |
nop |
94 |
nop |
95 |
nop |
96 |
lda #16+2 |
97 |
sta $bb80+40*27 |
98 |
bne from_brk |
99 |
|
100 |
|
101 |
|
102 |
|
103 |
; X=File index |
104 |
; A=Low |
105 |
; Y=High |
106 |
SetLoadAddress |
107 |
sta FileLoadAdressLow,x |
108 |
tya |
109 |
sta FileLoadAdressHigh,x |
110 |
rts |
111 |
|
112 |
|
113 |
; X=File index |
114 |
LoadData |
115 |
;STOP(2) |
116 |
|
117 |
; We have to start somewhere no matter what, compressed or not |
118 |
jsr StartReadOperation |
119 |
|
120 |
; Now at this stage we have to check if the data is compressed or not |
121 |
lda FileStoredSizeLow,x |
122 |
cmp FileSizeLow,x |
123 |
bne LoadCompressedData |
124 |
|
125 |
lda FileStoredSizeHigh,x |
126 |
cmp FileSizeHigh,x |
127 |
bne LoadCompressedData |
128 |
|
129 |
LoadUncompressedData |
130 |
|
131 |
; |
132 |
; Loop to read all the sectors |
133 |
; |
134 |
read_sectors_loop |
135 |
jsr ReadNextSector |
136 |
|
137 |
; Try to let time to an IRQ to play, and during that time copy the sector to the final location |
138 |
cli |
139 |
|
140 |
ldy #0 |
141 |
loop_copy |
142 |
lda loader_sector_buffer,y ; Load the byte from the sector buffer |
143 |
__auto_write_address |
144 |
sta $c000,y ; Store it to the final location |
145 |
iny |
146 |
bne loop_copy |
147 |
|
148 |
nop |
149 |
nop |
150 |
sei |
151 |
|
152 |
; Next sector |
153 |
inc __auto_write_address+2 |
154 |
dec sectors_to_go |
155 |
bne read_sectors_loop |
156 |
|
157 |
; Data successfully loaded (we hope), so we restore the interrupts |
158 |
cli |
159 |
rts |
160 |
|
161 |
|
162 |
LoadCompressedData |
163 |
clc |
164 |
lda FileLoadAdressLow,x |
165 |
sta ptr_destination+0 |
166 |
adc FileSizeLow,x |
167 |
sta ptr_destination_end+0 |
168 |
|
169 |
lda FileLoadAdressHigh,x |
170 |
sta ptr_destination+1 |
171 |
adc FileSizeHigh,x |
172 |
sta ptr_destination_end+1 |
173 |
|
174 |
;STOP(2) |
175 |
|
176 |
jsr UnpackData |
177 |
cli |
178 |
rts |
179 |
|
180 |
|
181 |
StartReadOperation |
182 |
sei |
183 |
|
184 |
ldy fdc_register_offset |
185 |
|
186 |
; Make sure the microdisc IRQ is disabled |
187 |
jsr WaitCompletion |
188 |
|
189 |
lda #%10000100 ; Disable the FDC (Eprom select + FDC Interrupt request) |
190 |
sta FDC_flags,y |
191 |
|
192 |
;jsr WaitCompletion |
193 |
|
194 |
; |
195 |
; Setup, we use the table to find out where the file is located on the floppy, |
196 |
; where to write it in memory, and how large it is. |
197 |
; |
198 |
lda FileLoadAdressHigh,x |
199 |
sta __auto_execute_address+2 |
200 |
sta __auto_write_address+2 |
201 |
|
202 |
lda FileLoadAdressLow,x |
203 |
sta __auto_execute_address+1 |
204 |
sta __auto_write_address+1 |
205 |
|
206 |
; Starting track |
207 |
ldy #%00000000 ; Side 0 |
208 |
lda FileStartTrack,x ; If the track id is larger than 128, it means it is on the other side of the floppy |
209 |
bpl first_side |
210 |
; The file starts on the second side |
211 |
ldy #FDC_Flag_DiscSide ; Side 1 |
212 |
and #%01111111 ; Mask out the extra bit |
213 |
first_side |
214 |
sty current_side |
215 |
sta current_track |
216 |
|
217 |
ldy fdc_register_offset |
218 |
|
219 |
; First sector |
220 |
lda FileStartSector,x |
221 |
sta current_sector |
222 |
|
223 |
; FileSizeLow/FileSizeHigh |
224 |
; Number of sectors to load |
225 |
.( |
226 |
lda FileStoredSizeHigh,x |
227 |
sta sectors_to_go |
228 |
lda FileStoredSizeLow,x |
229 |
beq skip |
230 |
inc sectors_to_go |
231 |
skip |
232 |
.) |
233 |
rts |
234 |
|
235 |
|
236 |
ReadNextSector |
237 |
cli |
238 |
|
239 |
ldy fdc_register_offset |
240 |
|
241 |
; Check if we have reached the end of the track |
242 |
lda current_sector |
243 |
cmp #FLOPPY_SECTOR_PER_TRACK+1 |
244 |
bne same_track |
245 |
|
246 |
; Next track |
247 |
inc current_track |
248 |
lda current_track |
249 |
cmp #FLOPPY_TRACK_NUMBER |
250 |
bne stay_on_same_side |
251 |
|
252 |
; Reset to the first track on the other side |
253 |
lda #0 |
254 |
sta current_track |
255 |
|
256 |
sei |
257 |
|
258 |
lda #FDC_Flag_DiscSide |
259 |
sta current_side |
260 |
stay_on_same_side |
261 |
|
262 |
|
263 |
; Reset the sector position |
264 |
lda #1 |
265 |
sta current_sector |
266 |
same_track |
267 |
|
268 |
#ifdef LOADER_SHOW_DEBUGINFO |
269 |
; Display debug info |
270 |
cli |
271 |
jsr DisplayPosition |
272 |
sei |
273 |
#else |
274 |
cli |
275 |
jsr WaitCommand |
276 |
sei |
277 |
#endif |
278 |
|
279 |
lda current_sector |
280 |
sta FDC_sector_register,y |
281 |
inc current_sector |
282 |
|
283 |
; Check if the drive is on the correct track |
284 |
lda current_track |
285 |
cmp FDC_track_register,y |
286 |
beq stay_on_the_track |
287 |
|
288 |
; Set the new track |
289 |
sta FDC_data,y |
290 |
|
291 |
lda #CMD_Seek |
292 |
sta FDC_command_register,y |
293 |
jsr WaitCompletion |
294 |
|
295 |
stay_on_the_track |
296 |
lda #%10000100 ; on force les le Microdisk en side0, drive A ... Set le bit de données !!! |
297 |
ora current_side |
298 |
sta FDC_flags,y |
299 |
|
300 |
lda #CMD_ReadSector |
301 |
sta FDC_command_register,y |
302 |
|
303 |
;cli |
304 |
jsr WaitCommand |
305 |
;sei |
306 |
|
307 |
; |
308 |
; Read the sector data |
309 |
; |
310 |
ldx #0 |
311 |
microdisc_read_data |
312 |
lda $0318 |
313 |
bmi microdisc_read_data |
314 |
|
315 |
lda FDC_data,y |
316 |
sta loader_sector_buffer,x ; Store the byte in sector buffer |
317 |
inx |
318 |
|
319 |
bne microdisc_read_data |
320 |
|
321 |
lda FDC_status_register,y |
322 |
and #$1C |
323 |
|
324 |
jsr WaitCompletion |
325 |
cli |
326 |
rts |
327 |
|
328 |
WaitCommand |
329 |
ldx #wait_status_floppy |
330 |
waitcommand |
331 |
nop |
332 |
nop |
333 |
dex |
334 |
bne waitcommand |
335 |
rts |
336 |
|
337 |
WaitCompletion |
338 |
txa |
339 |
pha |
340 |
|
341 |
php |
342 |
sei |
343 |
nop |
344 |
nop |
345 |
nop |
346 |
|
347 |
ldx #4 |
348 |
r_wait_completion |
349 |
dex |
350 |
bne r_wait_completion |
351 |
plp |
352 |
|
353 |
r2_wait_completion |
354 |
lda FDC_status_register,y |
355 |
lsr |
356 |
bcs r2_wait_completion |
357 |
|
358 |
;asl |
359 |
pla |
360 |
tax |
361 |
rts |
362 |
|
363 |
#ifdef LOADER_SHOW_DEBUGINFO |
364 |
HexData .byt "0123456789ABCDEF" |
365 |
|
366 |
DisplayPosition |
367 |
.( |
368 |
lda current_side |
369 |
lsr |
370 |
lsr |
371 |
lsr |
372 |
lsr |
373 |
tax |
374 |
lda HexData,x |
375 |
sta $bb80+40*27+0 |
376 |
|
377 |
lda #3 |
378 |
sta $bb80+40*27+1 |
379 |
|
380 |
lda current_track |
381 |
lsr |
382 |
lsr |
383 |
lsr |
384 |
lsr |
385 |
tax |
386 |
lda HexData,x |
387 |
sta $bb80+40*27+2 |
388 |
|
389 |
lda current_track |
390 |
and #15 |
391 |
tax |
392 |
lda HexData,x |
393 |
sta $bb80+40*27+3 |
394 |
|
395 |
lda #2 |
396 |
sta $bb80+40*27+4 |
397 |
|
398 |
lda current_sector |
399 |
lsr |
400 |
lsr |
401 |
lsr |
402 |
lsr |
403 |
tax |
404 |
lda HexData,x |
405 |
sta $bb80+40*27+5 |
406 |
|
407 |
lda current_sector |
408 |
and #15 |
409 |
tax |
410 |
lda HexData,x |
411 |
sta $bb80+40*27+6 |
412 |
|
413 |
;jsr WaitLoop |
414 |
rts |
415 |
.) |
416 |
#endif |
417 |
|
418 |
|
419 |
GetNextByte |
420 |
php |
421 |
lda __fetchByte+1 |
422 |
bne __fetchByte |
423 |
nop |
424 |
nop |
425 |
nop |
426 |
nop |
427 |
sei |
428 |
jsr ReadNextSector |
429 |
nop |
430 |
nop |
431 |
nop |
432 |
nop |
433 |
cli |
434 |
ldx #0 |
435 |
ldy #0 |
436 |
__fetchByte |
437 |
lda $200 |
438 |
inc __fetchByte+1 |
439 |
plp |
440 |
rts |
441 |
|
442 |
|
443 |
|
444 |
; void file_unpack(void *ptr_dst,void *ptr_src) |
445 |
|
446 |
; Need to be called with valid values in: |
447 |
; ptr_destination |
448 |
; ptr_source |
449 |
; ptr_destination_end (Destination + size) |
450 |
UnpackData |
451 |
;jmp UnpackData |
452 |
.( |
453 |
cli |
454 |
|
455 |
; Initialise variables |
456 |
; We try to keep "y" null during all the code, |
457 |
; so the block copy routine has to be sure that |
458 |
; y is null on exit |
459 |
ldy #0 |
460 |
sty __fetchByte+1 |
461 |
lda #1 |
462 |
sta mask_value |
463 |
|
464 |
unpack_loop |
465 |
; Handle bit mask |
466 |
lsr mask_value |
467 |
bne end_reload_mask |
468 |
|
469 |
jsr GetNextByte ; Read from source stream |
470 |
|
471 |
ror |
472 |
sta mask_value |
473 |
end_reload_mask |
474 |
bcc back_copy |
475 |
|
476 |
write_byte |
477 |
; Copy one byte from the source stream |
478 |
jsr GetNextByte ; Read from source stream |
479 |
sta (ptr_destination),y |
480 |
|
481 |
lda #1 |
482 |
sta nb_dst |
483 |
|
484 |
|
485 |
|
486 |
_UnpackEndLoop |
487 |
;// We increase the current destination pointer, |
488 |
;// by a given value, white checking if we reach |
489 |
;// the end of the buffer. |
490 |
clc |
491 |
lda ptr_destination |
492 |
adc nb_dst |
493 |
sta ptr_destination |
494 |
|
495 |
.( |
496 |
bcc skip |
497 |
inc ptr_destination+1 |
498 |
skip |
499 |
.) |
500 |
cmp ptr_destination_end |
501 |
lda ptr_destination+1 |
502 |
sbc ptr_destination_end+1 |
503 |
bcc unpack_loop |
504 |
rts |
505 |
|
506 |
|
507 |
back_copy |
508 |
;BreakPoint jmp BreakPoint |
509 |
; Copy a number of bytes from the already unpacked stream |
510 |
; Here we know that y is null. So no need for clearing it. |
511 |
; Just be sure it's still null at the end. |
512 |
; At this point, the source pointer points to a two byte value that actually contains a 4 bits counter, and a 12 bit offset to point back into the depacked stream. |
513 |
; The counter is in the 4 high order bits. |
514 |
;clc <== No need, since we access this routie from a BCC |
515 |
jsr GetNextByte ; Read from source stream |
516 |
adc #1 |
517 |
sta offset |
518 |
jsr GetNextByte ; Read from source stream |
519 |
tax |
520 |
and #$0f |
521 |
adc #0 |
522 |
sta offset+1 |
523 |
|
524 |
txa |
525 |
lsr |
526 |
lsr |
527 |
lsr |
528 |
lsr |
529 |
clc |
530 |
adc #3 |
531 |
sta nb_dst |
532 |
|
533 |
sec |
534 |
lda ptr_destination |
535 |
sbc offset |
536 |
sta ptr_source_back |
537 |
lda ptr_destination+1 |
538 |
sbc offset+1 |
539 |
sta ptr_source_back+1 |
540 |
|
541 |
; Beware, in that loop, the direction is important |
542 |
; since RLE like depacking is done by recopying the |
543 |
; very same byte just copied... Do not make it a |
544 |
; reverse loop to achieve some speed gain... |
545 |
.( |
546 |
copy_loop |
547 |
lda (ptr_source_back),y ; Read from already unpacked stream |
548 |
sta (ptr_destination),y ; Write to destination buffer |
549 |
iny |
550 |
cpy nb_dst |
551 |
bne copy_loop |
552 |
.) |
553 |
ldy #0 |
554 |
beq _UnpackEndLoop |
555 |
rts |
556 |
.) |
557 |
|
558 |
_EndLoaderCode |
559 |
|
560 |
; |
561 |
; This is free memory that can be used, when it reaches zero then the loader start address should be changed |
562 |
; |
563 |
|
564 |
.dsb $FFF4 - _EndLoaderCode |
565 |
|
566 |
_Vectors |
567 |
|
568 |
#if ( _Vectors <> $FFF4 ) |
569 |
#error - Vector address is incorrect, loader will crash |
570 |
#else |
571 |
|
572 |
; |
573 |
; Here are the functions that the user can call from his own application |
574 |
; |
575 |
_ApiSetLoadAddress .byt $4c,<SetLoadAddress,>SetLoadAddress ; $FFF4 |
576 |
_ApiSetLoadData .byt $4c,<LoadData,>LoadData ; $FFF7 |
577 |
|
578 |
; |
579 |
; These three HAVE to be at these precise adresses, they map to hardware registers |
580 |
; |
581 |
_VectorNMI .word IrqDoNothing ; FFFA-FFFB - NMI Vector (Usually points to $0247) |
582 |
_VectorReset .word IrqDoNothing ; FFFC-FFFD - RESET Vector (Usually points to $F88F) |
583 |
_VectorIRQ .word IrqHandler ; FFFE-FFFF - IRQ Vector (Normally points to $0244) |
584 |
|
585 |
#echo Remaining space in the loader code: |
586 |
#print (_Vectors - _EndLoaderCode) |
587 |
|
588 |
#endif |
589 |
|
590 |
; End of the loader - Nothing should come after because it's out of the addressable memory range :) |
591 |
|