-
Notifications
You must be signed in to change notification settings - Fork 1
/
monitor.asm
1343 lines (1038 loc) · 28.8 KB
/
monitor.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
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
.include 'hardware.inc'
.include 'ramvars.asm'
.area ROM (ABS)
; fast interrupt vector
.org 0xfff6
.word firqinterrupt
; normal interrupt vector
.org 0xfff8
.word irqinterrupt
; software interrupt vector
.org 0xfffa
.word moninterrupt
; non maskable interupt vector
.org 0xfffc
.word moninterrupt
; setup the reset vector, last location in rom
.org 0xfffe
.word reset
; this is the start of rom
.org 0xc000
; at the start of rom is the jump table for external (ram) programs to use
; to call into the rom
.include 'jumptable.asm'
; START OF GLOBAL READ-ONLY DATA
greetingmsg: .asciz '\r\n6809 Monitor v0.4\r\n\r\n'
youtypedmsg: .asciz 'You typed: '
promptmsg: .asciz 'Monitor: > '
nosuchmsg: .asciz 'No such command\r\n'
commfailedmsg: .asciz 'Command failed, possibly bad syntax\r\n'
breakatmsg: .asciz '***Break at '
badexitmsg: .asciz 'Internal error; leaving monitor\r\n'
flashreadymsg: .asciz '+++'
resetmsg: .asciz '\r\n***flash with f or any other key to start\r\n'
newlinemsg: .asciz '\r\n'
; commandarray - subroutine address followed by command letter code
commandarray: .word dumpmemory
.ascii 'd'
.word writememory
.ascii 'w'
.word exitmonitor
.ascii 'e'
.word showregisters
.ascii 'r'
.word showhelp
.ascii 'h'
.word showhelp
.ascii '?' ; same command different letter
.word resetmonitor
.ascii 'q'
.word showuptime
.ascii 'u'
.word resetuptime
.ascii 'U'
.word latchout
.ascii 'c'
.word latchin
.ascii 'C'
.word spistore
.ascii '+'
.word ideidentify
.ascii 'y'
.word idereadsector
.ascii '<'
.word idewritesector
.ascii '>'
.word readblk
.ascii '{'
.word fsmount
.ascii 'm'
.word readinode
.ascii 'i'
.word readbyinode
.ascii 'f'
.word listdirbyinode
.ascii 'l'
.word playay
.ascii 'p'
.word xmodem
.ascii 'x'
.word disassemble
.ascii 's'
.word parsetest
.ascii 'z'
.word setbank
.ascii 'b'
.word getbank
.ascii 'B'
.word readbyte
.ascii 'R'
.word testvramread
.ascii 'L'
.word testvramwrite
.ascii 'S'
.word terminit
.ascii 'Y'
.word tclearscreen
.ascii 'V'
.word testreg
.ascii 'K'
.word showstick
.ascii 'j'
.word playbuzzer
.ascii 'P'
.word waiter
.ascii 'W'
.word opl2play
.ascii 'O'
.word 0x0000
.byte NULL
bootbeeps: .asciz 'abcdefg'
; END OF DATA
; setup stack to the end of ram so it can go grown backwards
memerror: lda #0x80
sta SOUNDER ; change tone
memerrorloop: bra memerrorloop
reset: lda #0x10
sta SOUNDER
lda #0x04
nextbank: deca
sta BANKLATCH
ldx #HIRAMSTART
nextbyte: clr ,x
tst ,x+
bne memerror
cmpx #HIRAMEND+1
bne nextbyte
tsta
bne nextbank
lda #0x01
sta BANKLATCH
lds #STACKEND+1 ; setup hardware stack
clr SOUNDER
init: clr IRQFILTER ; clear interrupt regs
clr FIRQFILTER ; they will be init'd in inits
ldx #handlenothing
stx handleds3234
stx handle65spi
stx handle65c22
stx handlevdc
stx handle88c681
stx handlebuzzer
clr keyreadpointer
clr keywritepointer
lbsr serialinit ; setup the serial port
; lbsr spiinit ; prepare the SPI
; lbsr terminit
lbsr timerinit
; lbsr buzzerinit
lbsr serialactive
ldx #resetmsg ; show prompt for flash
lbsr ioputstr
lbsr iogetwto ; wait for a key, getting the command
bne normalstart ; timeout
cmpa #0x66 ; 'f'
beq flashing
cmpa #0x20 ; space
beq noscreen
bra normalstart
flashing: ldx #ROMSTART ; setup the rom copy to ram
ldy #ROMCOPYSTART ; this is the second half of ram
romcopy: lda ,x+ ; read in
sta ,y+ ; and read out
cmpx #ROMEND+1 ; check to see if we are at the end
bne romcopy ; copy more
ldx #flasher ; get the location of the flasher code
leax -ROMSTART,x ; offset it from the start of rom
leax ROMCOPYSTART,x ; offset it forward where it now is
jmp ,x ; jump to the new location of flasher
normalstart: ;lbsr tactive
noscreen: ldx #greetingmsg ; greetings!
lbsr ioputstr ; output the greeting
; ldx #bootbeeps
; lbsr ayplaytune ; play booting beeps
lda #0x20 ; beep frequency
sta SOUNDER ; set the beeper beeping
ldy #0xd000 ; small delay
lbsr delay
lda #0x10 ; higher pitched noise
sta SOUNDER ; more beeps
ldy #0x7000 ; shorter delay
lbsr delay
clr SOUNDER ; silence the beeper
enableinterrupts ; enable interrupts
swi ; enter the monitor (mainloop)
; we should never get here - it means rti was done without fixing up
; the return address - print error and loop
ldx #badexitmsg ; if we get here then setup a msg
lbsr ioputstr ; print the message
badexitloop: bra badexitloop ; loop on the spot
; dummy interupt handler for a peripheral - do nothing
handlenothing: rts
; fast irq routine - dispatch to device handlers
firqinterrupt: pshs a
lda FIRQFILTER
bsr allinterrupts
puls a
rti
irqinterrupt: lda IRQFILTER
bsr allinterrupts
rti
allinterrupts: coma
ora IRQSTATUS
;; bita #IRQDS3234
;; beq handleds3234go
bita #IRQ65SPI
beq handle65spigo
bita #IRQ65C22
beq handle65c22go
bita #IRQVDC
beq handlevdcgo
bita #IRQ88C681
beq handle88c681go
bita #IRQBUZZER
beq handlebuzzergo
rts
handleds3234go: jsr [handleds3234]
rts
handle65spigo: jsr [handle65spi]
rts
handle65c22go: jsr [handle65c22]
rts
handlevdcgo: jsr [handlevdc]
rts
handle88c681go: jsr [handle88c681]
rts
handlebuzzergo: jsr [handlebuzzer]
rts
; monitor entry point
moninterrupt: enableinterrupts ; enable interrupts again
ldx #outputbuffer ; setup the "break" message
ldy #breakatmsg ; ...
lbsr concatstr ; append it
leay ,s ; get the new stack pointr
sty spatentry ; save the new stack pointer
ldd 10,y ; the pc is 10 bytes in
lbsr wordtoaschex ; convert it to ascii
ldy #newlinemsg ; adding a newline
lbsr concatstr ; append it
clr ,x+ ; add a null
ldx #outputbuffer ; reset the string pointer
lbsr ioputstr ; so it can be output
mainloop: ldx #promptmsg ; ">" etc
lbsr ioputstr ; output that
ldx #inputbuffer ; now we need a command
lbsr iogetstr ; get the command (waiting as needed)
ldx #newlinemsg
lbsr ioputstr ; tidy up the output with a newline
lda inputbuffer ; get the first char
ldx #commandarray ; setup the command pointer
nextcommand: ldy ,x++ ; get the sub address
ldb ,x ; get the command letter
beq commandarraye ; end of command list?
cmpa ,x+ ; compare input letter with array item
bne nextcommand ; no match? check next one
jsr ,y ; jump to subroutine
bne commanderror ; error check for zero
bra mainloop ; back to top
commanderror: ldx #commfailedmsg
lbsr ioputstr ; show error
bra mainloop
commandarraye: ldx #nosuchmsg
lbsr ioputstr ; show error message
bra mainloop
; general error handler branch for commands that fail
generalerror: lda #1
rts
;;; COMMANDS ;;;
; dumpmemory - "d AAAA BBBB" - dumps from AAAA, BBBB bytes
;
; C000 48 65 6C 6C 6F 2C 20 74 68 69 73 20 69 73 20 61 [Hello, this is a]
dumpmemory: lbsr parseinput ; parse hexes, filling out inputbuffer
lda ,y+ ; get the type
cmpa #2 ; is it a word?
lbne generalerror ; validation error
ldd ,y++ ; start address
andb #0xf0 ; round to nearest 16
std dumppointer ; store it in the variable
lda ,y+ ; get the type
cmpa #2 ; is it a word?
bne generalerror ; yes, mark it as bad
ldd ,y++ ; length/count of bytes
andb #0xf0 ; also rounded
std dumpcounter ; store it in the variable
dumpnextrow: ldx #outputbuffer ; x is persistent across the whole row
ldd dumppointer ; get address of this row
lbsr wordtoaschex ; print the address into the buffer
lda #0x20 ; space
sta ,x+ ; add a space after the address
sta ,x+ ; and another
; hex version
ldy dumppointer ; points at the start of the row
ldb #0 ; counts across 16 bytes
hexbyteloop: cmpb #0x08 ; for pretty ness...
bne noextraspace ; add a space after 8 bytes
lda #0x20 ; space
sta ,x+ ; push it in
noextraspace: lda b,y ; actually read the byte from memory
lbsr bytetoaschex ; convert it to ascii
lda #0x20 ; space
sta ,x+ ; add a space between each byte
incb ; incrememnt offset
cmpb #0x10 ; 16 bytes per row
bne hexbyteloop ; and do the next byte
lda #0x20 ; spaces
sta ,x+ ; add it in
lda #0x5b ; opening [
sta ,x+ ; add it in
; ascii version
ldy dumppointer ; reset back to the start of the row
ldb #0 ; counts across 16 bytes
ascbyteloop: lda b,y ; get the byte from memory
lbsr printableasc ; nonprintable to a dot
sta ,x+ ; add it in
incb ; increment offset
cmpb #0x10 ; 16 bytes per row
bne ascbyteloop ; and do the next byte
lda #0x5d ; closing ]
sta ,x+ ; add it in
clr ,x+ ; null terminator
ldx #outputbuffer ; reset back to the start
lbsr ioputstr ; so we can finally output it!
ldx #newlinemsg ; newline
lbsr ioputstr ; output it
; move onto the the next row
ldx dumppointer ; load the pointer back in
leax 0x10,x ; add 0x10
stx dumppointer ; store it back
ldx dumpcounter ; loead the remaning byte counter
leax -0x10,x ; subtract 0x10
stx dumpcounter ; store it back
bne dumpnextrow ; more rows?
clra ; no error
rts
writememory: lbsr parseinput ; parse hexes, filling out inputbuffer
lda ,y+ ; get the type
cmpa #2 ; is it a word?
lbne generalerror ; validation error
ldx ,y++ ; start address
nextwrite: lda ,y+ ; get the type
beq writememoryout ; that's the end of the byte list
cmpa #1 ; is it a byte?
beq writebyte ; yes, so process bytes
cmpa #2
beq writeword ; same for words
cmpa #3
beq writestring ; same for strings
tsta
beq writememoryout ; null? we are done
lbra generalerror ; otherwise its unknown, so bail
writebyte: ldb ,y+ ; get the byte to write
stb ,x+ ; and load it at memory x
bra nextwrite ; back for more
writeword: ldd ,y++ ; get the word to write
std, x++ ; and load it
bra nextwrite ; back for more
writestring: lbsr concatstr ; use the concatstr operation
bra nextwrite ; ...it copies y->x
writememoryout: clra ; clean exit
rts
; exitmonitor - fixup return address and leave monitor
exitmonitor: lbsr parseinput ; parse hexes, filling out inputbuffer
lda ,y+ ; get the type
cmpa #2 ; is it a word?
lbne generalerror ; validation error
lds #STACKEND+1 ; move the stack to the top
leas -12,s ; then move it back one frame
ldx ,y++ ; sub address
beq cleanexit ; if exit address is 0 dont modify
stx 10,s ; before modifiying the pc in stack
cleanexit: rti ; run the usercode at that address
; shows the registers as they were when the monitor was entered
ccmsg: .asciz 'CC: '
amsg: .asciz ' A: '
bmsg: .asciz ' B: '
dpmsg: .asciz ' DP: '
xmsg: .asciz ' X: '
ymsg: .asciz ' Y: '
umsg: .asciz ' U: '
pcmsg: .asciz ' PC: '
showregisters: ldx #outputbuffer ; set output buffer
ldu spatentry
ldy #ccmsg ; get the 'C: '
lbsr concatstr ; concat it onto outputbuffer
lda 0,u ; get the register value
lbsr bytetoaschex ; convert and concat it
ldy #amsg ; same again
lbsr concatstr ; ...
lda 1,u ; ...
lbsr bytetoaschex ; ...
ldy #bmsg
lbsr concatstr
lda 2,u
lbsr bytetoaschex
ldy #dpmsg
lbsr concatstr
lda 3,u
lbsr bytetoaschex
ldy #xmsg
lbsr concatstr
ldd 4,u
lbsr wordtoaschex
ldy #ymsg
lbsr concatstr
ldd 6,u
lbsr wordtoaschex
ldy #umsg
lbsr concatstr
ldd 8,u
lbsr wordtoaschex
ldy #pcmsg
lbsr concatstr
ldd 10,u
lbsr wordtoaschex
ldy #newlinemsg
lbsr concatstr
clr ,x+
ldx #outputbuffer ; and output it
lbsr ioputstr
clra ; we always succeed
rts
; shows some help text
helpmsg: .ascii 'Commands:\r\n'
.ascii ' r : show registers\r\n'
.ascii ' w AAAA BB WWWW "STRING" ... : write to AAAA bytes, words, strings\r\n'
.ascii ' d AAAA LLLL : dump from AAAA count LLLL bytes in hex\r\n'
.ascii ' e EEEE : exit to user code at EEEE\r\n'
.ascii ' q : reset the monitor\r\n'
.ascii ' + SSSS WWWW RRRR : from address SSSS write WWWW spi bytes then read\r\n'
.ascii ' RRRR bytes\r\n'
.ascii ' u : show uptime\r\n'
.ascii ' U : clear uptime counter\r\n'
.ascii ' c OO : output OO on the latch\r\n'
.ascii ' m : set 8bit ide and read mbr\r\n'
.ascii ' y : send ide identify command and show basic info\r\n'
.ascii ' { MMMM NNNN : read 1k disk block NNNN into MMMM\r\n'
.ascii ' < L0 L1 NN MMMM : read NN sectors from L0 L1 into MMMM\r\n'
.ascii ' > L0 L1 NN MMMM : write NN sectors from L0 L1 from MMMM\r\n'
.ascii ' l IIII : list directory at inode IIII\r\n'
.ascii ' i IIII ; show info about inode IIII\r\n'
.ascii ' f MMMM IIII : read file(etc) at inode IIII into MMMM\r\n'
.ascii ' x MMMM : receive file over XMODEM starting at MMMM\r\n'
.ascii ' p MMMM or p "STRING" : play notes at MMMM or STRING\r\n'
.ascii ' b BB : set the memory bank to BB\r\n'
.ascii ' B : show the current memory bank\r\n'
.ascii ' h or ? : this help\r\n'
.asciz '\r\n'
showhelp: ldx #greetingmsg ; show the greeting
lbsr ioputstr ; for the version number
ldx #helpmsg ; and the help text
lbsr ioputstr
clra ; we always suceed
rts
; restart the monitor (so we can flash it with 'f', most likely)
resetmonitor: jmp [0xfffe] ; reset via the reset vector
; showuptime
showuptime: ldx #outputbuffer ; setup the output buffer
ldd uptimeh ; load the high word
lbsr wordtoaschex ; turn it into hex in x
ldd uptimel ; load the low word
lbsr wordtoaschex ; and turn that into hex in x
ldy #newlinemsg ; get the newline string
lbsr concatstr ; concat that too
clr ,x+ ; terminate the string
ldx #outputbuffer ; reset the pointer
lbsr ioputstr ; output the string
rts
; reset uptime back to 0
resetuptime: clra ; reset uptime
clrb ; both bytes
std uptimeh ; and store high word
std uptimel ; and low word
clra
rts
; latchout - "c OO" outputs a byte on the "latch"
latchout: lbsr parseinput ; parse the input
lda ,y+ ; get the type
cmpa #1 ; see if it is a byte
lbne generalerror ; if not then validation error
lda ,y+ ; get the byte itself
; sta LATCH ; output the byte on the latch leds
clra
rts
latchin: ;lda LATCH
ldx #outputbuffer
lbsr bytetoaschex
clr ,x+
ldx #outputbuffer
lbsr ioputstr
ldx #newlinemsg
lbsr ioputstr
clra
rts
; spi store - "+ FFFF WWW RRR..." - writes and reads to the spi bus
spistore: lbsr parseinput ; parse hexes, filling out inputbuffer
lda ,y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldu ,y++ ; get the start of mpu memory
lda, y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldx ,y++ ; get the count of bytes to read
lda, y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldy ,y ; get the count of bytes to read
lbsr spistart ; mark with start
spistorenext: leax ,x ; early exit loop if no bytes to send
beq spistoredone
ldb ,u+ ; get data to write
lbsr spiwrite ; write it
leax -1,x ; decrement the counter
bra spistorenext ; back for more if there is more
spistoredone:
spiloadnext: leay, y ; early exit loop if no bytes to recv
beq spiloaddone
lbsr spiread ; get the byte we have been sent
stb, u+ ; store it in the buffer we have
leay -1,y ; secrent the counter
bra spiloadnext ; back for more?
spiloaddone: lbsr spistop ; mark with stop
clra
rts
; ideidentify - print info about the device
serialnomsg: .asciz 'Serial number: '
firmwarerevmsg: .asciz 'Firmware revision: '
modelnomsg: .asciz 'Model number: '
ideidentify: lda #0xec ; this is the identify command
lbsr simpleidecomm ; send it
ldx #idescratchsec ; setup our read sector buffer
lbsr idellreadr ; 512 reads (byte swapped)
ldx #outputbuffer
ldy #serialnomsg
lbsr concatstr
ldy #idescratchsec+20
lda #20
lbsr concatstrn
ldy #newlinemsg
lbsr concatstr
clr ,x
ldx #outputbuffer
lbsr ioputstr
ldx #outputbuffer
ldy #firmwarerevmsg
lbsr concatstr
ldy #idescratchsec+46
lda #8
lbsr concatstrn
ldy #newlinemsg
lbsr concatstr
clr ,x
ldx #outputbuffer
lbsr ioputstr
ldx #outputbuffer
ldy #modelnomsg
lbsr concatstr
ldy #idescratchsec+54
lda #40
lbsr concatstrn
ldy #newlinemsg
lbsr concatstr
clr ,x+
ldx #outputbuffer
lbsr ioputstr
clra
rts
; idereadsector - < L0 L1 NN MMMM - read NN sectors from L0 L1 into MMMM
idereadsector: lbsr parseinput
lda ,y+ ; get the type
cmpa #1 ; byte?
lbne generalerror ; validation error
lda ,y+
sta IDELBA0 ; this is the lowest byte in lba
lda ,y+ ; get the type
cmpa #1 ; byte?
lbne generalerror ; validation error
lda ,y+
sta IDELBA1 ; this is the 2nd lowestbyte in lba
clr IDELBA2 ; other two lba are zero
clr IDELBA3
lda ,y+ ; get the type
cmpa #1 ; byte?
lbne generalerror ; validation error
lda ,y+ ; get the count of sectors
sta IDECOUNT ; store it
lda ,y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldx, y++ ; finally where to store the read
lda #0x20 ; this is read sector
lbsr simpleidecomm ; send the command
readsectorloop: lbsr idellread ; read into x
lda IDECOUNT ; we can ask the disk if there are
bne readsectorloop ; more sectors to read?
clra
rts
; idewritesector - > L0 L1 NN MMMM - read NN sectors from L0 L1 into MMMM
idewritesector: lbsr parseinput
lda ,y+ ; get the type
cmpa #1 ; byte?
lbne generalerror ; validation error
lda ,y+
sta IDELBA0 ; this is the lowest byte in lba
lda ,y+ ; get the type
cmpa #1 ; byte?
lbne generalerror ; validation error
lda ,y+
sta IDELBA1 ; this is the 2nd lowestbyte in lba
clr IDELBA2 ; other two lba are zero
clr IDELBA3
lda ,y+ ; get the type
cmpa #1 ; byte?
lbne generalerror ; validation error
lda ,y+ ; get the count of sectors
sta IDECOUNT ; store it
lda ,y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldx, y++ ; finally where to read from
lda #0x30 ; this is write sector
lbsr simpleidecomm ; send the command
writesectorloop:lbsr idellwrite ; write into x
lda IDECOUNT ; we can ask the disk if there are
bne writesectorloop ; more sectors to read?
clra
rts
; readblk - b MMMM NNNN - read 1k fs block NNNN into MMMM
readblk: lbsr parseinput
lda ,y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldx ,y++ ; memory address to write into
lda ,y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldy ,y++ ; fs block number to read
lbsr fsreadblk ; do the read
clra
rts
; fsmount - m - calls idemount then prepares the fs
magicmsg: .asciz 'Magic is: '
startinodemsg: .asciz 'Start of inodes at block: '
fsmount: lbsr idemount ; do the mbr read etc
ldx #scratchblk ; setup the super block pointer
ldy #0x0001 ; it is at block 1 (2nd block)
lbsr fsreadblk ; read it in
ldx #scratchblk ; no. inodes
lbsr wordswap ; little->big endian
ldx #scratchblk+2 ; device size
lbsr wordswap ; little->big endian
ldx #scratchblk+4 ; count of blocks of inode bmap blocks
lbsr wordswap ; little->big endian
ldx #scratchblk+6 ; count of blocks of data bmap blocks
lbsr wordswap ; little->big endian
ldx #scratchblk+8 ; where data blocks begin (unused)
lbsr wordswap ; little->big endian
ldx #scratchblk+16 ; magic!
lbsr wordswap ; little->big endian
ldd #2 ; we are already at the 2nd block
addd scratchblk+4 ; add the inode bmap blocks
addd scratchblk+6 ; and the data bmap blocks
std startofinodes ; to get the start of our inodes
ldx #magicmsg ; display the magic value
ldy #scratchblk+16
lbsr ioputlab ; with a handy sub
ldx #startinodemsg ; display the block offset value
ldy #startofinodes
lbsr ioputlab ; with a handy sub
rts
typemodemsg: .asciz 'Type and Mode: '
filesizemsg: .asciz 'File size: '
; readinode - i IIII - reads inode IIII and prints some info about it
readinode: lbsr parseinput
lda ,y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldy ,y++ ; this is the inode number
ldx #inode ; we use a our general inode store
lbsr fsreadinode ; read it in
ldx #typemodemsg ; print the inode type and mode
ldy #inode
lbsr ioputlab ; using our fancy label+data printer
ldx #filesizemsg ; and the file size
ldy #inode+4
lbsr ioputlab ; using the same fancy printer
rts
; readbyinode - f MMMM IIII - reads file at inode IIII into memory MMMM
readbyinode: lbsr parseinput
lda ,y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldx ,y++ ; memory address
lda ,y+ ; get the type
cmpa #2 ; word?
lbne generalerror ; validation error
ldy ,y++ ; inode number
lbsr fsreadfile
rts
notdirmsg: .asciz 'Not a directory at that inode\r\n'
listdirbyinode: lbsr parseinput
lda ,y+
cmpa #2
lbne generalerror
ldy ,y++
lbsr fsshowdirlist
bne listdirnotdir
clra
rts
listdirnotdir: ldx #notdirmsg
lbsr ioputstr
lda #1
rts
playay: lbsr parseinput
lda ,y+
cmpa #2
beq playaymemory
cmpa #3
beq playaydirect
lda #1
rts
playaymemory: ldx ,y++
bra playaynow
playaydirect: tfr y,x
bra playaynow
playaynow: lbsr ayplaytune
clra
rts
; x MMMM - read a xmodem upload into memory starting at MMMM
xmodem: lbsr parseinput
lda ,y+
cmpa #2
lbne generalerror
ldx ,y++
waitforstart: lda #NAK ; ask for a start
lbsr serialputchar
lbsr serialgetwto ; wait 2 sec for the start
beq blockloopnoget ; got a start, no need to re-read
bra waitforstart ; still waiting, so poke again
blockloop: lbsr serialgetchar ; get header byte
blockloopnoget: cmpa #EOT ; EOT for end of file
beq xmodemout ; if so then we are done
cmpa #SOH ; SOH for start of block
bne xmodemerr ; if not then this is an error
lbsr serialgetchar ; blocks so far
sta xmodemblkcount ; store the number of blocks
lbsr serialgetchar ; 255 less blocks so far
clr xmodemchecksum ; clear the checksum
ldb #0x80 ; 128 bytes per block
byteloop: lbsr serialgetchar ; get the byte for th efile
sta ,x+ ; store the byte
adda xmodemchecksum ; add the received byte the checksum
sta xmodemchecksum ; store the checksum on each byte
decb ; decrement our byte counter
bne byteloop ; see if there are more bytes
lbsr serialgetchar ; get the checksum from sender
cmpa xmodemchecksum ; check it against the one we made
bne blockbad ; if no good, handle it
lda #ACK ; if good, then ACK the block
lbsr serialputchar ; send the ACK
bra blockloop ; get more blocks
blockbad: lda #NAK ; oh no, it was bad
lbsr serialputchar ; send a NAK; sender resends block
leax -0x80,x ; move back to start of the block
bra blockloop ; try to get the same block again
xmodemout: lda #ACK ; at end of file, ACK the whole file
lbsr serialputchar
clra
rts
xmodemerr: lda #1
rts