;-----------------------------------------------
; アセンブラ・プログラムのサンプル COM用
;
; 2005.05.12 "OS.3as" -> "aOS.asm"
;
; アセンブラを NASK → NASM に変更。
;
; >nasm ファイル.asm -fbin -o ファイル.com
; でCOMファイルができる。
;
; ラベルで先頭が .(ピリオド)は、局所ラベル
;
;-----------------------------------------------
;
BITS 16 ;16ビットコードを生成せよ。
org 100h ;ロードは100hから。
;//
;// NASMでは org100h としても リストファイルでは 0番地からの
;// 表示となってしまう。 不満あり。NASKではちゃんと100hからになる。
;//
section .text
start:
;ここにコードを書く。
JMP _skip ;下の「DW 6」をパスする。
DW 3072/512 ;=6 これは何?
;//
;// NASMでは 下へのジャンプが 3バイトになってしまう。
;// NASKでは、2バイトで済む。コードサイズではNASKの方が優秀。
;//
_skip:
mov AX,0013h ;AL=13h 320x200ドット モード
int 10h ;(★ AH=00:ビデオモードの切り替え)
;
mov AX,1010h ;AX=1010h:カラーパレット設定
xor BX,BX ;BX=0:黒のカラー番号(0--FFh)
xor DH,DH ; DH=赤 (00-3Fhまで有効)
xor CX,CX ; CH=緑 CL=青
int 10h ;(★ 黒の設定)
;
mov AX,1010h ;
mov BX,15 ;BX=15:白のカラー番号
mov DH,3Fh ; RGB すべて Full・・・白になる。
mov CX,3F3Fh ;
;
;; mov DH,00h ; これだと ・・・青になる。
;; mov CX,003Fh ;
;
int 10h ;(★ 白の設定)
;
CALL cls ;●画面消去
;
mov SI,_msg ;OS名(オープニング・メッセージ)
CALL putstr ;●文字列表示
;
push DS
xor AX,AX ; ;//
mov DS,AX ;DSをゼロクリア ;// INT 80h の割り込み
; ;// ベクタテーブルのセット。
mov WORD [ds:0x0200],_syscall ;// _syscallへ飛ぶように
mov [ds:0202h],CS ;// セグメント:オフセットをセットする。
pop DS
;
CALL loadDir ;● ディレクトリ情報を取得。
;
;//---------------------------------------
;// ここから、コマンド入力。(メインループ)
;//---------------------------------------
;
_command:
xor AX,AX ;AX <- 0
mov BX,_cmdlin ;// コマンドラインバッファを
mov CX,40/2 ;// 40文字ゼロクリア
.@Lcmd:
mov [ds:BX],AX ;//
add BX,2 ;//
dec CX ;//
jne .@Lcmd
;
mov SI,_prompt ;コマンド待ち(>プロンプト)文字
CALL putstr ;●文字列表示
mov SI,_cursor ;カーソル文字(_)
CALL putstr ;●文字列表示
;
.@Lkeyin:
mov AH,00h ;キーが押されるまで待つ。
int 16h ;(★ キーボード入力)
; ;文字コード->AL, 走査コード->AH
xor BX,BX
mov BL,BYTE [_curx] ;X座標 -> BL
cmp AL,20h ;キーコード:スペースより小さい
jb .@Pcmd1 ; -> コントロールコード処理へ
cmp AL,7eH ;7Eh以上(アスキー文字でない)
jae .@Pcmd1 ; -> 同上。
;
;// AL=アスキー文字だった場合。
cmp BL,39 ;カーソルのX座標が、39文字
jae .@Pcmd1 ; 以上(横いっぱいだった)-> 表示しない。
;
mov SI,_char_cur ;入力文字コード
mov [ds:SI+1],AL ; 記憶
mov BYTE [BX-2+_cmdlin],AL ;文字列として記憶。
CALL putstr ;キー入力のエコー表示
JMP .@Lkeyin ;--> キー入力待ちループ。
;
.@Pcmd1: ;// コントロールコード処理
cmp AL,08H ;08h=BS(Back Space)
jne .@Pcmd2 ;--> バックスペースでない。
;
;// タブキーが押された
cmp BL,3 ;X座標が 3未満
jb .@Pcmd2 ;-->
;
mov BYTE [BX-3+_cmdlin],0 ;コマンド記憶を1文字削除
;
mov SI,_backspace ;一つ文字を消して戻す。
CALL putstr ;●
JMP .@Lkeyin ;--> キー入力待ちループ。
;--------------------------------
;
.@Pcmd2:
cmp AL,0Dh ;0Dh=Enter
je .@Pcr ;--> エンターキーが押された。
JMP .@Lkeyin ;---> キー入力待ちループへもどる。
;
.@Pcr: ;// エンターが押されたので、コマンド判断へ。
mov SI,_delcur_lf ;まずは、カーソルを消して、
CALL putstr ; 改行。
;
mov BX,_cmdlin ;コマンド・ラインから
mov AX,[ds:BX+0] ; 入力された文字を取り出し。
mov CX,[ds:BX+2] ; -> Max 6文字
mov DX,[ds:BX+4] ;
;
test AX,AX ;Enterのみ(コマンド無し)
je _command ;---> 戻る。
;
cmp AX,6c63H ;// ① 入力文字は "CLS" か?
jne .@Next1 ;// 63h=C , 6Ch=L
cmp CX,0073H ;// 73h=S
jne .@Next1 ;--> 次のコマンドチェックへ。
;
;// CLSコマンド処理
CALL cls ;画面を消す。
JMP _command
;
.@Next1:
cmp AX,6572h ;// ② 入力文字は "RESET" か?
jne .@Next2
cmp CX,6573h
jne .@Next2
cmp DX,0074h
jne .@Next2
;
int 19h ;(★ これでリセットがかかる)
JMP _command
;
.@Next2:
cmp AX,4142h ;// ③ 入力文字は "BASIC" か?
jne .@Next3 ; 42h='B' 41h='A'
cmp CX,4953h ; 53h='S' 49h='I'
jne .@Next3 ; 43h='C'
cmp DX,0043h
jne .@Next3
;
int 18h ;(★ ROM-BASIC起動??) これでリセットがかかる
JMP _command
.@Next3:
cmp AX,6964h ;// ④ 入力文字は "dir" か?
jne .@Next4 ; 64h='d' 69h='i'
cmp CX,0072h ; 72h='r'
jne .@Next4
;
;-----------------------
;● dir処理
;-----------------------
push ES
mov AX,CS ;// CS+1000hを
add AX,1000h ;// -> ES にセット。
mov ES,AX ;// 〜512バイトx14=1C00h ディレクトリ情報
;
xor DI,DI ;ポインタ0クリア
.@Ldir:
mov AX,[es:DI] ;1文字づつ読み込み。(ファイル名)
test AL,AL ; 文字コード=ゼロなら、
je .@Qdir ; ディレクトリ表示 終了。
;
cmp AL,0E5H ;= データがかかれていない部分が見つかった。
je .@Pdir ; -> 次の ファイル・エントリの先頭へ。
TEST BYTE [ES:DI+11],18h ;11文字目=「ファイル属性」18h=通常のファイル?
jne .@Pdir ;-> 次の ファイル・エントリへ。
;
mov SI,_cmdlin
mov [ds:SI+0],AX ;// ファイル名8文字を
mov AX,[es:DI+2] ;// コマンドラインバッファへ
mov [ds:SI+2],AX ;// コピーする。
mov AX,[es:DI+4] ;//
mov [ds:SI+4],AX ;//
mov AX,[es:DI+6] ;//
mov [ds:SI+6],AX ;//
;
mov AL,20h ;// ファイル名と拡張子の間に1つ空白を入れ、
mov AH,[es:DI+8] ;//
mov [ds:SI+8],AX ;// さらに、拡張子3文字
mov AL,[es:DI+9] ;// コピーする。
mov AH,[es:DI+10] ;//
mov [ds:SI+10],AX ;//
mov WORD [ds:SI+12],000Ah ;改行を付け足す。
;
CALL putstr ;ファイル名+拡張子 表示。
;
.@Pdir:
add DI,32 ;ポインタを1ディレクトリ分進める。
JMP .@Ldir ;ファイルがなくなるまで繰り返す。
.@Qdir:
pop ES
JMP _command
; ^^^^^^^^^^^^^^^^^^^^^^^^ ここまで DIR処理。
;
;
.@Next4: ;// 外部コマンド "hello"等 入力文字のチェック。
;
mov CL,8 ;MAX 8文字までチェックする。
.@Ldir2:
mov AL,[ds:BX] ;1文字づつ 確認。
cmp AL,00h
jne .@Pdir2 ; コード=0なら
mov AL,20h ; → スペースに変更。
.@Pdir2:
cmp AL,61h ;小文字の"a"
jb .@Pdir3 ; 未満なら →
cmp AL,7Ah ;小文字の"z"
ja .@Pdir3 ; より大きければ →
; 小文字の"a"〜"z" だった。
sub AL,20h ; 大文字"A"〜"Z"に変換。
.@Pdir3:
mov [ds:BX],AL ;キー入力バッファ格納し直す。
inc BX ; ポインタup
dec CL ; 文字数Down
jne .@Ldir2 ; 8文字 繰り返す↑(8文字以下なら、残りは空白で埋める)
;
sub BX,8 ;ポインタを先頭に戻す。
;
push ES
mov AX,CS ;//
add AX,1000h ;// CS+1000h〜1C00h ディレクトリ情報
mov ES,AX ;// → ESにセット。
;
xor DI,DI ;ポインタゼロクリア
.@Bdir:
mov AX,[es:DI] ;Dirバッファの先頭から 文字比較。
test AL,AL ; もし、先頭がNULLなら、リスト終わり
je .@Qcmd ; → コマンド確認 終了。
TEST BYTE [es:DI+11],18h ;11文字目=「ファイル属性」18h=通常のファイル?
jne .@Pdir5 ;-> 次の ファイル・エントリへ。
;
cmp WORD [es:DI+8],4F48H ;// 拡張子が
jne .@Pdir5 ;// 48h='H' 4Fh='O',41h='A' か?
cmp BYTE [es:DI+10],41H ;// そうでなければ、
jne .@Pdir5 ;// -> 次の ファイル・エントリへ。
;
cmp AX,[ds:BX] ;// キー入力文字列と
jne .@Pdir5 ;// ファイル名(8文字)を
mov AX,[es:DI+2] ;// 比較し、1文字でも
cmp AX,[ds:BX+2] ;// 違っていれば、
jne .@Pdir5 ;// -> 次の ファイル・エントリへ。
mov AX,[es:DI+4] ;//
cmp AX,[ds:BX+4] ;//
jne .@Pdir5 ;//
mov AX,[es:DI+6] ;//
cmp AX,[ds:BX+6] ;//
jne .@Pdir5 ;//
;
mov AX,[es:DI+26] ;Dir情報 26バイト目=(次のクラスタ番号)
sub AX,2 ; 2引いて、
; ; クラスタ/セクタ数 を かける。
MUL WORD [_SIZ_CLU] ;// (AX x [mem] → DX:AX)
; ;これに、ユーザー・データのエントリ 先頭を加えると、
add AX,[_LBA_CLU2] ; 実際のデータが格納されている、クラスタ位置になる。
mov SI,AX ;SI=クラスタ番号
mov CL,1 ;CL=読み込むクラスタ数(手抜きで1クラスタ=512バイトまで)
mov AX,CS ;//
add AX,2000h ;// ユーザプログラムを読み込むバッファ位置
mov ES,AX ;// → ESに CS+2000h
;
mov BX,0100h ;COMファイルを想定し、オフセット 100h〜
CALL readSec ;○ 1セクタ読み取り。
jnc .@Pdir4 ; → エラーが無ければ、実行。
;
mov SI,_diskerr ;FD読み込みエラー
CALL putstr ;○ エラーメッセージ表示
JMP _command
.@Pdir4: ;--- 外部コマンド(ファイル)の実行。
mov AX,ES ;CS+1C00h〜1FFFh が 空いているので、
mov SS,AX ; ここをスタックエリアとして利用。
mov SP,0FFFEH ; オフセットは 安全をみて FFFEh。
mov DS,AX ;DSもCS,ESと同じ。
push AX
;@@ push 0100h
mov AX,0100h ;実行アドレスを、
push AX ; スタックにセット。
RETF ;POPで 強制実行。
;
.@Pdir5:
add DI,32 ; 1リストは、32バイト。
JMP .@Bdir ;次のファイルリストへ。
.@Qcmd:
pop ES
mov SI,_badcmd
CALL putstr
JMP _command
;
;
;-------------------------------
; データ エリア
;-------------------------------
_msg: ;オープニング・メッセージ
DB 'heboOS dayoon!',10
_lf: DB 10,0
_prompt: DB '>',0 ;コマンド待ち文字
_char_cur: DB 8,0 ;1文字戻す(BS)文字コード
_cursor: DB '_',0 ;カーソル文字
_backspace: ;BS(バックスペース)
DB 8,20h,8,8 ; 左へ1つ戻し、スペースで文字を消し、
DB '_',0 ; プロンプト表示。
;
_delcur_lf: ; 左へ1つ戻しカーソルを消した後、
DB 8,20h,10,0 ; 改行。
_badcmd: DB 'Bad command or file name',10,0
_diskerr: DB 'Disk error',10,0
ALIGNB 2, db 0
_cmdlin:
;?? DB 40 dup (?)
; resb 40 ;コマンド文字のバッファ(40文字)
times 40 db 0
;;main endp
;^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
;-------------------------------
;● 画面の消去
cls:
push DS
;
mov AX,0A000h ;ビデオRAMの先頭アドレス
mov DS,AX ; -> DSセグメントへ
xor BX,BX
xor AX,AX
.@Lcls:
mov [ds:BX],AX ;全領域にゼロを書き込む。
add BX,2 ;ワード単位で
jne .@Lcls ; BXがゼロになるまで、繰り返し。
;
pop DS
;
mov [_curx],AX ;カーソル位置XYともゼロクリア
;
RET
;;cls endp
;-------------------------------
;● 文字列表示。
; in: SI ... 文字列
;
putstr: ; proc near
push ES
push DI
push SI
push BX
push CX
push AX
;
mov AX,0A000h ;V-RAMの先頭アドレス
mov ES,AX ; -> ESセグメントへ
.@Bstr:
xor BX,BX
mov BL,[ds:SI] ;1文字取り出し、チェック。
inc SI ; ポインタを進める。
;
cmp BL,0Ah ;改行か?
je .@Pnew ; -> 改行処理へ
;
cmp BL,08h ;BSか?
jne .@Pbs
;// BS(バックスペース処理)
dec BYTE [CS:_curx]
JMP .@Bstr
.@Pbs:
shl BX,4 ;(文字コード)左へ <- 4ビットシフト[C1 E3 04]
je .@Qstr ;-> 表示 終了
add BX,-20h*16+charfont ;文字フォントデータの先頭計算。
xor AX,AX ;//
mov AL,[CS:_curx] ;// AX = カーソルX座標
shl AX,3 ;それを8倍する。
xor CX,CX ;//
;
mov CX,[CS:_cury] ;// DI = カーソルY座標
;
mov DI,CX ;//
shl DI,2 ;それを5倍する。
add DI,CX ;
shl DI,10 ;[C1 E7 0A]
add DI,AX ; DI = Y*5125+X*8
;
mov CH,16 ;フォントデータ数
.@Lstr1:
mov CL,8
mov AL,[CS:BX] ;フォントデータ取り出し-> AL
inc BX ; ポインタup
.@Lstr2:
add AL,AL ;// 2倍する
SBB AH,AH ;//??
and AH,0Fh
mov [es:DI],AH ;ビット書き込み。
inc DI
dec CL ;8回繰り返す。
jne .@Lstr2 ;
;
add DI,320-8
dec CH
jne .@Lstr1
;
mov AL,[CS:_curx]
inc AL
mov BYTE [CS:_curx],AL
cmp AL,40
jne .@Pstr1
;
.@Pnew:
mov BYTE [CS:_curx],0
;
mov AL,BYTE [CS:_cury]
inc AL
mov BYTE [CS:_cury],AL
;
cmp AL,12
jne .@Pstr1
;
CALL scroll
.@Pstr1:
JMP .@Bstr
.@Qstr:
pop AX
pop BX
pop CX
pop SI
pop DI
pop ES
RETN ;ret ??? 違いは??? コードは C3 で同じ。
;;putstr endp
ALIGNB 2, db 0 ;これは有効 00 が1個入る。
;-------------------------------
; データ エリア
;-------------------------------
_curx: DB 0 ;X側、カーソル座標
_cury: DB 0 ;Y側、カーソル座標
;-------------------------------
;● 画面表示をスクロールする。
scroll: ; proc near
;
push DS
mov AX,0A000h ;V-RAMの先頭アドレス
mov DS,AX ; -> DSセグメントへ
;
mov SI,320*16 ;画面の2行目の先頭?
xor DI,DI
.@Lscr:
mov AX,[ds:SI] ;2ドット分のデータを読み取り、
add SI,2 ;
mov [ds:DI],AX ; 2行上にコピー。
add DI,2 ;
;
cmp SI,320*200 ;画面の最後のドットまで、
jb .@Lscr ; コピーを繰り返す。
;
xor AX,AX ;ドット色データをゼロに。
.@Lscr2:
mov [ds:DI],AX ;最後の1行分を、
add DI,2 ; クリアする。
cmp DI,320*200 ; (画面の最後のドットまで
jb .@Lscr2 ; 繰り返す。)
;
pop DS
;
dec BYTE [CS:_cury] ;カーソルXの値を1減らす。
RET
;
;;scroll endp
;-------------------------------
;● FDのセクタ読み取り。
; in: SI ... FD読み取り位置(クラスタ番号?)
; ES:BX ... 読み取りデータ格納先
; CL ... 読み取りセクタ数
;
readSec: ; proc near
mov CH,3 ;リトライ回数
.@Lrsec:
push ES
push SI
push BX
push DX
push CX
push AX
;
mov AX,SI ;// SIのポインタを18で割り、
mov CL,18 ;// → CHに入れる。CLにはあまりを。
DIV CL ;// (AX ÷ CL → 答 AL あまりAH)
mov CH,AL ;//
mov CL,AH ;SIを18で割ったあまり+1 -> セクタ番号
;
mov DH,AL
shr CH,1 ;SIを18で割った答えをさらに÷2->トラック番号
and DH,01h ;SIを18で割った答えのビット0 ->ヘッド番号
inc CL
; ;ES:BX= 読み取り先バッファアドレス。
; ;DH=0,1 ヘッドNo.
; ;CH=トラック番号, CL=セクタ番号
mov AX,0201h ;AH=2 セクタ読み取り AL=セクタ数
xor DL,DL ;DL=ドライブNo. 0=A:
int 13h ;(★ FDのセクタ読み取り)
; ; →AL=実際に読まれたセクタ数。
; ; →AH=FDの状態。
pop AX
pop CX
pop DX
pop BX
pop SI
pop ES
jnc .@Prsec ;NCなら読み取りエラー無し。
;
dec CH ;3回リトライでもエラーなら
je .@Qrsec ; エラー終了。
;
push ES ;↓以下、エラーリトライ
push SI
push BX
push DX
push CX
push AX
;
mov AH,11h ;AH=2 ヘッドの位置合わせ
xor DL,DL ;DL=ドライブ番号 0=A:
int 13h ;(★ ヘッドの位置合わせ)
;
pop AX
pop CX
pop DX
pop BX
pop SI
pop ES
JMP .@Lrsec ;↑もう一回やり直し。
;
.@Prsec:
add BX,512 ;データ格納先を 512バイト 進める。
inc SI ;読み取りクラスタ番号を1つ進める。
clc
dec CL ;読み取り回数(セクタ数)を1つ減らす。
jne .@Lrsec
.@Qrsec:
RET
;;readSec endp
;+----------------------------------------------------------+
;| 解説: FDのファイルシステムについて。 |
;| |
;|ファイルシステム名称: FAT12 |
;|1セクタあたり、512バイト、1クラスタ=1セクタ |
;| |
;| FDの先頭から1クラスタを使って、MBR(ブートプログラム) |
;| 次に FAT領域 9クラスタ分 No. 1〜 |
;| さらにFAT2領域 9クラスタ分 No. 10〜 |
;| その次にディレクトリ領域 14クラスタ分 No. 33〜 |
;| これ以降がユーザが自由にファイルを格納できる領域 |
;| |
;|ディレクトリ領域: |
;| 1区画は32バイト、ファイル名8文字、拡張子名3文字、属性1バイト |
;| |
;+----------------------------------------------------------+
;-------------------------------
;● ディレクトリ情報を取得。
;
; out: (CS+2000h) ... 〜512バイト BPB(BIOSパラメータ情報)
; (CS+1000h) ... 〜512バイトx14=1C00h ディレクトリ情報
;
loadDir: ; proc near
push ES
mov AX,CS ;//
add AX,1000h ;// CS+2000hを
mov ES,AX ;// → ESにセット。
mov BYTE [es:0],00h ;先頭をゼロクリア
mov AX,CS ;//
add AX,2000h ;// CS+2000hを
mov ES,AX ;// → ESにセット。
;
xor BX,BX ;読み込み先をオフセット=0に。
xor SI,SI ;読み込みクラスタ番号を0
mov CL,1 ; 1セクタだけ読む。
CALL readSec ;そこへ1セクタ分 FDから読み込み。
jc .@Err ; → 読み取りエラーなら終了。
;
mov AL,[es:000Dh] ;+13バイト目が、
mov [_SIZ_CLU],AL ; 1クラスタのセクタ数? 1セクタ=1クラスタ
mov AX,[es:000Eh] ;FATの入っているクラスタ番号先頭 (=0001)
mov [_LBA_FAT],AX ; ->LBA_FATへセット。
mov CX,[es:0016h] ;1つのFAT領域の大きさ。(=9)
add AX,CX ; これを加えると、
mov [_LBA_FAT2],AX ; -> FAT2 の先頭、LBA_FAT2へセット
add AX,CX ; さらに加えると、
mov [_LBA_DIR],AX ;ルート・ディレクトリ・エントリの先頭クラスタ番号
;
mov CX,[es:0011h] ;ルート・ディレクトリ・エントリのサイズ
mov [_SIZ_DIR],CX ; クラスタ数で 00E0h=224個分。
shl CX,5 ;CXを32倍 -> 1C00h
add CX,511 ; + (512-1) 512はセクタサイズ -> 1DFFh
shr CX,9 ;÷1024 -> 7
;
add AX,CX
mov [_LBA_CLU2],AX ;ユーザー・データのエントリ 先頭クラスタ番号
;
mov AX,CS ;//
add AX,1000h ;// CS+1000hを
mov ES,AX ;// → ESにセット。
;
xor BX,BX ;読み込みデータ格納先オフセット
mov SI,[_LBA_DIR] ;ルート・ディレクトリ・エントリの先頭クラスタ番号
; CLは??
CALL readSec ;ディレクトリの内容よ読み込む。
mov BX,[_SIZ_DIR] ;// 1ディレクトリは32バイト
dec BX ;//
shl BX,5 ;// BXを32倍
;
mov BYTE [es:BX],00h ;そこをゼロクリア
.@Err:
pop ES
RET
;
ALIGNB 2, db 0
_LBA_FAT: DW 1 ;1つ目のFATの先頭クラスタ番号
_LBA_FAT2: DW 10 ;2つ目のFATの先頭クラスタ番号
_LBA_DIR: DW 19 ;ディレクトリ・エントリの先頭クラスタ番号
_LBA_CLU2: DW 33 ;ユーザーデータ・エントリの先頭クラスタ番号
_SIZ_DIR: DW 00E0h ;ディレクトリの情報に使っている クラスタ数。
_SIZ_CLU: DW 1 ;1クラスタのセクタ数
;
;;loadDir endp
;-------------------------------
;● システムコール。
;解説:
; ユーザープログラムから int 80h で呼び出される
; システムコールの処理部分。AXに機能番号を入れて機能を指示。
; ただし、現時点では、
; AX=0: セグメントの初期化
; AX=1: 文字列の表示
; AX=2: 画面のクリア
; しか、機能実装されていない。
_syscall: ; proc
push DI
push SI
push BP
push BX
push DX
push CX
push AX
;
mov BP,SP
test AX,AX
jne .@Psys1
;
;// AX=0 の時の処理。【初期化?】
mov AX,CS
mov SS,AX
mov SP,0FFFEh
mov DS,AX
mov ES,AX
JMP _command
.@Psys1:
cmp AX,1
jne .@Psys2
;
;// AX=1 の時の処理。【文字列表示】
CALL putstr
JMP .@Psys3
;
.@Psys2:
cmp AX,2
jne .@Psys3
;
;// AX=2 の時の処理。【画面のクリア】
CALL cls
JMP .@Psys4
.@Psys3:
or BYTE [ss:BP+18],01h
JMP .@Qsys
.@Psys4:
and BYTE [ss:BP+18],0FEh
;
.@Qsys:
pop AX
pop CX
pop DX
pop BX
pop BP
pop SI
pop DI
IRET
;
;;_syscall endp
;-------------------------------
;● ここから下に 文字フォントデータをつなげる。
charfont:
;
;よって、データはこのファイルでは無し。
;
;// incbin "charfont.bin" ;←これで、直接リンクできる。
end ;プログラム終了。