summaryrefslogtreecommitdiff
path: root/v2.0/source/SKELIO.ASM
blob: b2ff8e3c69d77dbd783e55cd777bb8b2e37579a9 (plain) (blame)
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
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
       TITLE   IO.SYS for the ALTOS ACS-86C.

; I/O system for Version 2.x of MSDOS.

;This BIOS designed to be linked with the SYSINIT module provided by
;Microsoft

BIOSIZ  EQU     4096            ;Size of BIOS in bytes.
BIOSIZS EQU     100H            ;Size of BIOS in Paragraphs.
ANSI    EQU     0               ;Ansi switch.

;Additional Information for the ALTOS machine.

QSIZE   EQU     100             ;Input queue size.
BIOSSEG EQU     0C0H            ;I/O system segment.
MAX_MEM EQU     4000H           ;Memory size in paragraphs.

; Constants for commands in Altos ROM.

ROM_CONSTA      EQU     01      ;Return status AL of console selected in CX.
ROM_CONIN       EQU     02      ;Get char. from console in CX to AL
ROM_CONOUT      EQU     03      ;Write char. in DL to console in CX.
ROM_PMSG        EQU     07      ;Write string ES:DX to console in CX.
ROM_DISKIO      EQU     08      ;Perform disk I/O from IOPB in ES:CX.
ROM_INIT        EQU     10      ;Returns boot console and top memory ES:DX.

;Things needed to communicate with SYSINIT

EXTRN   SYSINIT:FAR                   ;The entry point of SYSINIT
EXTRN   CURRENT_DOS_LOCATION:WORD     ;Where the DOS is when SYSINIT called
EXTRN   FINAL_DOS_LOCATION:WORD       ;Where I want SYSINIT to put the DOS
EXTRN   DEVICE_LIST:DWORD             ;Pointer to the DEVICE list.
EXTRN   MEMORY_SIZE:WORD              ;Size in paragraphs of Physical memory.
EXTRN   DEFAULT_DRIVE:BYTE            ;Default Drive to use when system booted
EXTRN   BUFFERS:BYTE                  ;Number of default buffers.
                                      ; Leave as is and SYSINIT uses only 2.

CODE    SEGMENT
ASSUME  CS:CODE,DS:CODE,ES:CODE,SS:CODE

        ORG     0               ;Starts at an offset of zero.

INIT:   JMP     HWINIT

        PAGE

        SUBTTL  Device driver tables.

;-----------------------------------------------+
;     DWORD pointer to next device              | 1 word offset.
;         (-1,-1 if last device)                | 1 word segement.
;-----------------------------------------------+
;     Device attribute WORD                     ; 1 word.
;       Bit 15 = 1 for chacter devices.         ;
;                0 for Block devices.           ;
;                                               ;
;       Charcter devices. (Bit 15=1)            ;
;         Bit 0 = 1  current sti device.        ;
;         Bit 1 = 1  current sto device.        ;
;         Bit 2 = 1  current NUL device.        ;
;         Bit 3 = 1  current Clock device.      ;
;                                               ;
;         Bit 13 = 1 for non IBM machines.      ;
;                  0 for IBM machines only.     ;
;         Bit 14 = 1 IOCTL control bit.         ;
;-----------------------------------------------+
;     Device strategy pointer.                  ; 1 word offset.
;-----------------------------------------------+
;     Device interrupt pointer.                 ; 1 word offset.
;-----------------------------------------------+
;     Device name field.                        ; 8 bytes.
;       Character devices are any valid name    ;
;         left justified, in a space filled     ;
;         field.                                ;
;       Block devices contain # of units in     ;
;         the first byte.                       ;
;-----------------------------------------------+

DEVSTART LABEL WORD
CONDEV:                         ;Header for device CON
        DW      AUXDEV,BIOSSEG  ;Link to next device
        DW      8003H           ;Attributes - console input, output device
        DW      STRATEGY        ;Srategy entry point
        DW      CON_INT         ;Interrupt entry point
        DB      "CON     "      ;Device name

AUXDEV:                         ;Header for device AUX
        DW      PRNDEV,BIOSSEG
        DW      8000H
        DW      STRATEGY
        DW      AUX_INT
        DB      "AUX     "

PRNDEV:                         ;Header for device PRN
        DW      TIMDEV,BIOSSEG
        DW      8000H
        DW      STRATEGY
        DW      PRN_INT
        DB      "PRN     "

TIMDEV:                         ;Header for device CLOCK
        DW      DSKDEV,BIOSSEG
        DW      8008H
        DW      STRATEGY
        DW      TIM_INT
        DB      "CLOCK   "

DSKDEV:                         ;Header for disk devices
        DW      -1,-1           ;Last device
        DW      2000H           ;Is a block device
        DW      STRATEGY
        DW      DSK_INT
DRVMAX  DB      1               ;Number of Units
        DB      7 DUP (?)

        PAGE
        SUBTTL  Dispatch tables for each device.

DSKTBL: DW      DSK_INIT        ;0  - Initialize Driver.
        DW      MEDIAC          ;1  - Return current media code.
        DW      GET_BPB         ;2  - Get Bios Parameter Block.
        DW      CMDERR          ;3  - Reserved. (currently returns error)
        DW      DSK_RED         ;4  - Block read.
        DW      BUS_EXIT        ;5  - (Not used, return busy flag)
        DW      EXIT            ;6  - Return status. (Not used)
        DW      EXIT            ;7  - Flush input buffer. (Not used.)
        DW      DSK_WRT         ;8  - Block write.
        DW      DSK_WRV         ;9  - Block write with verify.
        DW      EXIT            ;10 - Return output status.
        DW      EXIT            ;11 - Flush output buffer. (Not used.)
        DW      EXIT            ;12 - IO Control.

CONTBL: DW      EXIT            ;0  - Init. (Not used)
        DW      EXIT            ;1  - Media check (Not used)
        DW      EXIT            ;2  - Get Bios Parameter Block (Not used)
        DW      CMDERR          ;3  - Reserved. (Currently returns error)
        DW      CON_READ        ;4  - Character read. (Destructive)
        DW      CON_RDND        ;5  - Character read. (Non-destructive)
        DW      EXIT            ;6  - Return status. (Not used)
        DW      CON_FLSH        ;7  - Flush Input buffer.
        DW      CON_WRIT        ;8  - Character write.
        DW      CON_WRIT        ;9  - Character write with Verify.
        DW      CON_WRST        ;10 - Character write status.
        DW      EXIT            ;11 - Flush output buffer. (Not used.)
        DW      EXIT            ;12 - IO Control.

AUXTBL: DW      EXIT            ;0  - Init. (Not used)
        DW      EXIT            ;1  - Media check (Not used)
        DW      EXIT            ;2  - Get Bios Parameter Block (Not used)
        DW      CMDERR          ;3  - Reserved. (Returns an error)
        DW      AUX_READ        ;4  - Character read. (Destructive)
        DW      AUX_RDND        ;5  - Character read. (Non-destructive)
        DW      EXIT            ;6  - Return status. (Not used)
        DW      AUX_CLR         ;7  - Flush Input buffer.
        DW      AUX_WRIT        ;8  - Character write.
        DW      AUX_WRIT        ;9  - Character write with verify.
        DW      AUX_WRST        ;10 - Character write status.
        DW      EXIT            ;11 - Flush output buffer. (Not used.)
        DW      EXIT            ;12 - IO Control.

TIMTBL: DW      EXIT            ;0  - Init. (Not used)
        DW      EXIT            ;1  - Media check (Not used)
        DW      EXIT            ;2  - Get Bios Parameter Block (Not used)
        DW      CMDERR          ;3  - Reserved. (Currently returns an error)
        DW      TIM_RED         ;4  - Character read. (Destructive)
        DW      BUS_EXIT        ;5  - (Not used, returns busy flag.)
        DW      EXIT            ;6  - Return status. (Not used)
        DW      EXIT            ;7  - Flush Input buffer. (Not used)
        DW      TIM_WRT         ;8  - Character write.
        DW      TIM_WRT         ;9  - Character write with verify.
        DW      EXIT            ;10 - Character write status. (Not used)
        DW      EXIT            ;11 - Flush output buffer. (Not used)
        DW      EXIT            ;12 - IO Control.

PRNTBL: DW      EXIT            ;0  - (Not used)
        DW      EXIT            ;1  - (Not used)
        DW      EXIT            ;2  - Block (Not used)
        DW      CMDERR          ;3  - Reserved. (currently returns error)
        DW      EXIT            ;4  - (Not used)
        DW      BUS_EXIT        ;5  - (Not used, returns busy flag.)
        DW      EXIT            ;6  - (Not used)
        DW      EXIT            ;7  - (Not used)
        DW      PRN_WRT         ;8  - Character write.
        DW      PRN_WRT         ;9  - Character write with verify.
        DW      PRN_STA         ;10 - Character write status.
        DW      EXIT            ;11 - (Not used.)
        DW      EXIT            ;12 - IO Control.

        PAGE
        SUBTTL  Strategy and Software Interrupt routines.

;Define offsets for io data packet

IODAT   STRUC
CMDLEN  DB      ?               ;LENGTH OF THIS COMMAND
UNIT    DB      ?               ;SUB UNIT SPECIFIER
CMD     DB      ?               ;COMMAND CODE
STATUS  DW      ?               ;STATUS
        DB      8 DUP (?)
MEDIA   DB      ?               ;MEDIA DESCRIPTOR
TRANS   DD      ?               ;TRANSFER ADDRESS
COUNT   DW      ?               ;COUNT OF BLOCKS OR CHARACTERS
START   DW      ?               ;FIRST BLOCK TO TRANSFER
IODAT   ENDS

PTRSAV  DD      0               ;Strategy pointer save.

;
; Simplistic Strategy routine for non-multi-Tasking system.
;
;   Currently just saves I/O packet pointers in PTRSAV for
;   later processing by the individual interrupt routines.
;

STRATP  PROC    FAR

STRATEGY:
        MOV     WORD PTR CS:[PTRSAV],BX
        MOV     WORD PTR CS:[PTRSAV+2],ES
        RET

STRATP  ENDP

;
; Console interrupt routine for processing I/O packets.
;

CON_INT:
        PUSH    SI
        MOV     SI,OFFSET CONTBL
        JMP     SHORT ENTRY

;
; Auxilary interrupt routine for processing I/O packets.
;

AUX_INT:
        PUSH    SI
        MOV     SI,OFFSET AUXTBL
        JMP     SHORT ENTRY

;
; Printer interrupt routine for processing I/O packets.
;

PRN_INT:
        PUSH    SI
        MOV     SI,OFFSET PRNTBL
        JMP     SHORT ENTRY

;
; Clock interrupt routine for processing I/O packets.
;

TIM_INT:
        PUSH    SI
        MOV     SI,OFFSET TIMTBL
        JMP     SHORT ENTRY

;
; Disk interrupt routine for processing I/O packets.
;

DSK_INT:
        PUSH    SI
        MOV     SI,OFFSET DSKTBL

;
; Common program for handling the simplistic I/O packet
;   processing scheme in MSDOS 2.0
;

ENTRY:  PUSH    AX              ;Save all nessacary registers.
        PUSH    CX
        PUSH    DX
        PUSH    DI
        PUSH    BP
        PUSH    DS
        PUSH    ES
        PUSH    BX

        LDS     BX,CS:[PTRSAV]  ;Retrieve pointer to I/O Packet.

        MOV     AL,[BX.UNIT]    ;AL = Unit code.
        MOV     AH,[BX.MEDIA]   ;AH = Media descriptor.
        MOV     CX,[BX.COUNT]   ;CX = Contains byte/sector count.
        MOV     DX,[BX.START]   ;DX = Starting Logical sector.

        XCHG    DI,AX           ;Move Unit & Media into DI temporarily.
        MOV     AL,[BX.CMD]     ;Retrieve Command type. (1 => 11)
        XOR     AH,AH           ;Clear upper half of AX for calculation.
        ADD     SI,AX           ;Compute entry pointer in dispatch table.
        ADD     SI,AX
        CMP     AL,11           ;Verify that not more than 11 commands.
        JA      CMDERR          ;Ah, well, error out.
        XCHG    AX,DI           ;Move Unit & Media back where they belong.
        LES     DI,[BX.TRANS]   ;DI contains addess of Transfer address.
                                ;ES contains segment.
        PUSH    CS
        POP     DS              ;Data segment same as Code segment.
        JMP     [SI]            ;Perform I/O packet command.

        PAGE
        SUBTTL  Common error and exit points.

BUS_EXIT:                       ;Device busy exit.
        MOV     AH,00000011B    ;Set busy and done bits.
        JMP     SHORT EXIT1

CMDERR: MOV     AL,3            ;Set unknown command error #.

;
;  Common error processing routine.
;   AL contains actual error code.
;
;   Error # 0 = Write Protect violation.
;           1 = Unkown unit.
;           2 = Drive not ready.
;           3 = Unknown command in I/O packet.
;           4 = CRC error.
;           5 = Bad drive request structure length.
;           6 = Seek error.
;           7 = Unknown media discovered.
;           8 = Sector not found.
;           9 = Printer out of paper.
;          10 = Write fault.
;          11 = Read fault.
;          12 = General failure.
;

ERR_EXIT:
        MOV     AH,10000001B    ;Set error and done bits.
        STC                     ;Set carry bit also.
        JMP     SHORT EXIT1     ;Quick way out.

EXITP   PROC    FAR             ;Normal exit for device drivers.

EXIT:   MOV     AH,00000001B    ;Set done bit for MSDOS.
EXIT1:  LDS     BX,CS:[PTRSAV]
        MOV     [BX.STATUS],AX  ;Save operation compete and status.

        POP     BX              ;Restore registers.
        POP     ES
        POP     DS
        POP     BP
        POP     DI
        POP     DX
        POP     CX
        POP     AX
        POP     SI
        RET                             ;RESTORE REGS AND RETURN
EXITP   ENDP

        PAGE
        SUBTTL  Main console I/O section.

MCON    DW      0001H
PCON    DW      0002H
ACON    DW      0003H

CHAR    DB      ?               ;Small typeahead buffer for now.

;
; Console keyboard handler.
;

CISTAT: PUSH    CX              ;Save CX pair.
        MOV     AL,[CHAR]
        OR      AL,AL
        JNZ     CISTA9          ;Character still in buffer.
CISTA1: MOV     BX,ROM_CONSTA
        MOV     CX,[MCON]
        CALL    ROM_CALL        ;See if character waiting.
        TEST    AL,AL
        JZ      CISTA9
        MOV     BX,ROM_CONIN
        MOV     CX,[MCON]
        CALL    ROM_CALL        ;Get character from Rom.
        OR      AL,AL
        JZ      CISTA1          ;Got a null character.
        MOV     [CHAR],AL
CISTA9: POP     CX              ;Can't lose CX pair.
        RET

;
; Get a character from the buffer queue.
;

CINP:   CALL    CISTAT          ;Check for character ready in queue.
        JZ      CINP            ;Cycle until one ready.
        MOV     [CHAR],0        ;We have character in AL, clear type a head.
        RET

;
; Console read non-destructive.
;

CON_RDND:
        CALL    CISTAT          ;See if character ready.
        JZ      CON_RDN2        ;No, return busy signal.
CON_RDN1:
        LDS     BX,CS:[PTRSAV]
        MOV     [BX.MEDIA],AL
        JMP     EXIT
CON_RDN2:
        JMP     BUS_EXIT

;
; Console destructive read.
;

CON_READ:
        CALL    CINP            ;Get character.
        STOSB                   ;Save it in users buffer.
        LOOP    CON_READ        ;Loop until CX is exhausted.
        JMP     EXIT

;
; Console flush routine. (ctrl-c, ctrl-f, or ctrl-s inspired)
;

CON_FLSH:
        MOV     [CHAR],0        ;Clear small type a head buffer.
        JMP     EXIT

;
; Console output status routine.
;

CON_WRST:
        JMP     EXIT            ;Yes, normal exit.

;
; Console output routine.
;

CON_WRIT:
        MOV     SI,DI           ;Get destination to source.
CON_WRI1:
        LODS    BYTE PTR ES:[SI]
        PUSH    CX
IF      ANSI
        CALL    CONOUT          ;Call ansi driver.
        ENDIF
IFE     ANSI
        CALL    OUTCHR
        ENDIF
        POP     CX
        LOOP    CON_WRI1        ;Keep going until user buffer through.
        JMP     EXIT

;
; Console character output routine.
;

OUTCHR: MOV     BX,ROM_CONOUT
        MOV     CX,[MCON]       ;Get current console port.
        MOV     DL,AL
        CALL    ROM_CALL
        RET

        PAGE

IF      ANSI

        SUBTTL  ANSI interface section.

;
;ANSI Info and routines. ANSI driver implemented as a finite state automata
;This ANSI driver translates the ANSI standard escape sequences into the
; Zenith Escape sequences used on the Zenith(Heath) Z(H)-19 terminal.
;This is not a full implementation of ANSI, but rather a minimal implementation
; which implements all of the necessary ANSI functions.
;

ESC     EQU     1BH             ;Escape character used in this implementation.
STATE   DW      ST1             ;Current ANSI character state.
PRMPNT  DW      PARMS           ;Current parameter pointer.
PARMS   DB      0,0,0,0,0,0,0   ;Allow for up to eight parameters.
LASTPRM DB      0               ;With this being the eight one.

CMDTABL DB      'A'             ;Cursor up.  "esc","[",#,"A"
        DW      CUU
        DB      'B'             ;Cursor down. "esc","[",#,"B"
        DW      CUD
        DB      'C'             ;Cursor forward. "esc","[",#,"C"
        DW      CUF
        DB      'D'             ;Cursor back. "esc","[",#,"D"
        DW      CUB
        DB      'H'             ;Direct cursor posit. "esc","[",x,y,"H"
        DW      CUP
        DB      'J'             ;Erase. "esc","[",code,"J"
        DW      ED
        DB      'K'             ;Erase in line. "esc","[",code,"K"
        DW      EL
        DB      'f'             ;Direct cursor posit. "esc","[",x,y,"f"
        DW      CUP
        DB      'm'             ;Special video mode. "esc","[",code,"m"
        DW      SGR
        DB      's'             ;Save cursor posit. "esc","[","s"
        DW      PSCP
        DB      'u'             ;Move cursor to saved. "esc","[","u"
        DW      PRCP
        DB      00              ;End of table.

;
; ANSI console output driver.
;

CONOUT: MOV     DI,OFFSET STATE ;Retrieve current ansi state.
        JMP     [DI]            ;Jump to it.

;
; State one (1).
;   Looks for an Escape character.
;

ST1:    CMP     AL,ESC          ;See if this the first character is ESC.
        JNZ     OUTCHR          ;No, treat as regular character output.
        MOV     WORD PTR [DI],OFFSET ST2        ;Yes, setup state two.
        RET

;
; State two (2).
;   Looks for the "[" character.
;

ST2:    CMP     AL,'['          ;See if a valide state two.
        JNZ     OUTCHR          ;No, treat as regular charcter
        MOV     BX,OFFSET PARMS ;Yes, get parameter pointer.
        MOV     WORD PTR [PRMPNT],BX    ;Setup in pointer index.
        MOV     WORD PTR [BX],0 ;Clear first entry.
        MOV     WORD PTR [DI],OFFSET ST3;Setup for state three.
        RET

;
; State three (3).
;   Entered one or more times for parameter passing.
;

ST3:    CMP     AL,';'          ;Look for decimal # seperator.
        JNZ     ST3A            ;No check phase A.
        INC     WORD PTR [PRMPNT]       ;Yes, incr. pointer to next param.
        MOV     AX,OFFSET LASTPRM       ;Check for outside parameter list.
        CMP     [PRMPNT],AX
        JBE     RETST3          ;Yes, proceed with next parameter.
        MOV     [PRMPNT],AX     ;No, treat as extentsion to old.
RETST3: MOV     DI,[PRMPNT]     ;Setup for next parameter.
        MOV     BYTE PTR [DI],0 ;Pre-Initialize it to zero.
        RET

;
; State three A (3A).
;   Check for a ascii digit.
;

ST3A:   CMP     AL,'0'          ;Check for ASCII digit.
        JB      ST3B            ;No, check for seconday command character.
        CMP     AL,'9'          ;Still checking for ASCII digit.
        JA      ST3B            ;No, it must be a secondary.
        SUB     AL,'0'          ;Convert to binary.
        MOV     DI,[PRMPNT]     ;Get the current parameter pointer.
        XCHG    [DI],AL         ;Get existing #.
        MOV     AH,10           ;Scale by 10.
        MUL     AH
        ADD     [DI],AL         ;Add to new digit.
        RET

;
; State three B (3B).
;   Wasn't a ascii digit, so check for secondary command.
;

ST3B:   MOV     [DI],OFFSET ST1         ;Preset STATE to state 1 just in case.
        MOV     DI,OFFSET PARMS-1       ;Get pointer to start of parameters.
        MOV     [PRMPNT],DI             ;Save it in Parameter pointer.
        MOV     DI,OFFSET CMDTABL-3     ;Get start of Secondary command table.

ST3B1:  ADD     DI,3            ;Update Command table pointer.
        CMP     BYTE PTR [DI],0 ;Check for end of table.
        JNZ     ST3B2           ;No, continue processing.
        JMP     OUTCHR          ;Yes, treat as regular character.
ST3B2:  CMP     AL,[DI]         ;Check for valid. command.
        JNZ     ST3B1           ;No, keep checking.
        JMP     [DI+1]          ;Yes, transfer to that secondary command.

;
; Get binary parameter from storage and return a one if = 0
;

GETONE: CALL    GETPARM         ;Get parameter form list.
        OR      AL,AL           ;Verify for non-zero.
        JNZ     GETRET          ;Good, then return to caller.
        INC     AL              ;Bad, make it at least a one.
GETRET: CBW                     ;Sign extend AL.
        MOV     CX,AX           ;Copy of it to CX.
        RET

GETPARM:INC     WORD PTR [PRMPNT]       ;Increment parameter pointer.
GOTPARM:MOV     DI,[PRMPNT]     ;Get parameter pointer.
        MOV     AL,[DI]         ;Get parameter value.
        RET

;
; Send escape, character sequence.
;

OUTESC: MOV     AL,ESC          ;Send escape character.
        CALL    OUTCHR
        MOV     AL,BL           ;Send follow character.
        JMP     OUTCHR

;
; Cursor Positioning routines.
;

CUU:    MOV     BL,'A'          ;Cursor up.
        JMP     SHORT CURPOS
CUD:    MOV     BL,'B'          ;Cursor down.
        JMP     SHORT CURPOS
CUF:    MOV     BL,'C'          ;Cursor forward.
        JMP     SHORT CURPOS
CUB:    MOV     BL,'D'          ;Cursor back.

CURPOS: CALL    GETONE          ;Get number of positions to move into CX.
MOVCUR: CALL    OUTESC          ;Send escape, command characters.
        LOOP    MOVCUR          ;Keep moving until done.
        RET

;
; Direct cursor positioning routine.
;

CUP:    CALL    GETONE          ;Get X position.
        MOV     DX,AX           ;Save in DX.
        CALL    GETONE          ;Get Y position.
        MOV     BL,'Y'
        CALL    OUTESC          ;Send escape, "Y" sequence.
        MOV     AL,DL
        ADD     AL,' '-1        ;Convert binary to Character.
        CALL    OUTCHR          ;Send X posit.
        MOV     AL,CL
        ADD     AL,' '-1        ;Convert binary to Character.
        JMP     OUTCHR          ;Send Y posit.

;
; Erase all/part of screen.
;

ED:     CALL    GETPARM         ;Get trinary command type.
        MOV     BL,'b'
        DEC     AL              ;See if erase from begining of screen.
        JZ      ED1             ;Yes, perform ZDS function.
        MOV     BL,'E'
        DEC     AL              ;See if erase from end of screen.
        JZ      ED1             ;Yes, perform ZDS function.
        MOV     BL,'J'          ;Now we assume erase whole screen.
ED1:    JMP     OUTESC

;
; Erase all/part of a line.
;

EL:     CALL    GETPARM         ;Get trinary command type.
        MOV     BL,'o'
        DEC     AL              ;See if erase from begining of line.
        JZ      EL1             ;Yes, perform ZDS function.
        MOV     BL,'l'
        DEC     AL              ;See if erase whole line.
        JZ      EL1             ;Yes, perform ZDS function.
        MOV     BL,'K'          ;Now we assume erase to end of line.
EL1:    JMP     OUTESC

;
; Special video modes.
;

SGR:    CALL    GETPARM         ;Get trinary command type.
        MOV     BL,'p'
        CMP     AL,7            ;See if enter reverse video mode.
        JZ      SGR2            ;Yes, perform ZDS function.
        MOV     BL,'q'
        OR      AL,AL           ;See if exit reverse video mode.
        JNZ     SGR3            ;No, ignore.
SGR2:   CALL    OUTESC
SGR3:   RET

;
; Save / restore cursor position.
;

PSCP:   MOV     BL,'j'          ;Set save cursor posit. mode.
        JMP     OUTESC

PRCP:   MOV     BL,'k'          ;Restore last cursor save.
        JMP     OUTESC

        ENDIF


        PAGE
        SUBTTL  Printer buffer handler.

;
; Printer status routine.
;

PRN_STA:
        JMP     EXIT

;
; Printer write routine.
;

PRN_WRT:MOV     SI,DI           ;Set source = destination index.

PRN_WR1:LODS    BYTE PTR ES:[SI];Get a data byte.
        PUSH    CX
        MOV     CX,[PCON]
        MOV     BX,ROM_CONOUT
        MOV     DL,AL
        CALL    ROM_CALL
        POP     CX
        LOOP    PRN_WR1
        RET

        PAGE
        SUBTTL  Auxilary I/O routines.

AUXCHAR DB      0               ;Temporary AUX ahead storage.

;
; Status routine for Auxilary port.
;

AISTAT: MOV     AL,[AUXCHAR]
        TEST    AL,AL
        JNZ     AISTA9          ;Character already waiting.
        MOV     CX,[ACON]
        MOV     BX,ROM_CONSTA
        CALL    ROM_CALL
        TEST    AL,AL
        JZ      AISTA9          ;Still none waiting.
        MOV     CX,[ACON]
        MOV     BX,ROM_CONIN
        CALL    ROM_CALL
AISTA9: MOV     [AUXCHAR],AL
        RET

;
; Auxilary port read.
;

AIN:    CALL    AISTAT          ;Get status and/or char.
        JZ      AIN             ;Cycle until one is ready.
        MOV     [AUXCHAR],0
        RET

;
; Write routine for Auxilary port.
;

AOUT:   MOV     CX,[ACON]
        MOV     BX,ROM_CONOUT
        MOV     DL,AL
        CALL    ROM_CALL
        RET

;
; Non-Destructive Auxilary read routine.
;

AUX_RDND:
        CALL    AISTAT          ;Get status and copy of char. waiting if any.
        JZ      AUX_RDN2        ;No character waiting, exit.
        JMP     CON_RDN1
AUX_RDN2:
        JMP     BUS_EXIT

;
; Destructive Auxilary read routine.
;

AUX_READ:
        CALL    AIN             ;Get data character.
        STOSB                   ;Save it through DI.
        LOOP    AUX_READ        ;Cycle until user buffer full.
        JMP     EXIT

;
; Auxilary clear type a head.
;

AUX_CLR:
        MOV     [AUXCHAR],0
        JMP     EXIT

;
; Auxilary write port status.
;

AUX_WRST:
        JMP     EXIT

;
; Auxilary write.
;

AUX_WRIT:
        MOV     SI,DI
AUX_WRI1:
        LODS    BYTE PTR ES:[SI]        ;Get char. from users buffer.
        CALL    AOUT            ;Send it to device.
        LOOP    AUX_WRI1        ;Cycle until all done.
        JMP     EXIT

        PAGE
        SUBTTL  Date/Time Routines.

TIM_DAYS: DB    2 DUP (?)       ;Number of days since 1-1-80.
TIM_MINS: DB    ?               ;Minutes.
TIM_HRS:  DB    ?               ;Hours.
TIM_HSEC: DB    ?               ;Hundreths of a second.
TIM_SECS: DB    ?               ;Seconds.

;
; Time write routine.
;

TIM_WRT:
        MOV     SI,OFFSET TIM_DAYS
        XCHG    SI,DI
        PUSH    ES
        MOV     AX,DS
        POP     DS
        MOV     ES,AX
        MOV     CX,6
        REP     MOVSB
        MOV     AL,0
        JMP     EXIT

;
; Time read routine.
;

TIM_RED:
        MOV     SI,OFFSET TIM_DAYS
        MOV     CX,6
        REP     MOVSB
        MOV     AL,0
        JMP     EXIT

        PAGE
        SUBTTL  8089 Monitor structure.

;
; Structure to reference 8089 and ROM command table.
;

SIOPB   STRUC
        DB      4 DUP (?)       ;Monitor Use Only
OPCODE  DB      ?               ;I/O operation code.
DRIVE   DB      ?               ;Logical drive spec.
TRACK   DW      ?               ;Logical track number.
HEAD    DB      ?               ;Logical head number.
SECTOR  DB      ?               ;Logical sector to start with.
SCOUNT  DB      ?               ;Number of logical sectors in buffer.
RETCODE DB      ?               ;Error code after masking.
RETMASK DB      ?               ;Error mask.
RETRIES DB      ?               ;Number of retries before error exit.
DMAOFF  DW      ?               ;Buffer offset address.
DMASEG  DW      ?               ;Buffer segment.
SECLENG DW      ?               ;Sector Length.
        DB      6 DUP (?)       ;8089 use only.
SIOPB   ENDS

IOPB    SIOPB   <,00H,0,0,0,0,0,0,000H,0,0,0,0,>

        PAGE
        SUBTTL  Drive Tables.


;
; MSDOS drive initialization tables and other what not.
;
;  Drive 0 is:
;               Single sided, Single density, 77 track with 26
;               128 byte sectors per track.  One sector for
;               boot and header.  (256,128 bytes free, old style).
;       or
;               Single sided, Single density, 77 track with 26
;               128 byte sectors per track.  Four sectors for
;               boot and header. (255,744 bytes free).
;       or
;               Single sided, Double Density, 75 track with 12
;               512 byte sectors per track.
;               (460,800 bytes)
;               Two hidden single density tracks.
;

DBP     STRUC

JMPNEAR DB      3 DUP (?)       ;Jmp Near xxxx  for boot.
NAMEVER DB      8 DUP (?)       ;Name / Version of OS.

;-------  Start of Drive Parameter Block.

SECSIZE DW      ?               ;Sector size in bytes.                  (dpb)
ALLOC   DB      ?               ;Number of sectors per alloc. block.    (dpb)
RESSEC  DW      ?               ;Reserved sectors.                      (dpb)
FATS    DB      ?               ;Number of FAT's.                       (dpb)
MAXDIR  DW      ?               ;Number of root directory entries.      (dpb)
SECTORS DW      ?               ;Number of sectors per diskette.        (dpb)
MEDIAID DB      ?               ;Media byte ID.                         (dpb)
FATSEC  DW      ?               ;Number of FAT Sectors.                 (dpb)

;-------  End of Drive Parameter Block.

SECTRK  DW      ?               ;Number of Sectors per track.

DBP     ENDS

LSDRIV1 DBP     <,,128,4,1,2,68,2002,0FEH,6,26>

LSDRIV2 DBP     <,,128,4,4,2,68,2002,0FDH,6,26>

LDDRIV1 DBP     <,,512,1,24,2,128,924,0F8H,3,12>

LDDRIV2	DBP	<,,1024,1,16,2,128,616,0F9H,1,8>

DSK_INIT:
	MOV     AX,1
        MOV     SI,OFFSET INITTAB
        JMP     GET_BP5

INITTAB:
        DW      LDDRIV2.SECSIZE

DSTAT   EQU     41H             ;1793 status port.
DTRACK  EQU     43H             ;1793 track port.
DSECTOR EQU     45H             ;1793 sector port.
DDATA   EQU     47H             ;1793 data I/O port.

DDENS   EQU     55H             ;Density select port.
DDBIT	EQU	04H		;Density select bit.
DSELECT EQU     53H             ;Drive select port.

CURDRV  DB      0
DRVTAB  DB      0EH,0DH,0BH,07H
TRKPT   DB      0,1,2,3
TRKTAB  DB      -1,-1,-1,-1
PREDENS DB      0,0,0,0

        PAGE
        SUBTTL  Media check routine

;
; Media check routine.
; On entry:
;       AL = disk unit number.
;       AH = media byte
; On exit:
;
;       [MEDIA FLAG] = -1 (FF hex) if disk is changed.
;       [MEDIA FLAG] = 0 if don't know.
;       [MEDIA FLAG] = 1 if not changed.
;
;       [MEDIA] = 0FEH for Standard single density.
;       [MEDIA] = 0FDH for Altos single density.
;       [MEDIA] = 0F4H for Altos double density.
;

MEDIAS  STRUC
        DB      13 DUP(?)               ;Static request header.
MEDIAS1 DB      ?                       ;Media byte.
MEDIAS2 DB      ?                       ;Media status byte flag.
MEDIAS  ENDS

MEDIAC: 
	AND	AL,03H		;Clear any extraneous bits.
	PUSH    AX              ;Save drive number requested.
	MOV	AL,0D0H		;Terminate with no interrupt.
	CALL	DCOM
        AND     AL,20H          ;See if head load bit set.
        POP     AX
        JZ	MEDIA2		;Head not loaded, so see if media changed.
        MOV     AH,1            ; AH = 1, disk not changed.
	JMP	SHORT MEDIA1

MEDIA1A:MOV	[PREDENS],DL	;Save last density used for read.

MEDIA1: LDS     BX,[PTRSAV]     ;Udate media section of data block.
        MOV     [BX.MEDIAS2],AH
	MOV	AL,0
        JMP     EXIT

MEDIA2: CALL    MEDIA4          ;Unload head if selecting new drive.
        MOV     CX,2            ;Try each density once.
	MOV	BX,OFFSET DRVTAB
	XLAT			;Convert from drive # to select code.
        OUT     DSELECT,AL      ;Select disk
	MOV	AH,0		;Assume that we don't know.
	MOV	DL,[PREDENS]	;Get last density.
	AND	DL,DDBIT	;Be sure only Density bit set/clr.
MEDIA3:	IN	AL,DDENS
	AND	AL,0FBH		;Clear density bit.
	OR	AL,DL		;Set/clear density bit.
        OUT     DDENS,AL        ;Select density.
        MOV     AL,0C4H         ;READ ADDRESS command
        CALL    DCOM
        AND     AL,98H
        IN      AL,DDATA        ;Eat last byte to reset DRQ
        JZ      MEDIA1A         ;Jump if no error in reading address.
        MOV     AH,0FFH         ; AH = -1 (disk changed) if new density works.
        XOR     DL,DDBIT	;Flip density bit.
        LOOP    MEDIA3
        MOV     AX,2            ;Couldn't read disk at all, AH = 0 for don't
        JMP     ERR_EXIT        ;  know if disk changed, AL = error code 2 -

MEDIA4: MOV     AH,AL           ;Save disk drive number in AH.
        XCHG    AL,[CURDRV]     ;make new drive current, AL = previous
        CMP     AL,AH           ;Changing drives?
        JZ      MEDIA5          ;No, return to caller.
;
; If changing drives, unload head so the head load delay one-shot
; will fire again. Do it by seeking to same track with the H bit reset.
;
        IN      AL,DTRACK       ;Get current track number
        OUT     DDATA,AL        ;Make it the track to seek to
        MOV     AL,10H          ;Seek and unload head
        CALL    DCOM
        MOV     AL,AH           ;Restore current drive number
MEDIA5: RET

;
; Short routine to send a command to 1793 diskette controller chip and
; wait for 1793 to complete the command.
;

DCOM:   OUT     41H,AL          ;Send command to 1793.
        MOV     CX,10H
DCOM1:  LOOP    DCOM1           ;Wait a short time for 1793 to digest it.

DCOM2:  IN      AL,41H          ;Get 1793's status.
        AND     AL,1            ;See if busy.
        JNZ     DCOM2           ;Yes, keep checking.
        IN      AL,41H          ;Get 1793's status for return
        RET

        PAGE
        SUBTTL  Build and return Bios Parameter Block for a diskette.

;
; Build Bios Parameter Blocks.
;
;       On entry:  ES:DI contains the address of a scratch sector buffer.
;                  AL = Unit number.
;                  AH = Current media byte.
;
;       On exit:   Return a DWORD pointer to the associated BPB
;                  in the Request packet.
;

BPBS    STRUC
        DB      13 DUP(?)               ;Static request header.
BPB1    DB      ?                       ;Media byte.
BPB2    DW      ?                       ;DWORD transfer address.
        DW      ?
BPB3    DW      ?                       ;DWORD pointer to BPB
        DW      ?
BPBS    ENDS

GET_BPB:
	PUSH    ES
        PUSH    DI
        MOV     [IOPB.DMASEG],ES
        MOV     [IOPB.DMAOFF],DI
	MOV	BYTE PTR[IOPB.SECTOR],1
	MOV	BYTE PTR[IOPB.SCOUNT],1
	MOV	BYTE PTR[IOPB.OPCODE],088H
	MOV	BYTE PTR[IOPB.RETRIES],1
	MOV	BYTE PTR[IOPB.DRIVE],0
	MOV	[IOPB.TRACK],0
	MOV	BYTE PTR[IOPB.HEAD],1
	MOV	BYTE PTR[IOPB.RETMASK],0DCH
	MOV	[IOPB.SECLENG],128
        MOV     BX,ROM_DISKIO
        MOV     CX,OFFSET IOPB
        PUSH    CS
        POP     ES
        CALL    ROM_CALL        ;Read sector zero for information.
	PUSH	CS
	POP	DS
	POP	DI
        POP     ES
        MOV     AH,[IOPB.RETCODE]
        OR      AH,AH
	JNZ	GET_BP3		;Disk error, assume old single density.

GET_BP1:MOV     AL,ES:[DI.MEDIAID] ;Get diskettes media ID.
        MOV     SI,OFFSET LSDRIV2
        CMP     AL,[SI.MEDIAID]
        JZ      GET_BP4
        MOV     SI,OFFSET LDDRIV1
        CMP     AL,[SI.MEDIAID]
        JZ      GET_BP4
	MOV	SI,OFFSET LDDRIV2
	CMP	AL,[SI.MEDIAID]
	JZ	GET_BP4

GET_BP3:MOV     SI,OFFSET LSDRIV1 ;No compares, assume old style for now.

GET_BP4:MOV     AL,[SI.MEDIAID]
        ADD     SI,11           ;Convert to DPB pointer

GET_BP5:LDS     BX,[PTRSAV]     ;Update I/O data packet.
        MOV     [BX.BPB1],AL    ;Media byte.
        MOV     [BX.BPB3],SI    ;DPB pointer.
        MOV     [BX.BPB3+2],CS  ;Code segment.
	OR	AH,AH
	JNZ	GET_BP6
	MOV	AL,0
	JMP     EXIT
GET_BP6:MOV	AX,7
	JMP	ERR_EXIT

        PAGE

        SUBTTL  Disk I/O equates.

;       Floppy drives

;      --------------------------
;         Hardware command def.
;      --------------------------
;
;            Read command    = 88 hex.
;            Write command   = A8 hex.
;            Format command  = F0 hex.
;            Seek command    = 1E hex.
;            Recal command   = 0A hex.
;            Set DD mode     = 80 hex.
;
;      --------------------------
;        Status bits:
;      --------------------------
;
;            Busy            = 01 hex.
;            (not used)      = 02 hex.
;               TK0(seek)    = 04 hex.
;               Lost Data    = 04 hex.
;            CRC error       = 08 hex.
;               Seek error   = 10 hex.
;               Not found    = 10 hex.
;            Write fault     = 20 hex.
;            Write protect   = 40 hex.
;            Not ready       = 80 hex.
;
;      --------------------------

F_READ  EQU     088H            ;Floppy read command.
F_WRIT  EQU     0A8H            ;Floppy write command.
F_FMT   EQU     0F0H            ;Floppy format command.
F_SEEK  EQU     01EH            ;Floppy seek command.
F_RECAL EQU     00AH            ;Floppy recal. command.
F_DD    EQU     080H            ;Set Drive double density bit.

        PAGE
        SUBTTL  MSDOS 2.x Disk I/O drivers.

;
; Disk READ/WRITE functions.
;
; On entry:
;       AL = Disk I/O driver number
;       AH = Media byte.
;       ES = Disk transfer segment.
;       DI = Disk transfer offset in ES.
;       CX = Number of sectors to transfer
;       DX = Logical starting sector.
;
; On exit:
;       Normal exit through common exit routine.
;
;       Abnormal exit through common error routine.
;

DSK_RED:
        MOV     BX,0DC88H               ;Set read mode and Error mask.
        JMP     SHORT DSK_COM
DSK_WRV:
DSK_WRT:MOV     BX,0FCA8H               ;Set write mode and Error mask.

DSK_COM:MOV     SI,OFFSET LSDRIV1
        CMP     AH,[SI.MEDIAID]
        JE      DSK_CO3
        MOV     SI,OFFSET LSDRIV2
        CMP     AH,[SI.MEDIAID]
        JE      DSK_CO3
        MOV     SI,OFFSET LDDRIV1
        CMP     AH,[SI.MEDIAID]
        JE      DSK_CO2
	MOV	SI,OFFSET LDDRIV2
	CMP	AH,[SI.MEDIAID]
	JE	DSK_CO2
        MOV     AL,7
        JMP     ERR_EXIT

DSK_CO2:OR      AL,F_DD                 ;Set double density mode.

DSK_CO3:MOV     [IOPB.DMASEG],ES	;Setup Buffer segment.
        MOV     [IOPB.DMAOFF],DI	;Setup buffer offset.
        MOV     DI,[SI.SECSIZE]		;Get sector size.
        MOV     [IOPB.SECLENG],DI
        MOV     [IOPB.RETRIES],1	;Setup number of retries.
        MOV     [IOPB.RETMASK],BH	;Operation error mask.
        MOV     [IOPB.OPCODE],BL	;R/W opcode.
        MOV     [IOPB.DRIVE],AL		;Drive with density select.
        MOV     [IOPB.HEAD],1           ;Only one head on floppy drive.
        MOV     BP,CX                   ;Save number of sectors to R/W
DSK_CO4:PUSH    DX                      ;Save starting sector.
        MOV     AX,DX
        MOV     DX,0                    ;32 bit divide coming up.
        MOV     CX,[SI.SECTRK]
        DIV     CX                      ;Get track+head and start sector.
        INC     DL
        MOV     [IOPB.SECTOR],DL        ;Starting sector.
        MOV     BL,DL                   ;Save starting sector for later.
        MOV     [IOPB.TRACK],AX         ;Track to read/write.
        MOV     AX,[SI.SECTRK]          ;Now see how many sectors
        INC     AL                      ;  we can burst read.
        SUB     AL,BL                   ;BL is the starting sector.
        MOV     AH,0
        POP     DX                      ;Retrieve logical sector start.
        CMP     AX,BP                   ;See if on last partial track+head.
        JG      DSK_CO5                 ;Yes, on last track+head.
        SUB     BP,AX                   ;No, update number of sectors left.
        ADD     DX,AX                   ;Update next starting sector.
        JMP     SHORT DSK_CO6
DSK_CO5:MOV     AX,BP                   ;Only read enough of sector
        MOV     BP,0                    ;to finish buffer and clear # left.
DSK_CO6:MOV     [IOPB.SCOUNT],AL
        MOV     DI,AX                   ;Save number sectors for later.
        MOV     BX,ROM_DISKIO
        MOV     CX,OFFSET IOPB
        PUSH    CS
        POP     ES
        CALL    ROM_CALL                ;Do disk operation.
        MOV     AL,[IOPB.RETCODE]       ;Get error code.
        OR      AL,AL
        JNZ     DERROR
        MOV     AX,DI                   ;Retrieve number of sectors read.
        MOV     CX,[SI.SECSIZE]         ;Number of bytes per sector.
        PUSH    DX
        MUL     CX
        POP     DX
        TEST    AL,0FH                  ;Make sure no strange sizes.
        JNZ     DSK_CO7			;Illegal sector size found.
        MOV     CL,4
        SHR     AX,CL                   ;Convert number of bytes to para.
        ADD     AX,[IOPB.DMASEG]
        MOV     [IOPB.DMASEG],AX
        OR      BP,BP
        JNZ     DSK_CO4                 ;Still more to do.
        MOV     AL,0
        JMP	EXIT                    ;All done.
DSK_CO7:MOV     AL,12
        JMP	ERR_EXIT

        PAGE
        SUBTTL  Disk Error processing.

;
; Disk error routine.
;

DERROR: LDS     BX,CS:[PTRSAV]
        MOV     [BX.COUNT],0
        PUSH    CS
        POP     DS

        MOV     BL,-1
        MOV     AH,AL
        MOV     BH,14           ;Lenght of table.
        MOV     SI,OFFSET DERRTAB
DERROR2:INC     BL              ;Increment to next error code.
        LODS    BYTE PTR CS:[SI]
        CMP     AH,AL           ;See if error code matches disk status.
        JZ      DERROR3         ;Got the right error, exit.
        DEC     BH
        JNZ     DERROR2         ;Keep checking table.
        MOV     BL,12           ;Set general type of error.
DERROR3:MOV     AL,BL           ;Now we've got the code.
        RET

DERRTAB DB      40H             ; 0. Write protect error
        DB      00H             ; 1. Unknown unit.
        DB      80H             ; 2. Not ready error.
        DB      0FFH            ; 3. Unknown command.
        DB      08H             ; 4. CRC error
        DB      00H             ; 5. Bad drive request.
        DB      02H             ; 6. Seek error
        DB      00H             ; 7. Unknown media.
        DB      10H             ; 8. Sector not found
        DB      00H             ; 9. (Not used.)
        DB      20H             ;10. Write fault.
        DB      04H             ;11. Read fault.
        DB      07H             ;12. General type of failure.

        PAGE
        SUBTTL  Common ROM call routine.

;
;  Save all registers except CX, BX and AX.

ROMRTN  DD      0FE000000H      ;Main ROM entry point.

ROM_CALL:
        PUSH    DI
        PUSH    SI
        PUSH    BP
        PUSH    DX
        PUSH    ES
        CALL    CS:DWORD PTR [ROMRTN]
        POP     ES
        POP     DX
        POP     BP
        POP     SI
        POP     DI
        RET

        PAGE
        SUBTTL  Initalization code and temporary work areas.

;
; Overlayed by MSDOS by SYSINIT.
;

WRKSTK  LABEL   WORD
        DB      100 DUP (?)


HWINIT: XOR     BP,BP
        MOV     SS,BP
        MOV     SP,OFFSET WRKSTK+98     ;Some nice area for stack.

        PUSH    CS
        POP     ES

        MOV     BX,ROM_INIT
        CALL    ROM_CALL
        MOV     AH,0
        MOV     MCON,AX

        MOV     AX,SEG SYSINIT
        MOV     DS,AX

ASSUME  DS:SEG SYSINIT

        MOV     AX,CS
        ADD     AX,BIOSIZS
        MOV     DS:[CURRENT_DOS_LOCATION],AX
        MOV     DS:[MEMORY_SIZE],MAX_MEM
        MOV     AX,CS
        MOV     WORD PTR DS:[DEVICE_LIST+2],AX
        MOV     WORD PTR DS:[DEVICE_LIST],OFFSET DEVSTART
        MOV     AX,CS
        ADD     AX,((OFFSET WRKSTK - OFFSET INIT)+50) /16
        MOV     DS:[FINAL_DOS_LOCATION],AX
        JMP     SYSINIT

DOSSPOT LABEL   WORD

CODE    ENDS

        END