-
Notifications
You must be signed in to change notification settings - Fork 1
/
X1_compatible_rom.z80
2351 lines (1993 loc) · 64.7 KB
/
X1_compatible_rom.z80
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
;
; X1 compatible IPL
;
; programed by NAKAUE,T
;
; These codes are licensed under CC0.
; http://creativecommons.org/publicdomain/zero/1.0/deed.ja
;
; 2020-07-31 ver0.1.0 first version
; 武田君のエミュレータでS-OS SWORDを起動できた
; バイナリサイズ 950byte,未実装機能があるのに大きい
; 2020-08-01 ver0.2.0 リファクタリング
; ディスク関係以外のアドレスをオリジナルと合わせた
; 連続空きメモリ134バイト
; 2020-08-03 ver0.3.0 ディスク関係並べ替え
; IPL ROMからRAMへの切り替えをRAM上で行うようにした
; 起動時にWIDTH40にする処理で,8255への出力を追加
; 連続空きメモリ118バイト
; 2020-08-04 ver0.3.1 ディスク関係リファクタリングとデバッグ
; ファイルバッファの位置を直し忘れていた
; ファイルバッファが60K CP/Mに潰されるので対策
; 2020-08-05 ver0.3.2 パレット初期化を追加
; 2020-09-13 ver0.4.0 BASIC ROMボードCZ-8RBに対応(実機未所有のため,仕様解説のみで確認)
; EMM0からの起動に対応(CZ-8RBと微妙に仕様が違って面倒)
; 1081バイト。ついに1KB突破……
; そもそもオリジナルのROMサイズを1KBだと勘違いしていた
; (正しくは4KB)
; 2020-09-15 コメントのみ修正
; 2021-03-03 ver0.4.1 ディスクREAD(021ah)にキャリーフラグのクリアを追加
; X-DOS起動不具合対策
; 2022-02-11 ver0.5.0 CMTブート追加のためのリファクタリング
; メニューの大文字/小文字を無視するようにした
; 2022-02-11 ver0.6.0 CMTブート対応
; 2022-02-11 ver0.6.1 CMTブート時のリーダ部(1の連続)の読み飛ばし方法を変更
; ファイル名拡張子(.Sys)のチェックをやめた
; RuinousXIII起動不具合対策
; 2022-02-20 ver0.7.0 ROMブートの不具合修正
; ブートセクタの開始アドレスをオフセット1dhからの3バイトに修正
; (元は1ehからの2バイト)
; EMMとROMのルーチン共用をやめ内部構造が大きく変わったため,バージョン番号を上げた
; デバッグ支援用にモニタの実装を開始
; 2022-02-20 ver0.7.1 リファクタリング
; 2022-02-23 ver0.7.2 8255の初期化を追加
; X1 Fのデモディスクがおかしいのはこれが原因だった
; エラーステータス表示を消した(入らないのであきらめた)
; アドレス固定エントリのorgを減らし,代わりにORG_XXXXラベルを置いた
; ビルド時に.lstファイルのORG_XXXXラベルをチェックすること
; 2022-02-23 ver0.7.3 モニタコマンドを実装
;
; かつて X1エミュの部屋(http://www.turboz.to/)に掲載されていた
; ぷにゅ氏作の IPL ver1.01(x1ipl101.zip,IPLROM.z80)を参考にしている
;
; その他の参考文献
; [1] X1 turbo BIOSの解析, 稲葉 康治, Oh!MZ 1985年1月号, p.97~109
; [2] IOCS DATA LIST, 泉 大介ら, Oh!MZ 1986年11月号, p.76~
; [3] 試験に出るX1, 祝 一平, 日本ソフトバンク, 1987
; [4] HuBASIC Format詳細, BouKiCHi, https://boukichi.github.io/HuDisk/HuBASIC_Format.html
; 2020-07-31 閲覧
; [5] 試験に出ないX1 第0章 まだまだ完全無欠にならないI/Oマップ, X1cetner, http://www.x1center.org/sdx1/sdx1_0.html
; 2022-02-23 閲覧
;
; 開発にあたり武田氏のX1エミュレータ eX1 (http://takeda-toshiya.my.coocan.jp/)を
; 全面的に使用した。eX1の強力なデバッグ機能のお陰でこのプラグラムを作りえた。
; FDD0-3およびROM,EMM,RAM,CMTからの起動を実装した
; Timer関係を実装しない
; モニタの実装が未着手
; 以下のエントリを固定番地とする
; 0066h : NMIリセット(ok)
; 00f5h : IPLエラー処理?(未実装)
; (01cfh : IPL overlay? x1ipl101で固定アドレスとしているが,不要?)
; 021ah : IPL用ディスクREAD
; 038ah : IPL用KEY入力(ok)
; 03cbh : IPL用メッセージ表示(ok)
; 03d9h : IPL用1文字表示ルーチン(ok)
;
; 以下のバッファを固定番地とする
; 0ff80h : カーソルxy
; 0ff86h : テキスト色
; 0ff87h : ドライブ番号
; ワークエリアアドレス
WRKTOP equ 0ff80h ; ワークエリアの先頭アドレス
TXTCUR equ WRKTOP + 0h ; カーソルxy
; WRKTOP + 2h ; 初期化後の0を維持すること
; WRKTOP + 3h ; 初期化後の0を維持すること
; WRKTOP + 4h ; 初期化後の0を維持すること
TXTATR equ WRKTOP + 6h ; テキスト色
IPLDRV equ WRKTOP + 7h ; ドライブ番号
;(ただしROM起動の場合22h,EMM起動の場合15h)
WRKSIZ equ 20h ; ワークエリアの長さ
REDIREC equ WRKTOP + 10h ; IPL ROMからRAMに切り替えるリダイレクタ
EXECADR equ REDIREC + 3 ; 実行アドレス
INPBUF equ WRKTOP + 10h ; モニタの入力文字列用バッファ(リダイレクタ領域と共用)
INPSIZ equ 0eh ; モニタの入力文字列用バッファの長さ
MONADR equ WRKTOP + 1eh ; モニタのアクセス中アドレス
FILEBUF equ 0fe00h ; ファイル読込みバッファ
; +00h ブートフラグ(1バイト)
; +01h ファイル名(13バイト)
; 拡張子と連続で扱う。間のごみが表示されてもご愛敬
; +0eh 拡張子(3バイト)
; 参考文献[4]によれば'Sys'でなければならないが,チェックをやめた
; +11h パスワード(1バイト)
; 無視。0を書き込んで文字列終端にしている
; +12h サイズ(2バイト)
; +14h 読込みアドレス(2バイト)
; +16h 実行アドレス(2バイト)
; +18h 日付(6バイト)
; +1dh ディスク上のオフセット(3バイト)
; 参考文献[4]によれば+1dhが未使用,+1ehが開始セクタとなっているが,
; +1dhからの3バイトでオフセットバイト数を示し,
; 1セクタ256バイトのFDDやEMMでは常に+1dhに00が入っていると考えるとCZ-8RBとの整合が取れる
; 以下はturbo BIOSで使用
COLORF equ 0f8d0h
CLSCHR equ 0f8d1h
; IOアドレス
IOEMM_L equ 0d00h ; EMM アドレス下位
IOEMM_M equ 0d01h ; EMM アドレス中位
IOEMM_H equ 0d02h ; EMM アドレス上位
IOEMM equ 0d03h ; EMM データ読み書き
IOROM_H equ 0e00h ; BASIC ROMボード アドレス上位
IOROM_M equ 0e01h ; BASIC ROMボード アドレス中位
IOROM_L equ 0e02h ; BASIC ROMボード アドレス下位
IOROM equ 0e03h ; BASIC ROMボード データ読出し
IOFDCCR equ 0ff8h ; FDC コマンドレジスタ
IOFDCTR equ 0ff9h ; FDC トラックレジスタ
IOFDCSR equ 0ffah ; FDC セクタレジスタ
IOFDCDR equ 0ffbh ; FDC データレジスタ
IOFDCNO equ 0ffch ; ドライブNo./サイド/モーターON
IOPALET equ 1200h ; パレット
IOCRTC equ 1800h ; CRTC レジスタ
IO80C49 equ 1900h ; サブCPU
IO8255B equ 1a01h ; 8255 port B (CMT読出し)
IO8255C equ 1a02h ; 8255 port C
IO8255L equ 1a03h ; 8255 CWR(controL)
IOIPLOF equ 1e00h ; IPL ROM OFF
IOATTR equ 2000h ; アトリビュートVRAM
IOTEXT equ 3000h ; テキストVRAM
TXTSIZ equ 800h ; テキストVRAMのサイズ
; IOATTRとIOTEXTで異なるビット位置
; log2((IOATTR ^ IOTEXT) >> 8)
BIT_ATTR_TEXT equ 4
; テキストクリアの標準色
TEXT_STD equ 2007h ; 20=SPC,07=白
org 00000h
; ----------------------------------------------------------
; メインルーチンとメニュー
; ----------------------------------------------------------
; IPL起動
IPLBOT:
; ワークエリアの初期化 (インライン展開済み)
; 11バイト
INIT_WORK:
ld sp, WRKTOP + WRKSIZ ; 初期化用の仮設定
ld hl, 0
ld b, WRKSIZ / 2
INIT_WORK_1:
push hl
djnz INIT_WORK_1
; 0以外としたいワーク(たとえばTXTATR)が初期化されていないので注意
INIT_WORK_END:
ld sp, 0 ; ずれたので再設定
ld hl, PARM40 ; CRTCをWIDTH40で初期化
; 8255を初期化 (インライン展開済み)
; 7バイト
INIT_8255:
ld bc, IO8255L
ld a, 82h ; ポートBのみ入力
out (c), a
INIT_8255_END:
; CRTCを初期化 (インライン展開済み)
; パラメータ
; hl : 初期化パラメータの先頭アドレス
; レジスタ破壊 af bc hl
; 22バイト
INIT_CRTC:
ld a, 13 ; CRTCレジスタ番号
INIT_CRTC_1:
ld bc, IOCRTC
out (c), a
inc c
inc b
outi ; outiの仕様に注意
dec a
jp p, INIT_CRTC_1
ld bc, IO8255C + 100h
outi
INIT_CRTC_END:
call CLR_PALET
; メインループ
; 38バイト
IPL_LOOP:
call CLR_VRAM_ALL
ld a, 2 ; 赤
ld (TXTATR), a
ld de, MSG_WELCOME
call IPLPRN_XY
ld a, 7 ; 白
ld (TXTATR), a
ld de, MSG_WAITING
call IPLPRN_XY
call PRT_DRV
call IS_DRV_RDY ; IPLDRV(初回はFDD 0)の挿入チェック
jr nc, IPL_LOAD ; 挿入されていれば起動
IPL_LOOP2:
call IPL_MENU ; メニュー表示と入力待ち
jr IPL_LOOP
IPL_LOOP_END:
; 読込みエラー等 (インライン展開済み)
; 5バイト
ERR_LOAD:
ld de, MSG_ERROR
jr ERR_MISSING_1
ERR_LOAD_END:
; NMIリセットがアドレス066hとなるよう,調整する
; ここに3バイトあき
nop
db 0, 0
; 読み込むべきファイルが見つからないエラー (インライン展開済み)
; 9バイト
ERR_MISSING:
ld de, MSG_MISSING
ERR_MISSING_1:
call IPLPRN_XY
call WAIT_MOMENT
; ループの戻りをNMIリセットと共用
; NMIリセットのエントリ(メニューに戻す)
ORG_0066:
; org 0066h
RST_066H:
jr IPL_LOOP2
; ここに8バイトあき
nop
db 0, 0, 0, 0, 0, 0, 0
; パレットの初期化
; TXTCUR+2から3バイトが0である前提
; レジスタ破壊 f b hl
; 12バイト
CLR_PALET:
ld hl, TXTCUR + 2
ld b, HIGH(IOPALET + 100h)
outi
outi
outi
ret
CLR_PALET_END:
; ドライブ番号の表示
; パラメータ
; (0ff80h) TXTCUR カーソルxy
; (0ff86h) TXTATR アトリビュート
; (0ff87h) IPLDRV ドライブ指定(0~3)
; 戻り値
; (0ff80h) TXTCUR カーソルxy
; レジスタ破壊 a
; FDD以外では表示がおかしくなる(しかしEMMとROMは一瞬なので気にしない)
; 8バイト
PRT_DRV:
ld a, (IPLDRV)
add a, 30h
jp IPLPTC ; 飛び先でリターン
PRT_DRV_END:
; 数秒待つ
; レジスタ破壊 af bc de
; 13バイト
WAIT_MOMENT:
ld b, 10
ld de, 0
WAIT_MOMENT_1:
dec de
ld a, d
or e
jr nz, WAIT_MOMENT_1
djnz WAIT_MOMENT_1
ret
WAIT_MOMENT_END:
; ファイルの読込みと実行
; 88バイト
IPL_LOAD:
; call CLR_VRAM_TOP ; 長いメッセージで上書きされるので省略
ld de, MSG_LOOKING
call IPLPRN_XY
call PRT_DRV
ld a, (IPLDRV)
cp 12h ; CMTの場合メッセージが異なる
jr nz, IPL_LOAD_0
ld de, MSG_LOOKCMT
call IPLPRN_XY
IPL_LOAD_0:
call LOAD1ST_COM ; 先頭セクタの読込み
jr nz, ERR_LOAD ; デバイスがおかしい?
call CHECK1ST ; 起動フラグの確認
jr nz, ERR_MISSING ; フラグ等がおかしい
; リダイレクタをRAMに書き込む
ld de, (FILEBUF+16h) ; 実行アドレス
call WRITE_REDIRECTOR
; ファイル名の表示
call CLR_VRAM_TOP
ld de, MSG_LOADING
call IPLPRN_XY
ld de, FILEBUF+1
call IPLPRN
ld a, (IPLDRV)
cp 12h ; CMTの場合別処理
jp z, IPL_CMT
; ファイル本体の読込み
ld bc, (FILEBUF+12h) ; プログラムサイズ(byte)
ld hl, (FILEBUF+14h) ; ロードアドレス
ld a, (FILEBUF+1dh) ; 開始アドレス下位バイト
ld de, (FILEBUF+1eh) ; 開始アドレス中・上位バイト(ほぼそのままセクタ)
call LOADFILE_COM
jp nz, ERR_LOAD ; デバイスがおかしい?
IPL_LOAD_1:
ld bc, IOIPLOF
jp REDIREC ; IPL終了
IPL_LOAD_END:
; メニュー表示と選択
; 戻り値
; (0ff87h) IPLDRV ドライブ指定(0~3,10h=EMM,11h=ROM,12h=CMT)
; レジスタ破壊 af af' bc de hl
; 39バイト=表示20バイト+入力19バイト
IPL_MENU:
call CLR_VRAM_TOP
ld hl, MSG_ADDR_MENU
ld a, (hl) ; メッセージの行数
inc hl
IPL_MENU_1:
ld e, (hl)
inc hl
ld d, (hl)
inc hl
ex af, af'
call IPLPRN_XY
ex af, af'
dec a
jr nz, IPL_MENU_1
INP_MENU:
call IPLKEY
cp '#' ; RAMから起動(謎機能)
jp z, EXEC_RAM
call SET_IPLDRV
ret nc ; 正常
cp 'm' ; モニタ
jp z, EXEC_MON
jr INP_MENU ; 無効文字
INP_MENU_END:
; ドライブ文字をIPLDRVに変換
; パラメータ
; a : ドライブ文字
; 戻り値
; (0ff87h) IPLDRV ドライブ指定(0~3,10h=EMM,11h=ROM,12h=CMT)
; キャリ : 無効文字
; a : 無効文字の場合に小文字化した元の文字
; レジスタ破壊 af bc
; 30バイト
SET_IPLDRV:
cp 34h ; FDD(0-3)
jr c, SET_IPLDRV_2
or 20h ; 全て小文字に統一
ld b, 40h ; IPLDRV = 10h
cp 'e' ; EMMから起動
jr z, SET_IPLDRV_1
inc b ; IPLDRV = 11h
cp 'r' ; BASIC ROM(CZ-8RB)
jr z, SET_IPLDRV_1
inc b ; IPLDRV = 12h
cp 'c' ; CMTから起動
scf
ret nz ; 無効文字
SET_IPLDRV_1:
ld a, b
SET_IPLDRV_2:
sub 30h
ret c ; 無効文字
ld (IPLDRV), a
ret
SET_IPLDRV_END:
; リダイレクタをRAMに書き込む
; ファイルを読み込む前に実行アドレスを書いておかないと
; CP/Mにバッファを潰される
; パラメータ
; de : 実行アドレス
; レジスタ破壊 f hl
; 16バイト
WRITE_REDIRECTOR:
ld hl, REDIREC
ld (hl), 0edh ; out (c), a
inc hl
ld (hl), 79h
inc hl
ld (hl), 0c3h ; jp xxxx
ld (EXECADR), de
ret
WRITE_REDIRECTOR_END:
; 先頭セクタのチェック
; パスワード領域を0にし,ファイル名の文字列を0終端にする
; 戻り値
; ゼロ : エラーでnz
; レジスタ破壊 af hl
; 10バイト
CHECK1ST:
ld hl, FILEBUF + 11h ; パスワード領域
ld (hl), 0 ; パスワード領域をつぶし,文字列の終端0にする
; どうせパスワードをサポートしないので問題なし
ld l, LOW(FILEBUF) ; 起動フラグ
ld a, (hl)
dec a
ret
CHECK1ST_END:
; ----------------------------------------------------------
; 各ドライブ共通ルーチン
; ----------------------------------------------------------
; ドライブの準備確認(FDD・EMM・ROM・CMT共通)
; パラメータ
; (0ff87h) IPLDRV ドライブ指定(0~3)
; ただし12hの場合,CMTをチェック
; その他4以上の場合無条件で準備完了(ノンキャリ)を返す
; 戻り値
; キャリ : 準備未完で1
; レジスタ破壊 af bc de
; 38バイト
IS_DRV_RDY:
ld a, (IPLDRV)
cp 12h
jp z, IS_CMT_READY ; CMTの場合
cp 4
jr nc, IS_DRV_RDY_2 ; EMM・ROMの場合(無条件でOK)
; ここからFDDの準備
or 80h
ld bc, IOFDCNO
out (c), a
ld c, LOW(IOFDCCR)
ld de, 0
IS_DRV_RDY_1:
in a, (c)
jp p, IS_DRV_RDY_2
dec de
ld a, d
or e
jr nz, IS_DRV_RDY_1
scf
ret
IS_DRV_RDY_2:
and a
ret
IS_DRV_RDY_END:
; 先頭セクタの読込み(FDD・EMM・ROM・CMT共通)
; パラメータ
; (0ff87h) IPLDRV ドライブに応じて処理を振り分け
; 戻り値
; ゼロ : エラーでnz
; レジスタ破壊 af bc de hl
; 15バイト
LOAD1ST_COM:
ld a, (IPLDRV)
cp 4
jp c, LOAD1ST ; FDDの場合
cp 12h
jp z, CMT_LOAD1ST ; CMTの場合
jr EMM_LOAD1ST ; EMM・ROM共通
LOAD1ST_END:
; ファイルの読込み(FDD・EMM・ROM共通)
; IPLDRVの内容に応じて飛び先を変える
; パラメータ
; (0ff87h) IPLDRV ドライブに応じて処理を振り分け
; bc : 読込みバイト数
; de+a : 開始オフセット
; (FDDとEMMの場合 de : レコード番号(トラック+サイド+セクタ))
; hl : 読込みバッファのアドレス
; レジスタ破壊 af bc de hl af'
; 25バイト
LOADFILE_COM:
ld ixh, a ; 未定義命令
ld a, (IPLDRV)
cp 11h ; ROM
jr c, LOADFILE_COM_1 ; FDDかEMM
ld a, ixh ; 未定義命令
jp ROM_LOADFILE ; ROM
LOADFILE_COM_1:
; FDDとEMMの場合
dec bc ; バイト数からセクタ数を計算(256で割っている)
inc b
cp 10h
ld a, b
jp z, EMM_LOADFILE ; EMM
jp LOADFILE
LOADFILE_COM_END:
; ----------------------------------------------------------
; EMM・BASIC ROM関連ルーチン
; ----------------------------------------------------------
; EMMまたはROMのIOアドレスをセットする
; パラメータ
; ゼロ : ROMの時にセット
; 戻り値
; bc : IOアドレス(IOEMM_L,IOROM_H)
; レジスタ破壊 af
; 7バイト
EMM_SETIO:
ld bc, IOEMM_L
ret nz ; 条件リターンは好きではないが
ld b, HIGH(IOROM_H)
ret
END_EMM_SETIO:
; EMMまたはROMから先頭32バイトを読みだす
; パラメータ
; ゼロ : ROMの場合セット
; 45バイト
EMM_LOAD1ST:
cp 11h ; ROMの場合
call EMM_SETIO
ld ix, EMM_LOAD1ST_2 ; EMMの場合の分岐アドレス
jr nz, EMM_LOAD1ST_1
ld ix, EMM_LOAD1ST_3 ; ROMの場合の分岐アドレス
EMM_LOAD1ST_1:
xor a
out (c), a ; 読出しアドレスに0をセット
inc c ; ROMは上位・中位・下位,EMMは下位・中位・上位
out (c), a
inc c
out (c), a
inc c
; bcは読出しアドレスになっている
ld hl, FILEBUF
EMM_LOAD1ST_2:
ini ; in tmp,(c) ; ld (hl),tmp ; dec b ; inc hl
inc b
inc a
cp 0x20
jr z, EMM_LOAD1ST_4
jp (ix) ; EMMとROMで分岐
EMM_LOAD1ST_3: ; ROMの場合のみ
dec c ; 読出しポートの前が下位アドレス
out (c), a
inc c
jr EMM_LOAD1ST_2
EMM_LOAD1ST_4:
ret
EMM_LOAD1ST_END:
; EMMファイルの読込み
; パラメータ
; a : セクタ数
; de : レコード番号(トラック+サイド+セクタ)
; hl : 読込みバッファのアドレス
; レジスタ破壊 af bc de hl af' ix
; 26バイト
EMM_LOADFILE:
ex af, af' ; セクタ数を退避
xor a
ld bc, IOEMM_L
out (c), a ; アドレス 下位
inc c
out (c), e ; アドレス 中位
inc c
out (c), d ; アドレス 上位
inc c ; bcは読出しアドレス
ex af, af' ; セクタ数を復帰
ld d, a
EMM_LOADFILE_1: ; 1セクタ256バイト読込み
ini ; in tmp,(c) ; ld (hl),tmp ; dec b ; inc hl
inc b
inc a
jr nz, EMM_LOADFILE_1
dec d ; 残りセクタ数の確認
jr nz, EMM_LOADFILE_1
ret
EMM_LOADFILE_END:
; ROMファイルの読込み
; パラメータ
; bc : 読込みバイト数
; de+a : 開始オフセット
; hl : 読込みバッファのアドレス
; レジスタ破壊 af bc de hl af' ix
; 48バイト
ROM_LOADFILE:
ex de, hl ; deがバッファアドレス,hlがアドレス上位中位
push bc ; バイト数を退避
ld bc, IOROM_H
out (c), h ; アドレス 上位
inc c
out (c), l ; アドレス 中位
inc c
out (c), a ; アドレス 下位
ex (sp), hl ; アドレス上位中位を保存し,バイト数を戻す
ex de, hl ; deが読込みバイト数,hlがバッファアドレス
ROM_LOADFILE_1:
inc c ; bcは読出しIOアドレス
ini ; in tmp,(c) ; ld (hl),tmp ; dec b ; inc hl
inc b
dec de ; 残りバイト数の確認
ex af, af'
ld a, d
or e
jr z, ROM_LOADFILE_2
ex af, af'
; ROMはオートインクリメントしてくれない
dec c ; 読出しポートの前が下位アドレス
inc a
out (c), a
jr nz, ROM_LOADFILE_1
; 下位アドレスがオーバーフロー
ex (sp), hl ; バッファアドレスを保存し,アドレスを戻す
inc hl
ld bc, IOROM_H
out (c), h ; アドレス 上位
inc c
out (c), l ; アドレス 中位
inc c
ex (sp), hl ; アドレスを保存し,バッファアドレスを戻す
jr ROM_LOADFILE_1
ROM_LOADFILE_2:
pop bc
ret
ROM_LOADFILE_END:
; ----------------------------------------------------------
; FDD関連ルーチン
; ----------------------------------------------------------
; ちょっと待つ
; 呼び出し元のcall命令含め 146clock = 36.5usec
; レジスタ破壊 af
; 6バイト
; call 17clock
WAIT1:
ld a, 7 ; 7clock
WAIT1_1:
dec a ; 4clock
jr nz, WAIT1_1 ; 12clock
ret ; 10clock
WAIT1_END:
; ここにあきなし
; ファイルの読込み(アドレス固定)
; パラメータ
; a : セクタ数
; de : レコード番号(トラック+サイド+セクタ)
; hl : 読込みバッファのアドレス
; レジスタ破壊 af bc de hl af'
; 76バイト
ORG_021A:
; org 021ah
LOADFILE:
or a ; キャリークリア
ex af, af' ; aレジスタ退避
ld a, e
; d←トラック番号+サイド
; d = HIGH(de << 4)
rlca
rl d
rlca
rl d
rlca
rl d
rlca
rl d
; e←セクタ番号(0オリジン)
ld a, e
and 0fh
ld e, a
LOADFILE_1:
; ドライブ番号とサイドを指定してモータON
ld a, 1
and d ; f←サイド
ld a, (IPLDRV)
jr z, LOADFILE_2 ; サイド0だった
or 10h ; サイド1だった
LOADFILE_2:
or 80h ; モータON
ld bc, IOFDCNO
out (c), a
; トラックシーク
ld a, d
srl a
call FDC_SEEK ; シーク
ret nz ; エラー
LOADFILE_3:
; 1セクタ読込み
push de
ld a,e
call FDC_READ
pop de
ret nz ; エラー
; セクタ数確認
ex af, af'
dec a
jr z, LOADFILE_4 ; 読込み完了
ex af, af'
; セクタ番号++
ld a, e
inc a
and 0fh
ld e, a
jr nz, LOADFILE_3 ; 次も同じトラック
; トラック番号++
ld a, d
inc a
ld d, a
jr LOADFILE_1
LOADFILE_4:
ld a, (IPLDRV) ; モータOFF
ld bc, IOFDCNO
out (c), a
ret
LOADFILE_END:
; FDCリストア
; レジスタ破壊 af bc
; 2バイト
FDC_RESTORE:
ld a, 2
; 次のルーチン(FDC_CMD)へ続く
; FDCのコマンドレジスタに命令を与え,完了を待つ
; パラメータ
; a : コマンド番号
; レジスタ破壊 af bc
; 5バイト
FDC_CMD:
ld bc, IOFDCCR
out (c), a
; 次のルーチン(WAIT_FDC_BUSY)へ続く
; FDCのBusy待ち
; bcレジスタがIOFDCCRでなければならない
; bレジスタが0fh(FDCのIOアドレスの上位)でなければならない
; レジスタ破壊 af bc
; 7バイト
WAIT_FDC_BUSY:
WAIT_FDC_BUSY_1:
in a, (c)
and 81h
jr nz, WAIT_FDC_BUSY_1
ret
WAIT_FDC_BUSY_END:
; FDCシーク
; パラメータ
; a : トラック番号
; レジスタ破壊 af bc
; ゼロ : エラーでnz
; 15バイト
FDC_SEEK:
ld bc, IOFDCDR
out (c), a
ld a, 1eh
call FDC_CMD
in a, (c)
and 99h
ret
FDC_SEEK_END:
; 先頭セクタの読込み
; 戻り値
; ゼロ : エラーでnz
; レジスタ破壊 af bc de hl
; 7バイト
LOAD1ST:
call FDC_RESTORE
ld hl, FILEBUF
xor a
; 次のルーチン(FDC_READ)へ続く
; 1セクタ読込み
; トラック移動は完了しているものとする
; パラメータ
; a : セクタ番号(0オリジン)
; hl : 読込みバッファのアドレス
; レジスタ破壊 af bc de hl
; 43バイト
FDC_READ:
ld bc, IOFDCSR ; セクタ番号のセット
inc a
out (c), a
ld c, LOW(IOFDCCR)
call WAIT_FDC_BUSY
ld d, LOW(IOFDCCR) ; FDCステータスレジスタ
ld e, LOW(IOFDCDR) ; FDCデータレジスタ
ld bc, IOFDCCR
ld a, 80h
out (c), a ; 読出し指示
call WAIT1
FDC_READ_1:
in a,(c) ; ステータス確認
rrca ; BUSY?
jr nc,FDC_READ_2
rrca ; DATA REQUEST?
jr nc,FDC_READ_1
ld c, e ; FDCデータレジスタ
in a, (c)
ld (hl), a
inc hl
ld c, d ; FDCステータスレジスタ
jr FDC_READ_1
FDC_READ_2:
rlca ; BACK STAT (RRCA <-> RLCA)
ret
FDC_READ_END:
; ----------------------------------------------------------
; テキスト関係ルーチン (1)
; ----------------------------------------------------------
; テキストVRAMクリア(全画面) (アドレス変えてもよい)
; レジスタ破壊 af bc hl
; 10バイト
CLR_VRAM_ALL:
ld hl, 0
ld (TXTCUR), hl
ld a, HIGH(TXTSIZ)
jr CLR_VRAM_TOP_1 ; 飛び先でリターン
CLR_VRAM_ALL_END:
; テキストVRAMクリア(上部12行+αだけ) (アドレス変えてもよい)
; レジスタ破壊 af bc hl
; 5バイト
CLR_VRAM_TOP:
ld a, 2
CLR_VRAM_TOP_1:
ld hl, TEXT_STD
;jr CLR_VRAM ; 次のルーチンなので省略
; 次のルーチン(CLR_VRAM)へ続く
; テキストVRAMクリア(レジスタ指定) (アドレス変えてもよい)
; パラメータ
; a : 埋めるバイト数 / 256
; h : 埋めるキャラクタコード(通常 20h)
; l : 埋めるアトリビュート(通常 7h)
; レジスタ破壊 af bc hl
; 22バイト
CLR_VRAM:
ld bc, IOTEXT
CLR_VRAM_1: ; テキストを256バイト分クリア
out (c), h
inc c
jr nz, CLR_VRAM_1
res BIT_ATTR_TEXT, b ; アトリビュートアドレスに変換
; 例えば 30aah → 20aah
CLR_VRAM_2: ; アトリビュートを256バイト分クリア
out (c), l
inc c
jr nz, CLR_VRAM_2
set BIT_ATTR_TEXT, b ; テキストアドレスに変換
inc b
dec a
jr nz, CLR_VRAM_1 ; 256*aバイト分のループ
ret
CLR_VRAM_END:
; 改行
; パラメータ
; (0ff80h) TXTCUR カーソルxy
; 戻り値
; (0ff80h) TXTCUR カーソルxy
; レジスタ破壊 f
;
; WIDTH40を仮定
; TXTCUR + (40 - X) = TXTCUR - (X - 40) を求めたい
;
; 39バイト
TXT_LTNL:
push hl
call TXT_ISLAST ; HLに(TXTCUR)が入る
jr c, TXT_LTNL_3
push de
push hl
; X座標を得る(40で割った余り)
ld de, 40
or a
TXT_LTNL_1: