-
Notifications
You must be signed in to change notification settings - Fork 1
/
mbc816.a86
1884 lines (1626 loc) · 60.7 KB
/
mbc816.a86
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
; ********************************************************************************
;
; V20-MBC (HW ref. A250220) CP/M-86 Custom BIOS - S220520
;
; Required: IOS S260320-R230520 (or following revisions until otherwise stated)
;
; Compile with: ASM86.COM (CP/M-80) or ASM86.CMD (CP/M-86)
;
;
;
; CHANGELOG:
;
; S220520 First release
; S110321 SAH - CP/M-86/80 BIOS
;
; ********************************************************************************
; --------------------------------------------------------------------------------
;
; V20-MBC IOS equates
;
; --------------------------------------------------------------------------------
EXC_WR_OPCD EQU 000H ; Address of the EXECUTE WRITE OPCODE write port
EXC_RD_OPCD EQU 000H ; Address of the EXECUTE READ OPCODE read port
STO_OPCD EQU 001H ; Address of the STORE OPCODE write port
SERIAL_RX EQU 001H ; Address of the SERIAL RX read port
SYSFLAGS EQU 002H ; Address of the SYSFLAGS read port
SERTX_OPC EQU 001H ; SERIAL TX opcode
SELDISK_OPC EQU 009H ; SELDISK opcode
SELTRCK_OPC EQU 00AH ; SELTRACK opcode
SELSECT_OPC EQU 00BH ; SELSECT opcode
WRTSECT_OPC EQU 00CH ; WRITESECT opcode
DATETIM_OPC EQU 084H ; DATETIME opcode
ERRDSK_OPC EQU 085H ; ERRDISK opcode
RDSECT_OPC EQU 086H ; READSECT opcode
SDMOUNT_OPC EQU 087H ; SDMOUNT opcode
;
; CCP Equates for the AUTOEXEC.SUB execution
;
CCPLEN EQU 0AH ; Address of current number of chars into the CCP input buffer
CCPFIRST EQU 0BH ; Address of the first charater of the CCP input buffer
; -------------------------------------
true equ -1
false equ not true
cr equ 0dh ;carriage return
lf equ 0ah ;line feed
;*********************************************
;* *
;* Loader_bios is true if assembling the *
;* LOADER BIOS, otherwise BIOS is for the *
;* CPM.SYS file. *
;* *
;*********************************************
loader_bios equ false
bdos_int equ 224 ;reserved BDOS interrupt
IF not loader_bios
;---------------------------------------------
;| |
bios_code equ 2500h
ccp_offset equ 0000h
bdos_ofst equ 0B06h ;BDOS entry point
;| |
;---------------------------------------------
ENDIF ;not loader_bios
IF loader_bios
;---------------------------------------------
;| |
bios_code equ 1200h ;start of LDBIOS
ccp_offset equ 0003h ;base of CPMLOADER
bdos_ofst equ 0406h ;stripped BDOS entry
;| |
;---------------------------------------------
ENDIF ;loader_bios
cseg
;--vv---------------- SAH ----------------vv--
;| |
CodeMacro AAD10 ; modified AAD instruction
db 0d5h
db 010h
EndM
;
CodeMacro BRKEM interrupt:db ; branch to emulation interrupt
db 0fh
db 0ffh
db interrupt
EndM
;
; bdos functions used by 8080 emulation
C_RAWIO equ 6 ; Perform Direct I/O
C_STAT equ 11 ; Get Console Status
F_CLOSE equ 16 ; Close File
DRV_SET equ 14 ; Set Default Drive
F_DELETE equ 19 ; Delete File
F_READ equ 20 ; Read Sequential
F_WRITE equ 21 ; Write Sequential
F_MAKE equ 22 ; Create File
F_DMAOFF equ 26 ; Set DMA Buffer Offset
DRV_ALLOCVEC equ 27 ; Get Allocation Vector Address
DRV_DPB equ 31 ; Get DPB Address
S_BIOS equ 50 ; Call BIOS Routine
F_DMASEG equ 51 ; Set DMA Segment
MC_ALLOC equ 55 ; Allocate Memory
MC_FREE equ 57 ; Free Memory
;
; bios functions used by 8080 emulation
BIOS_SELDSK equ 9 ; Select Disk Drive
;
; emulation entry interrupts and calculated base page offsets
intemul equ 080h ; enter (8080) emulation interrupt
intbdos equ 081h ; interrupt native (8086) bdos
intbios equ 082h ; interrupt native (8086) bios
intemul_offset equ (intemul * 4)
intbdos_offset equ (intbdos * 4)
intbios_offset equ (intbios * 4)
;
; equates/locations in cpm86 ccp to be patched/used at run time
ccp_file equ .0827h ; drive+filename to be loaded
ccp_file_type equ .0830h ; filetype of ^
ccp_file_rec equ .0847h ; record count of ^
ccp_file_ext equ .0833h ; extent number of ^
ccp_cur_drv equ .0939h ; current drive
com_patch equ .0727h ; address in ccp to be patched to force
; jump to bios routine to check for .com
; file if not .cmd file.
com_desc equ .000ah ; location of command line descriptor
com_line equ .000bh ; location of command line cpm86, as input
ccp_parse_patch equ .07a0h ; place temp ret here to end ccp parse routine
;
org 00a6h
ccp_crlf: ; routine to display cr + lf
org 00edh
ccp_open: ; routine to open a file
;
org 046ch
ccp_cleanup: ; reset default disk drive
;
org 03deh
ccp_exit: ; back to cpm86 command level
;
org 0732h
ccp_cmd: ; back to load .CMD file
;
org 0738h
ccp_parse: ; parse command line to fcb1,2 and dma buffer
;
org 072ch
ccp_error: ; cpm86 command error routine
;| |
;--^^---------------- SAH ----------------^^--
org ccpoffset
ccp:
org bios_code
;*********************************************
;* *
;* BIOS Jump Vector for Individual Routines *
;* *
;*********************************************
jmp INIT ;Enter from BOOT ROM or LOADER
jmp WBOOT ;Arrive here from BDOS call 0
jmp CONST ;return console keyboard status
jmp CONIN ;return console keyboard char
jmp CONOUT ;write char to console device
jmp LISTOUT ;write character to list device
jmp PUNCH ;write character to punch device
jmp READER ;return char from reader device
jmp HOME ;move to trk 00 on cur sel drive
jmp SELDSK ;select disk for next rd/write
jmp SETTRK ;set track for next rd/write
jmp SETSEC ;set sector for next rd/write
jmp SETDMA ;set offset for user buff (DMA)
jmp READ ;read a 128 byte sector
jmp WRITE ;write a 128 byte sector
jmp LISTST ;return list status
jmp SECTRAN ;xlate logical->physical sector
jmp SETDMAB ;set seg base for buff (DMA)
jmp GETSEGT ;return offset of Mem Desc Table
jmp GETIOBF ;return I/O map byte (IOBYTE)
jmp SETIOBF ;set I/O map byte (IOBYTE)
;*********************************************
;* *
;* INIT Entry Point, Differs for LDBIOS and *
;* BIOS, according to "Loader_Bios" value *
;* *
;*********************************************
INIT: ;print signon message and initialize hardware
mov ax,cs ;we entered with a JMPF so use
mov ss,ax ;CS: as the initial value of SS:,
mov ds,ax ;DS:,
mov es,ax ;and ES:
;use local stack during initialization
mov sp,offset stkbase
cld ;set forward direction
IF not loader_bios
;---------------------------------------------
;| |
; This is a BIOS for the CPM.SYS file.
; Setup all interrupt vectors in low
; memory to address trap
push ds ;save the DS register
mov IOBYTE,0 ;clear IOBYTE
mov ax,0
mov ds,ax
mov es,ax ;set ES and DS to zero
;setup interrupt 0 to address trap routine
mov int0_offset,offset int_trap
mov int0_segment,CS
mov di,4
mov si,0 ;then propagate
mov cx,510 ;trap vector to
rep movs ax,ax ;all 256 interrupts
;BDOS offset to proper interrupt
mov bdos_offset,bdos_ofst
pop ds ;restore the DS register
;
; ---------------------------------------------------
; Set up the execution of AUTOEXEC.SUB if required.
; Converted from the Z80-MBC2 BIOS (S030818-R140319)
; I left the original Z80 code in the comments.
; ---------------------------------------------------
;
;ld a, SYSFLAG_OPC ; A = SYSFLAG opcode
;out (STO_OPCD), a ; Write the opcode
in al, SYSFLAGS ;in a, (EXC_RD_OPCD); Check if AUTOEXEC execution is requierd
and al, 01 ;and $01 ; Isolate AUTOEXEC flag
jz init2 ;jr z, GOCPM ; Jump if flag = 0 (nothing to set up)
mov si, offset CCPAuto ;ld bc, CCPAuto ; Flag = 1, BC = address of AUTOEXEC command string
mov di, CCPFIRST ;ld hl, CCPFIRS ; HL = address of the first char of CCP input string
bufCopy: ; Copy the AUTOEXEC command string into the CCP input buffer
mov al, [si] ;ld a, (bc) ; A = current command string char
cmp al, 0 ;cp eos ; End of string reached?
jz bufCopyEnd ;jr z, bufCopyEnd ; Yes, jump
mov [di], al ;ld (hl), a ; No, load it the CCP input buffer
inc si ;inc bc ; Increment command string (to inject) character pointer
inc di ;inc hl ; Increment CCP input buffer character pointer
jmp bufCopy ;jr bufCopy ; Copy next character
bufCopyEnd: ; Calculate command string lenght and store it to CCP input buffer
; lenght variable
mov si, CCPFIRST ;ld bc, CCPFIRS ; BC = address of the first char of CCP input string
;xor a ; Carry = 0
;sbc hl, bc ; L = command string lenght (H = 0 always)
sub di, si ; Calculate lenght of the injected string (always < 255)
mov ax, di ;ld a, l ; A = command string lenght
mov bx, CCPLEN
mov [bx], al ;ld (CCPLEN), a ; Store it into CCP buffer lenght variable
;jr GOCPM
init2:
;| |
;---------------------------------------------
ENDIF ;not loader_bios
IF loader_bios
;---------------------------------------------
;| |
;This is a BIOS for the LOADER
push ds ;save data segment
mov ax,0
mov ds,ax ;point to segment zero
;BDOS interrupt offset
mov bdos_offset,bdos_ofst
mov bdos_segment,CS ;bdos interrupt segment
; (additional LOADER initialization)
pop ds ;restore data segment
;| |
;---------------------------------------------
ENDIF ;loader_bios
IF not loader_bios
;--vv---------------- SAH ----------------vv--
;| |
; Patch ccp to test for .com files if V20 processor
;
; only if v20 processor
mov ax,0f0fh
AAD10 ; 8088 will merge 0F0Fh to 00FFh
cmp al,0ffh ; 8088 processor?
jz init4 ; yes, don't patch ccp
;
; and the ccp patch address starts with a call instruction
cmp byte ptr com_patch,0e8h ; call instruction?
jnz init4 ; no, dont patch ccp
mov byte ptr com_patch,0e9h ; patch jump instruction
mov word ptr com_patch +1,offset check_cmd - (offset com_patch +3)
mov byte ptr v20_cpu,true ; flag v20 cpu
init4:
;| |
;--^^---------------- SAH ----------------^^--
ENDIF ;not loader_bios
mov bx,offset signon
call pmsg ;print signon message
IF not loader_bios
;--vv---------------- SAH ----------------vv--
;| |
cmp byte ptr v20_cpu,true ; v20 cpu?
jnz init61
mov bx,offset sign80
call pmsg ; yes, print 816 message
jmp init6
init61:
mov bx,offset sign86
call pmsg ; yes, print 86 message
init6:
mov bx,offset signver
call pmsg ; print bios version
;| |
;--^^---------------- SAH ----------------^^--
ENDIF ;not loader_bios
call RAMset ; Check how much RAM is installed, set the TPA and print it
mov cl,0 ;default to dr A: on coldstart
jmp ccp ;jump to cold start entry of CCP
WBOOT:
jmp ccp+6 ;direct entry to CCP at command level
IF not loader_bios
;---------------------------------------------
;| |
int_trap:
cli ;block interrupts
mov ax,cs
mov ds,ax ;get our data segment
mov bx,offset int_trp
call pmsg
hlt ;hardstop
;| |
;---------------------------------------------
ENDIF ;not loader_bios
;*********************************************
;* *
;* CP/M Character I/O Interface Routines *
;* *
;*********************************************
; -------------------------------------
CONST: ;console status
in al, SYSFLAGS
and al, 4 ; isolate the Rx ready flag
jnz Rx_ready
ret ; return not ready flag 00H
Rx_ready:
or al, 0FFH ; return ready flag 0FFH
ret
; -------------------------------------
CONIN: ;console input
call CONST
jz CONIN ; wait for Rx ready
in al, SERIAL_RX ; read a char
ret
; -------------------------------------
CONOUT: ;console output
mov al, SERTX_OPC ; AL = Serial Tx Opcode
out STO_OPCD, al ; send it to IOS
mov al, cl
out EXC_WR_OPCD, al ; send the char
ret
; -------------------------------------
LISTOUT: ;list device output - not implemented
ret
; -------------------------------------
LISTST: ;poll list status - not implemented
xor al, al
ret
; -------------------------------------
PUNCH: ;write punch device - not implemented
ret
; -------------------------------------
READER: ; not implemented
mov al, 1ah
ret ; return EOF for now
; -------------------------------------
GETIOBF:
mov al,IOBYTE
ret
; -------------------------------------
SETIOBF:
mov IOBYTE,cl ;set iobyte
ret ; iobyte not implemented
;------------------------------------------------------------------------------------------------
; V20-MBC RAM sizing and setting routine.
; Size the installed RAM (128KB/512KB/1024KB) and set the correct parameter for CP/M-86
; TPA allocation. The amount of installed RAM is printed in the signon message.
;
; NOTE: the RAM sizing algorithm uses the "address mirroring" of the V20-MBC address decoding
; schema. When the RAM is not fully installed (128KB or 512KB configuration) the installed
; RAM is mirrored in all the remaining "empty" addresses.
;------------------------------------------------------------------------------------------------
FLAGCHK1 EQU 55h ; Ram check test pattern 1
FLAGCHK2 EQU 0AAh ; Ram check test pattern 2
MASK128K EQU 2000h ; Segment increment/mask to address next 128KB block
MASK512K EQU 8000h ; Segment increment/mask to address next 512KB block
RAMchkvar RS 1 ; Used to check the installed RAM
RAMset:
push es ; Save current ES
mov ax, ds
or ax, MASK512K ; Check for 1024KB RAM config
call RAMchk
or al, al
jnz RAM1024 ; Jump if 1024KB found
mov ax, ds
or ax, MASK128K ; Check for 512KB RAM config
call RAMchk
or al, al
jnz RAM512 ; Jump if 512KB found
;
; 128KB RAM found. Just print it (TPA already set for 128KB as default)
;
mov bx, offset msg128
call pmsg ; Print the 128KB message
RAMend:
mov bx, offset signon2 ; Complete the RAM message
call pmsg
pop es ; Restore ES
ret
RAM1024:
;
; 1024KB RAM found
;
mov RAMlen, tpa_len2 ; Set TPA for 1024KB
mov bx, offset msg1024
call pmsg ; Print the 1024KB message
jmps RAMend
RAM512:
;
; 512KB RAM found
;
mov RAMlen, tpa_len1 ; Set TPA for 512KB
mov bx, offset msg512
call pmsg ; Print the 512KB message
jmps RAMend
RAMchk:
; Check if RAM is installed.
; On calling AX = segment to be used (MASK128K for 512K check, MASK512K for 1024KB check)
; Return with result in AL: AL = 0 RAM not found, AL = 1 RAM found.
mov es, ax ; ES = check segment
;
; First RAM check
;
mov RAMchkvar, FLAGCHK1
mov ah, es:RAMchkvar
cmp ah, FLAGCHK1 ; First check passed?
jnz RAMfound ; Yes, jump if RAM found
;
; Second RAM check
;
mov RAMchkvar, FLAGCHK2
mov ah, es:RAMchkvar
cmp ah, FLAGCHK2 ; Second check passed?
jnz RAMfound ; Yes, jump if RAM found
xor al, al ; AL = RAM not found flag
ret
;
RAMfound:
mov al, 1 ; AL = RAM found flag
ret
; -------------------------------------
pmsg:
mov al,[BX] ;get next char from message
test al,al
jz return ;if zero return
mov CL,AL
call CONOUT ;print it
inc BX
jmps pmsg ;next character and loop
;*********************************************
;* *
;* Disk Input/Output Routines *
;* *
;*********************************************
;*****************************************************
;* *
;* CP/M to host disk constants *
;* *
;* This is setup for CP/M block size of 4K *
;* with a host sector size of 512 bytes, and 32 sec- *
;* tors per track. *
;*****************************************************
una equ byte ptr [BX] ;name for byte at BX
blksiz equ 4096 ;CP/M allocation size
hstsiz equ 512 ;host disk sector size
hstspt equ 32 ;host disk sectors/trk
hstblk equ hstsiz/128 ;CP/M sects/host buff
;
;*****************************************************
;* *
;* secshf is log2(hstblk), and is listed below for *
;* values of hstsiz up to 2048. *
;* *
;* hstsiz hstblk secshf *
;* 256 2 1 *
;* 512 4 2 *
;* 1024 8 3 *
;* 2048 16 4 *
;* *
;*****************************************************
secshf equ 2 ;log2(hstblk)
cpmspt equ hstblk * hstspt ;CP/M sectors/track
secmsk equ hstblk-1 ;sector mask
;
;*****************************************************
;* *
;* BDOS constants on entry to write *
;* *
;*****************************************************
wrall equ 0 ;write to allocated
wrdir equ 1 ;write to directory
wrual equ 2 ;write to unallocated
;
;*****************************************************
;* *
;* The BIOS entry points given below show the *
;* code which is relevant to deblocking only. *
;* *
;*****************************************************
SELDSK: ; select disk given by register CL
ndisks equ 16 ; number of disks (up to 16). Set to 16 for the V20-MBC
mov disk,cl ; save disk number
mov bx,0000h ; ready for error return
cmp cl,ndisks ; n beyond max disks?
jnb return ; return if so
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;select disk
;is this the first activation of the drive?
test DL,1 ;lsb = 0?
jnz selset
;this is the first activation, clear host buff
mov hstact,0
mov unacnt,0
selset:
mov al,cl ! cbw ;put in AX
mov sekdsk,al ;seek disk number
mov cl,4 ! shl al,cl ;times 16
add ax,offset dpbase
mov bx,ax
return:
ret
; -------------------------------------
HOME: ;move selected disk to home position (Track 0)
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;home the selected disk
mov al,hstwrt ;check for pending write
test al,al
jnz homed
mov hstact,0 ;clear host active flag
homed:
;mov cx,0 ;now, set track zero
ret
;
; -------------------------------------
SETTRK: ;set track address given by CX
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;set track given by registers CX
mov sektrk,CX ;track to seek
ret
; -------------------------------------
;
SETSEC: ;set sector number given by cl (<255)
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;set sector given by register cl
mov seksec,cl ;sector to seek
ret
;
; -------------------------------------
SETDMA: ;set DMA offset given by CX
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;set dma address given by CX
mov dma_off,CX
ret
; -------------------------------------
SETDMAB: ;set DMA segment given by CX
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;set segment address given by CX
mov dma_seg,CX
ret
; -------------------------------------
SECTRAN: ;translate sector CX using table at [DX]
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;translate sector number CX with table at [DX]
test DX,DX ;test for hard skewed
jz notran ;(blocked must be hard skewed)
mov BX,CX
add BX,DX
mov BL,[BX]
ret
no_tran:
;hard skewed disk, physical = logical sector
mov BX,CX
ret
; -------------------------------------
READ:
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;read the selected CP/M sector
mov unacnt,0 ;clear unallocated counter
mov readop,1 ;read operation
mov rsflag,1 ;must read data
mov wrtype,wrual ;treat as unalloc
jmp rwoper ;to perform the read
; -------------------------------------
WRITE:
;
; Blocking/Deblocking routines (CP/M-86 Systen Guide, Appendix A - DEBLOCK.LIB)
;
;write the selected CP/M sector
mov readop,0 ;write operation
mov wrtype,cl
cmp cl,wrual ;write unallocated?
jnz chkuna ;check for unalloc
;
; write to unallocated, set parameters
;
mov unacnt,(blksiz/128) ;next unalloc recs
mov al,sekdsk ;disk to seek
mov unadsk,al ;unadsk = sekdsk
mov ax,sektrk
mov unatrk,ax ;unatrk = sektrk
mov al,seksec
mov unasec,al ;unasec = seksec
; ..........................................
; Blocking / Deblocking subroutines
; ..........................................
chkuna:
;check for write to unallocated sector
;
mov bx,offset unacnt ;point "UNA" at UNACNT
mov al,una ! test al,al ;any unalloc remain?
jz alloc ;skip if not
;
; more unallocated records remain
dec al ;unacnt = unacnt-1
mov una,al
mov al,sekdsk ;same disk?
mov BX,offset unadsk
cmp al,una ;sekdsk = unadsk?
jnz alloc ;skip if not
;
; disks are the same
mov AX, unatrk
cmp AX, sektrk
jnz alloc ;skip if not
;
; tracks are the same
mov al,seksec ;same sector?
;
mov BX,offset unasec ;point una at unasec
;
cmp al,una ;seksec = unasec?
jnz alloc ;skip if not
;
; match, move to next sector for future ref
inc una ;unasec = unasec+1
mov al,una ;end of track?
cmp al,cpmspt ;count CP/M sectors
jb noovf ;skip if below
;
; overflow to next track
mov una,0 ;unasec = 0
inc unatrk ;unatrk=unatrk+1
;
noovf:
;match found, mark as unnecessary read
mov rsflag,0 ;rsflag = 0
jmps rwoper ;to perform the write
;
alloc:
;not an unallocated record, requires pre-read
mov unacnt,0 ;unacnt = 0
mov rsflag,1 ;rsflag = 1
;drop through to rwoper
;
;*****************************************************
;* *
;* Common code for READ and WRITE follows *
;* *
;*****************************************************
rwoper:
;enter here to perform the read/write
mov erflag,0 ;no errors (yet)
mov al, seksec ;compute host sector
mov cl, secshf
shr al,cl
mov sekhst,al ;host sector to seek
;
; active host sector?
mov al,1
xchg al,hstact ;always becomes 1
test al,al ;was it already?
jz filhst ;fill host if not
;
; host buffer active, same as seek buffer?
mov al,sekdsk
cmp al,hstdsk ;sekdsk = hstdsk?
jnz nomatch
;
; same disk, same track?
mov ax,hsttrk
cmp ax,sektrk ;host track same as seek track
jnz nomatch
;
; same disk, same track, same buffer?
mov al,sekhst
cmp al,hstsec ;sekhst = hstsec?
jz match ;skip if match
nomatch:
;proper disk, but not correct sector
mov al, hstwrt
test al,al ;"dirty" buffer ?
jz filhst ;no, don't need to write
call writehst ;yes, clear host buff
; (check errors here)
;
filhst:
;may have to fill the host buffer
mov al,sekdsk ! mov hstdsk,al
mov ax,sektrk ! mov hsttrk,ax
mov al,sekhst ! mov hstsec,al
mov al,rsflag
test al,al ;need to read?
jz filhst1
;
call readhst ;yes, if 1
; (check errors here)
;
filhst1:
mov hstwrt,0 ;no pending write
;
match:
;copy data to or from buffer depending on "readop"
mov al,seksec ;mask buffer number
and ax,secmsk ;least signif bits are masked
mov cl, 7 ! shl ax,cl ;shift left 7 (* 128 = 2**7)
;
; ax has relative host buffer offset
;
add ax,offset hstbuf ;ax has buffer address
mov si,ax ;put in source index register
mov di,dma_off ;user buffer is dest if readop
;
push DS ! push ES ;save segment registers
;
mov ES,dma_seg ;set destseg to the users seg
;SI/DI and DS/ES is swapped
;if write op
mov cx,128/2 ;length of move in words
mov al,readop
test al,al ;which way?
jnz rwmove ;skip if read
;
; write operation, mark and switch direction
mov hstwrt,1 ;hstwrt = 1 (dirty buffer now)
xchg si,di ;source/dest index swap
mov ax,DS
mov ES,ax
mov DS,dma_seg ;setup DS,ES for write
;
rwmove:
cld ! rep movs AX,AX ;move as 16 bit words
pop ES ! pop DS ;restore segment registers
;
; data has been moved to/from host buffer
cmp wrtype,wrdir ;write type to directory?
mov al,erflag ;in case of errors
jnz return_rw ;no further processing
;
; clear host buffer for directory write
test al,al ;errors?
jnz return_rw ;skip if so
mov hstwrt,0 ;buffer written
call writehst
mov al,erflag
return_rw:
ret
;------------------------------------------------------------------------------------------------
; Read physical sector from host.
; Parameters: hstdsk, hsttrk, hstsec, dma_seg, dma_off
;
; Converted from the Z80-MBC2 BIOS (S030818-R140319)
; I left the original Z80 code in the comments.
;------------------------------------------------------------------------------------------------
readhst:
push cx ;push bc
push bx ;push hl
call setDTS ; Select disk, track, sector
;
; Read current host sector (512 byte) to hstbuf
;ld c, EXC_RD_OPCD ; Set the EXECUTE READ OPCODE port into C
mov bx, offset hstbuf ;ld hl, hstbuf ; HL points to buffer hstbuf
mov al, RDSECT_OPC ;ld a, RDSECT_OPC ; Select READSECT opcode (IOS)
out STO_OPCD, al ;out (STO_OPCD), a
; ld b, 0 ; Byte counter = 256
; inir ; Read 256 byte to hstbuf
; inir ; Read 256 byte to hstbuf
mov cx, 512 ; Bytes to read counter = 512
rdhst:
in al, EXC_RD_OPCD ; Read a byte...
mov [bx], al ; ..and put it into hstbuf
inc bx ; Update the pointer to hstbuf
loop rdhst
;
; Check for errors
mov al, ERRDSK_OPC ; ld a, ERRDSK _OPC ; Select ERRDISK opcode (IOS)
out STO_OPCD, al ; out (STO_OPCD), a
in al, EXC_RD_OPCD ; in a, (EXC_RD_OPCD); Read error code into A...
mov erflag, al ; ld (erflag), a ; ... and store it into erflag
pop bx ; pop hl
pop cx ; pop bc
ret ; Return with the success/error code in AL
;------------------------------------------------------------------------------------------------
; Write physical sector to host
; Converted from the Z80-MBC2 BIOS (S030818-R140319)
; I left the original Z80 code in the comments.
;------------------------------------------------------------------------------------------------
writehst:
push cx ;push bc
push bx ;push hl
call setDTS ;call setDTS ; Select disk, track, sector
;
; Write current host sector (512 byte) to hstbuf
;ld c, EXC_WR_OPCD ; Set the EXECUTE WRITE OPCODE port into C
mov bx, offset hstbuf ;ld hl, hstbuf ; HL points to buffer hstbuf
mov al, WRTSECT_OPC ;ld a, WRTSECT_OPC ; Select WRITESECT opcode (IOS)
out STO_OPCD, al ;out (STO_OPCD), a
;ld b, 0 ; Byte counter = 256
;otir ; Write 256 byte to hstbuf
;otir ; Write 256 byte to hstbuf
mov cx, 512 ; Bytes to read counter = 512
wrhst:
mov al, [bx] ; Read a byte from buffer...
out EXC_WR_OPCD, al ; ...and write it to IOS
inc bx ; Update the pointer to hstbuf
loop wrhst
; Check for errors
mov al, ERRDSK_OPC ;ld a, ERRDSK _OPC ; Select ERRDISK opcode (IOS)
out STO_OPCD, al ;out (STO_OPCD), a
in al, EXC_RD_OPCD ;in a, (EXC_RD_OPCD); Read error code into A...
mov erflag, al ;ld (erflag),a ; ... and store it into erflag
pop bx ;pop hl
pop cx ;pop bc
ret ; Return with the success/error code in AL
;------------------------------------------------------------------------------------------------
; Set disk, track and sector routine for a read or write operation on the V20-MBC.
; Converted from the Z80-MBC2 BIOS (S030818-R140319).
; I left the original Z80 code in the comments.
;------------------------------------------------------------------------------------------------
setDTS:
; Select hstdsk host disk (AL = A, AH = B)
mov al, lastDsk ;ld a, (lastDsk)
mov ah, al ;ld b, a ; B = last disk number
mov al, hstdsk ;ld a, (hstdsk) ; A = new disk number
cmp al, ah ;cp b ; previous disk = new disk?
jz setTrack ;jr z, setTrack ; Yes, jump ahead
mov al, SELDISK_OPC ;ld a, SELDISK_OPC ; No, Select SELDISK opcode (IOS)
out STO_OPCD, al ;out (STO_OPCD), a
mov al, hstdsk ;ld a, (hstdsk) ; Select the disk number (hstdsk)
out EXC_WR_OPCD, al ;out (EXC_WR_OPCD), a
mov lastDsk, al ;ld (lastDsk), a ; Update last disk number
; Select hsttrk host track
setTrack:
mov al, SELTRCK_OPC ;ld a, SELTRCK_OPC ; Select SELTRACK opcode (IOS)
out STO_OPCD, al ;out (STO_OPCD), a
mov ax, hsttrk ;ld a, (hsttrk) ; Select the track number (hsttrk) LSB
out EXC_WR_OPCD, al ;out (EXC_WR_OPCD), a
mov al, ah ;ld a, (hsttrk+1) ; Select the track number (hsttrk) MSB
out EXC_WR_OPCD, al ;out (EXC_WR_OPCD), a
; Select hstsec host sector
mov al, SELSECT_OPC ;ld a, SELSECT_OPC ; Select SELSECT opcode (IOS)
out STO_OPCD, al ;out (STO_OPCD), a
mov al, hstsec ;ld a, (hstsec) ; Select the sector number (hstsec)
out EXC_WR_OPCD, al ;out (EXC_WR_OPCD), a
ret
lastDsk db 0FFh ; Last disk number (= 0FFh after cold boot)
;--vv---------------- SAH ----------------vv--
;| |
IF not loader_bios
; Enter here when CCP is about to look for .CMD file
;
; open and execute .CMD file, if found
;
check_cmd:
call ccp_open ; open .CMD file
jz check_save
mov byte ptr mcb_alloc,false ; flag 8080 bank not available
jmp ccp_cmd ; success, back to ccp to load and execute
; execute SAVE command, if specified and 8080 bank still available
;
check_save:
mov si,offset ccp_file +1
mov di,offset save_cmd
mov cx,5
cld
rep cmpsb ; SAVE command?
jnz check_com ; no, check for .COM file
cmp byte ptr mcb_alloc,true ; 8080 bank available?
jnz check_error ; no, back to ccp as error
call save_pages ; yes, save pages from 8080 bank
jmp ccp_exit ; back to ccp
; open and execute .COM file, if found
;