; Kernel of 4RM/CHAOS
; Public domain
; ------------------------------------------------------------------------
; This will start from MBR code, at 0060:0000 with interrupts off
ORG 0
; Fix stack pointer
XOR AX AX
MOV SS AX
MOV SP 7FFF
; Enable A20 line
CALL $A20WAIT
MOV AL AD
OUT 64
CALL $A20WAIT
MOV AL D0
OUT 64
CALL $A20WAIT2
MOV AL 60
PUSH AX
CALL $A20WAIT
MOV AL D1
OUT 64
CALL $A20WAIT
POP AX
OR AL 3
OUT 60
CALL $A20WAIT
MOV AL AE
OUT 64
CALL $A20WAIT
; Enter unreal mode
LGDT *+$GDTINFO
MOV AX CR0
OR AL 1
MOV CR0 AX
MOV BX 8
MOV DS BX
MOV ES BX
MOV FS BX
MOV GS BX
AND AL FE
MOV CR0 AX
XOR AX AX
MOV DS AX
MOV ES AX
MOV FS BX
; Begin kernel
; Store the disk number, at first
MOV *+$.DISK DL
; Set cursor
MOV AH 1
MOV CX F ; Full block cursor, lines 0 to 15
INT 10
; Start interrupts
STI
; Test code!
CALL $CLS
NAME $TESTCODE
CALL $KEY
MOV AH E
XOR BH BH
INT 10
JMP $TESTCODE
; Extra functions
NAME $A20WAIT
IN 64
TEST AL 2
JNZ $A20WAIT
RET
NAME $A20WAIT2
IN 64
TEST AL 1
JZ $A20WAIT2
RET
NAME $CLS
XOR BX BX
XOR DX DX
MOV AX 200
INT 10
OPS MOV CX @FA0
OPS MOV DI @B8000
MOV AX 720
ADS REP STOSW
RET
NAME $KEY ; ( -- AX=key )
OPS XOR AX AX
INT 16
OR AL 0
JZ $KEY.1
XOR AH AH
NAME $KEY.1
RET
; Forth functions for primitives
NAME $`(LIT)
ADS OPS LODSW
SUB BP 4
OPS MOV *BP+0 AX
ADS LODSW
= JMP AX
NAME $`0<>BRANCH
NAME $`0=BRANCH
ADS OPS LODSW
OPS MOV DX *BP+0
ADD BP 4
NAME $`BRANCH
ADS OPS LODSW
OPS MOV SI AX
ADS LODSW
JMP AX
NAME $`DOCOL
ADS OPS LODSW
MOV BX GS
SUB BX 4
MOV GS BX
MOV *BX SI
OPS MOV SI AX
ADS LODSW
JMP AX
NAME $`DOWORD ; ( machine-addr data-addr -- )
OPS MOV DX *BP+0
MOV AX *BP+4
ADD BP 8
JMP AX
NAME $`DROP
ADD BP 4
ADS LODSW
JMP AX
NAME $`EMIT
OPS MOV AX *BP+0
ADD BP 4
MOV AH E
XOR BH BH
INT 10
ADS LODSW
JMP AX
NAME $`KEY
CALL $KEY
SUB BP 4
OPS MOV *BP+0 AX
ADS LODSW
JMP AX
; Forth functions to decide what a word does
; @DX will be the pointer to the data
NAME $,CONST
TEST *+$.STATE FF
JZ $,CONSTIMM
MOV AX $`(LIT)
ADS STOSW
ADS OPS MOV AX *@DX
ADS OPS STOSW
ADS LODSW
JMP AX
NAME $,CONSTIMM
ADS OPS MOV AX *@DX
SUB BP 4
OPS MOV *BP+0 AX
ADS LODSW
JMP AX
NAME $,PRIM
TEST *+$.STATE FF
JZ $,PRIMIMM
ADS MOV AX *@DX
ADS STOSW
ADS LODSW
JMP AX
NAME $,PRIMIMM
ADS LODSW
JMP AX
NAME $,FORTH
TEST *+$.STATE FF
JZ $,FORTHIMM
MOV AX $`DOCOL
ADS STOSW
ADS OPS MOV AX *@DX
ADS OPS STOSW
ADS LODSW
JMP AX
NAME $,FORTHIMM
ADS OPS MOV AX *@DX
MOV BX GS
SUB BX 4
MOV GS BX
MOV *BX SI
OPS MOV SI AX
ADS LODSW
JMP AX
NAME $,DOES
RET
NAME $,DOESIMM
RET
; Data area
ORG 600
; GDT
NAME $GDTINFO
DW F ; Size of table - 1
= DDW %= 0
DB FF FF 0 0 0 92 CF 0
; Dictionary
; (Prev dict;Machine addr;String;Null terminator;Data)
ASMVAR 0 0
= DDW %0
DW $,CONST
"DISK"
DB 0
ASMVAR 0 %=
DDW $.DISK
; Variables
NAME $.DICTPTR
DDW %0
NAME $.STATE
DDW 0
NAME $.DISK
DDW FFFFFFFF
; @SI is forth instruction ptr
; BP is forth data stack ptr
; GS is forth return stack ptr
; @DI is forth here ptr