
[INSTRSET "i486p"]

		org		0x7c00			; このプログラムがどこに読み込まれるのか

; 以下は標準的なfat12フォーマットフロッピーディスクのための記述

		jmp		entry
		db		0x90
		db		"chnos   "		; ブートセクタの名前を自由に書いてよい（8バイト）
		dw		512				; 1セクタの大きさ（512にしなければいけない）
		db		1				; クラスタの大きさ（1セクタにしなければいけない）
		dw		1				; fatがどこから始まるか（普通は1セクタ目からにする）
		db		2				; fatの個数（2にしなければいけない）
		dw		224				; ルートディレクトリ領域の大きさ（普通は224エントリにする）
		dw		2880			; このドライブの大きさ（2880セクタにしなければいけない）
		db		0xf0			; メディアのタイプ（0xf0にしなければいけない）
		dw		9				; fat領域の長さ（9セクタにしなければいけない）
		dw		18				; 1トラックにいくつのセクタがあるか（18にしなければいけない）
		dw		2				; ヘッドの数（2にしなければいけない）
		dd		0				; パーティションを使ってないのでここは必ず0
		dd		2880			; このドライブ大きさをもう一度書く
		db		0,0,0x29		; よくわからないけどこの値にしておくといいらしい
		dd		0xffffffff		; たぶんボリュームシリアル番号
		db		"chnosboot  "	; ディスクの名前（11バイト）
		db		"fat12   "		; フォーマットの名前（8バイト）
		resb	18				; とりあえず18バイトあけておく

; プログラム本体

entry:
		mov		ax,0			; レジスタ初期化
		mov		ss,ax
		mov		sp,0x7c00
		mov		ds,ax

; ディスクを読む

        mov     ax,0x0820
        mov     es,ax
        mov     ch,0            ; シリンダ0
        mov     dh,0            ; ヘッド0
        mov     cl,2            ; セクタ2
        mov     bx,18*2-1       ; 読み込みたい合計セクタ数 (2006.12.23 バグ修正)
        call    readfast        ; 高速読み込み

        mov     bx,4312+0x8200+2
fatloop:
        add     bx,-2
        cmp     word [bx],0
        jz      fatloop
        mov     ax,bx
        add     ax,-0x8200-5+54+53
        mov     bl,54
        div     bl              ; al = ax / bl

        cmp     al,0
        jnz     fatskip1
        mov     al,1
fatskip1:
        cmp     al,33
        jbe     fatskip2
        mov     al,33
fatskip2:
        mov     [0x0ff0],al     ; iplがどこまで読んだのかをメモ
        add     al,-1
        jz      fatskip3
        mov     ah,0
        imul    bx,ax,18*2

        mov     ax,0x0c80
        mov     es,ax
        mov     ch,1            ; シリンダ1
        mov     dh,0            ; ヘッド0
        mov     cl,1            ; セクタ1
        call    readfast        ; 高速読み込み
fatskip3:

; 読み終わったのでharibote.sysを実行だ！

        jmp     0xc200


error:
		mov		ax,0
		mov		es,ax
		mov		si,msg
putloop:
		mov		al,[si]
		add		si,1			; siに1を足す
		cmp		al,0
		je		fin
		mov		ah,0x0e			; 一文字表示ファンクション
		mov		bx,15			; カラーコード
		int		0x10			; ビデオbios呼び出し
		jmp		putloop
fin:
		hlt						; 何かあるまでcpuを停止させる
		jmp		fin				; 無限ループ
msg:
		db		0x0a, 0x0a		; 改行を2つ
		db		"load error"
		db		0x0a			; 改行
		db		0

readfast:	; alを使ってできるだけまとめて読み出す
;	es:読み込み番地, ch:シリンダ, dh:ヘッド, cl:セクタ, bx:読み込みセクタ数

		mov		ax,es			; < esからalの最大値を計算 >
		shl		ax,3			; axを32で割って、その結果をahに入れたことになる （shlは左シフト命令）
		and		ah,0x7f			; ahはahを128で割った余り（512*128=64k）
		mov		al,128			; al = 128 - ah; 一番近い64kb境界まで最大何セクタ入るか
		sub		al,ah

		mov		ah,bl			; < bxからalの最大値をahに計算 >
		cmp		bh,0			; if (bh != 0) { ah = 18; }
		je		.skip1
		mov		ah,18
.skip1:
		cmp		al,ah			; if (al > ah) { al = ah; }
		jbe		.skip2
		mov		al,ah
.skip2:

		mov		ah,19			; < clからalの最大値をahに計算 >
		sub		ah,cl			; ah = 19 - cl;
		cmp		al,ah			; if (al > ah) { al = ah; }
		jbe		.skip3
		mov		al,ah
.skip3:

		push	bx
		mov		si,0			; 失敗回数を数えるレジスタ
retry:
		mov		ah,0x02			; ah=0x02 : ディスク読み込み
		mov		bx,0
		mov		dl,0x00			; aドライブ
		push	es
		push	dx
		push	cx
		push	ax
		int		0x13			; ディスクbios呼び出し
		jnc		next			; エラーがおきなければnextへ
		add		si,1			; siに1を足す
		cmp		si,5			; siと5を比較
		jae		error			; si >= 5 だったらerrorへ
		mov		ah,0x00
		mov		dl,0x00			; aドライブ
		int		0x13			; ドライブのリセット
		pop		ax
		pop		cx
		pop		dx
		pop		es
		jmp		retry
next:
		pop		ax
		pop		cx
		pop		dx
		pop		bx				; esの内容をbxで受け取る
		shr		bx,5			; bxを16バイト単位から512バイト単位へ
		mov		ah,0
		add		bx,ax			; bx += al;
		shl		bx,5			; bxを512バイト単位から16バイト単位へ
		mov		es,bx			; これで es += al * 0x20; になる
		pop		bx
		sub		bx,ax
		jz		.ret
		add		cl,al			; clにalを足す
		cmp		cl,18			; clと18を比較
		jbe		readfast		; cl <= 18 だったらreadfastへ
		mov		cl,1
		add		dh,1
		cmp		dh,2
		jb		readfast		; dh < 2 だったらreadfastへ
		mov		dh,0
		add		ch,1
		jmp		readfast
.ret:
		ret

		resb	0x7dfe-$		; 0x7dfeまでを0x00で埋める命令

		db		0x55, 0xaa
