/*
 * Debugging boot sector.  Reads the first directory
 * sector from disk and displays it.
 *
 * It relies on the _volid field in the FAT header containing
 * the LBA of the root directory.
 */
#include "x16.h"

#define DIROFF		0x00200		/* where to read the root directory (offset) */
#define LOADSEG		(0x10000/16)	/* where to load code (64KB) */
#define LOADOFF		0

/*
 * FAT directory entry.
 */
#define Dname		0x00
#define Dext		0x08
#define Dattr		0x0B
#define Dtime		0x16
#define Ddate		0x18
#define Dstart		0x1A
#define Dlengthlo	0x1C
#define Dlengthhi	0x1E

#define Dirsz		0x20

/*
 * We keep data on the stack, indexed by rBP.
 */
#define Xdrive		0x00		/* boot drive, passed by BIOS in rDL */
#define Xrootlo		0x02		/* offset of root directory */
#define Xroothi		0x04
#define Xrootsz		0x06		/* file data area */
#define Xtotal		0x08		/* sum of allocated data above */
#define Xdap		0x00		/* disc address packet */

TEXT _magic(SB), $0
	BYTE $0xEB; BYTE $0x3C;		/* jmp .+ 0x3C  (_start0x3E) */
	BYTE $0x90			/* nop */
TEXT _version(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _sectsize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _clustsize(SB), $0
	BYTE $0x00
TEXT _nresrv(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _nfats(SB), $0
	BYTE $0x00
TEXT _rootsize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _volsize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _mediadesc(SB), $0
	BYTE $0x00
TEXT _fatsize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _trksize(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _nheads(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _nhiddenlo(SB), $0
	BYTE $0x00; BYTE $0x00
TEXT _nhiddenhi(SB), $0
	BYTE $0x00; BYTE $0x00;
TEXT _bigvolsize(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
TEXT _driveno(SB), $0
	BYTE $0x00
TEXT _reserved0(SB), $0
	BYTE $0x00
TEXT _bootsig(SB), $0
	BYTE $0x00
TEXT _volid(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
TEXT _label(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00
	BYTE $0x00; BYTE $0x00; BYTE $0x00
TEXT _type(SB), $0
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;
	BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00;

_start0x3E:
	CLI
	CLR(rAX)
	MTSR(rAX, rSS)			/* 0000 -> rSS */
	MTSR(rAX, rDS)			/* 0000 -> rDS, source segment */
	MTSR(rAX, rES)
	LWI(_magic-Xtotal(SB), rSP)
	MW(rSP, rBP)			/* set the indexed-data pointer */

	SBPB(rDL, Xdrive)		/* save the boot drive */

	STI

	LWI(confidence(SB), rSI)	/* for that warm, fuzzy feeling */
	CALL(BIOSputs(SB))

	LBI(0x41, rAH)			/* check extensions present */
	LWI(0x55AA, rBX)
	LXB(Xdrive, xBP, rDL)		/* drive */
	SYSCALL(0x13)			/* CF set on failure */
	JCS _jmp01
	CMPI(0xAA55, rBX)
	JNE _jmp01
	ANDI(0x0001, rCX)
	JEQ _jmp01

					/* rCX contains 0x0001 */
	SBPWI(0x0010, Xdap+0)		/* reserved + packet size */
	SBPW(rCX, Xdap+2)		/* reserved + # of blocks to transfer */

	DEC(rCX)
	SBPW(rCX, Xdap+12)
	SBPW(rCX, Xdap+14)

/* BIOSread will do this 	CALL(dreset(SB)) */

_jmp00:
	LW(_volid(SB), rAX)		/* Xrootlo */
	LW(_volid+2(SB), rDX)		/* Xroothi */

	LWI(_magic+DIROFF(SB), rBX)
	CALL(BIOSread(SB))		/* read the root directory */

	CALL(printnl(SB))
	LWI(_magic+DIROFF(SB), rBX)
	LWI((512/2), rCX)
	CALL(printbuf(SB))

xloop:
	JMP xloop


_jmp01:

TEXT buggery(SB), $0
	LWI(error(SB), rSI)
	CALL(BIOSputs(SB))

xbuggery:
	JMP xbuggery

/*
 * Read a sector from a disc. On entry:
 *   rDX:rAX	sector number
 *   rES:rBX	buffer address
 */
TEXT BIOSread(SB), $0
	LWI(5, rDI)			/* retry count (ATAPI ZIPs suck) */
_retry:
	PUSHA				/* may be trashed by SYSCALL */

	SBPW(rBX, Xdap+4)		/* transfer buffer :offset */
	MFSR(rES, rDI)			/* transfer buffer seg: */
	SBPW(rDI, Xdap+6)
	SBPW(rAX, Xdap+8)		/* LBA (64-bits) */
	SBPW(rDX, Xdap+10)

	MW(rBP, rSI)			/* disk address packet */
	LBI(0x42, rAH)			/* extended read */
	LBPB(Xdrive, rDL)		/* form drive */
	SYSCALL(0x13)			/* CF set on failure */
	JCC _BIOSreadret

	POPA
	DEC(rDI)			/* too many retries? */
	JEQ _ioerror

	CALL(dreset(SB))
	JMP _retry

_ioerror:
	LWI(ioerror(SB), rSI)
	CALL(BIOSputs(SB))
	JMP xbuggery

_BIOSreadret:
	POPA
	RET

TEXT dreset(SB), $0
	PUSHA
	CLR(rAX)			/* rAH == 0 == reset disc system */
	LBPB(Xdrive, rDL)
	SYSCALL(0x13)
	ORB(rAH, rAH)			/* status (0 == success) */
	POPA
	JNE _ioerror
	RET


TEXT printsharp(SB), $0
	LWI(sharp(SB), rSI)
_doprint:
	CALL(BIOSputs(SB))
	RET

TEXT printspace(SB), $0
	LWI(space(SB), rSI)
	JMP _doprint

TEXT printnl(SB), $0
	LWI(nl(SB), rSI)
	JMP _doprint

/*
 * Output a string to the display.
 * String argument is in rSI.
 */
TEXT BIOSputs(SB), $0
	PUSHA
	CLR(rBX)
_BIOSputs:
	LODSB
	ORB(rAL, rAL)
	JEQ _BIOSputsret

	LBI(0x0E, rAH)
	SYSCALL(0x10)
	JMP _BIOSputs

_BIOSputsret:
	POPA
	RET

/*
 * Output a register to the display.
 */
TEXT printAX(SB), $0
	PUSHW(rAX)
	PUSHW(rBX)
	PUSHW(rCX)
	PUSHW(rDI)

	LWI(4, rCX)
	LWI(numbuf+4(SB), rSI)

_nextchar:
	DEC(rSI)
	MW(rAX, rBX)
	ANDI(0x000F, rBX)
	ADDI(0x30, rBX)	/* 0x30 = '0' */
	CMPI(0x39, rBX)	/* 0x39 = '9' */
	JLE _dowrite
	ADDI(0x07, rBX)	/* 0x07 = 'A'-(1+'9')*/

_dowrite:
	SXB(rBL, 0, xSI)
	SHRI(4, rAX)

	DEC(rCX)
	JNE _nextchar

	LWI(numbuf(SB), rSI)
	CALL(BIOSputs(SB))

	POPW(rDI)
	POPW(rCX)
	POPW(rBX)
	POPW(rAX)

	CALL(printspace(SB))
	RET

TEXT printDXAX(SB), $0
	PUSHW(rAX)
	MW(rDX, rAX)
	CALL(printAX(SB))
	POPW(rAX)
	CALL(printAX(SB))
	RET

TEXT printBX(SB), $0
	PUSHW(rAX)
	MW(rBX, rAX)
	CALL(printAX(SB))
	POPW(rAX)
	RET

/*
 * Output some number of words to the display
 * rDS:rDI - buffer
 * rCX: number of words
 */
TEXT printbuf(SB), $0
	PUSHW(rAX)
	PUSHW(rBX)
	PUSHW(rCX)

_nextword:
	LXW(0, xBX, rAX)
	CALL(printAX(SB))
	INC(rBX)
	INC(rBX)
	DEC(rCX)
	JNE _nextword

	POPW(rCX)
	POPW(rBX)
	POPW(rAX)
	RET

TEXT error(SB), $0
	BYTE $'E'; 

TEXT ioerror(SB), $0
	BYTE $'I'; 

TEXT nl(SB), $0
	BYTE $'\r';
	BYTE $'\n';
	BYTE $'\z';

TEXT numbuf(SB), $0
	BYTE $'X'; BYTE $'X'; BYTE $'X'; BYTE $'X';
	BYTE $'\z';

TEXT space(SB), $0
	BYTE $' ';
	BYTE $'\z';

TEXT sharp(SB), $0
	BYTE $'#'; BYTE $'\z';
