; CEPTIC Operating System for the TI-83 Plus/Silver Edition
; 
; By Michael Vincent (me@michaelv.org)
; Project started 08-22-2002.
;
;
 GLOBALS ON
 EXTERN ErasePage,WriteFlash
 INCLUDE "includes.inc"
 ;This is the 0000h start
	jp CEPTIC_Startup		;Handle OS stuff
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
LCD_Delay:
	;08h, this is a LCD delay routine
	push af
LCD_Delay_Loop:
	in a,(2)
	and 2
	jr z,LCD_Delay_Loop
	pop af
	ret
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	;20h, here is our HL -> (fileOP1) routine...takes 11 bytes from HL
	jp MovToFileOP1
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	;28h, here is where the TI-OS B_CALLs come to...must intercept if we ever
	;want an emulation layer
	jp TIOS_ROMCall_Executed
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	rst 00h
	;38h
	jp IM1_Routine
JumpTable:
	;This is the jump table for all the calls that CEPTIC provides
	;When writing documentation from this, don't forget the rst ones too.
	jp Clear_RAM_FAT			;Initializes RAM after a reset
	jp RAM_FAT_Checksum		;HL is a checksum of the RAM
	jp Flash_Erase				;Erases flash page A
	jp GrBufCpy					;Copies the graph buffer to the LCD
	jp ClearGraphBuffer		;Clears the graph buffer
	jp ClearLCDScreen			;Clears the LCD screen
	jp VPutMap					;Displays character A, returns C if doesn't fit (the character is in the C register too then)
	jp VPutStr					;Displays null-terminated string at HL
	jp Initialize_Calculator
	DW 0A55Ah
	jp GetCSC					;Fetches the last keypress
	jp DisplayCurrentFolder	;Displays the name of the current folder
	jp CharacterWidth			;Returns the width of a character
	jp Cursor_Clear			;Clears cursor
	jp Cursor_Show				;Shows cursor
	jp Flash_Write				;Writes BC bytes from HL to DE on page A
	jp Link_Receive			;Attempts to read a byte from the link port, returns in A
	jp Link_Send				;Sends a byte in A over the link port
	jp Create_File				;Creates (fileOP1) of size BC in folder A; outputs pointer to file in HL
MovToFileOP1:
	;Takes 11 bytes from HL and puts it into (fileOP1)
	ld de,fileOP1
	ld bc,11
	ldir
	ret
IM1_Routine:
	;This is the interrupt that is called ~150 times per second.
	;Here we shall scan for keys and other fun stuff.
	di
	ex af,af'
	exx
	;Check for on key
	in a,(4)
	bit 3,a
	jr nz,IM1_NoOn
	set onKey,(iy+keyFlags)
IM1_NoOn:
	;Let's scan for keys now, shall we?
	ld a,0FFh
	out (1),a
	or a		;pause
	xor a
	out (1),a
	or a		;pause
	in a,(1)
	cp 0FFh
	jr z,IM1_NoKeyPressed
	;We have a key press...it's only valid if it's different than (lastKey) when we are all
	;done
	ld a,0FFh
	out (1),a
	or a		;pause
	ld e,0FEh
IM1_CheckGroup:
	ld a,e
	out (1),a
	or a		;pause
	in a,(1)
	cp 0FFh
	jr z,IM1_CheckGroup_Nothing
	;A key is down!
	ld d,-1
IM1_CheckGroup_FindKey:
	inc d
	sra a
	jr c,IM1_CheckGroup_FindKey
	;D is now the key number...
	ld c,-1
IM1_CheckGroup_FindGroup:
	inc c
	sra e
	jr c,IM1_CheckGroup_FindGroup
	;C is the group number
	sla c
	sla c
	sla c
	sla c
	ld a,c
	or d
	;A is the new key code
	inc a			;so we can't have 0
	ld b,a
	ld a,(lastKey)
	cp b
	jr z,IM1_KeyPressOver
	ld a,b
	ld (lastKey),a
	ld (keyCode),a
	jr IM1_KeyPressOver
IM1_CheckGroup_Nothing:
	rlc e
	bit 7,e
	jr nz,IM1_CheckGroup
IM1_NoKeyPressed:
	xor a
	ld (lastKey),a
IM1_KeyPressOver:
	;Now cursor
	bit cursorEnabled,(iy+miscFlags)
	jr z,IM1_NoCursor
	ld a,(interruptCount)
	inc a
	ld (interruptCount),a
	cp 50
	jr c,IM1_NoCursor		;Don't change the cursor unless it's time to
	bit cursorOn,(iy+miscFlags)
	call nz,Cursor_Clear
	call z,Cursor_Show
	xor a
	ld (interruptCount),a
IM1_NoCursor:
	;End of interrupt routine
	ld a,8
	out (3),a
	ld a,9
	out (3),a
	ld a,0Fh
	out (3),a
	exx
	ex af,af'
	ei
	reti
TIOS_ROMCall_Executed:
	;Put code here to handle TI-OS romcalls
Initialize_Calculator:
	xor a
	ld (interruptCount),a
	ld sp,stackStart
	ld iy,flags				;flags!
	im 1
	ei
	;Now initialize hardware...first link port
	ld a,0C0h
	out (0),a
	;Now keyboard
	ld a,0FFh
	out (1),a
	;Status port
	ld a,0Bh
	out (3),a
	;Interrupts
	ld a,076h
	out (4),a
	;Set up 4000-7FFFh with the FAT page
	ld a,04h
	out (6),a
	;Set up the RAM page 8000-BFFFh
	ld a,81h
	out (7),a
	;Set up the RAM page C000-FFFFh
	xor a
	out (5),a
	;LCD screen
	;Turn on LCD
	ld a,03h
	out (10h),a
	;Set the 8-bit mode
	rst rLCD_Delay
	ld a,01h
	out (10h),a
	;Set the Z-address
	rst rLCD_Delay
	ld a,40h
	out (10h),a
	;Set the appropriate increment mode
	rst rLCD_Delay
	ld a,05h
	out (10h),a
	;Set our CPU speed
	ld a,1
	out (20h),a		;15 MHz
	;Now the timers
	out (30h),a
	out (33h),a
	out (36h),a
	;Control which flash pages can be executed from
	ld a,8		;allow 69h-08h...all others can already work
	out (23h),a
	;Initialization is complete...Now we check if the flash/RAM is valid or corrupted
	;We check the RAM checksum now
	call RAM_FAT_Checksum
	ld de,(RAMChecksum)
	or a
	sbc hl,de
	call nz,Clear_RAM_FAT
	;Set up contrast level
	ld a,(contrast)
	out (10h),a
	;Now we are ready to begin the interface
 INCLUDE "cli.asm"
 INCLUDE "font.asm"
 INCLUDE "display.asm"
Clear_RAM_FAT:
	;Clears the RAM FAT and initializes stuff
	ld a,0EBh	;default contrast
	ld (contrast),a
	ld hl,0
	ld (lastKey),a		;Sets both keycode addresses to 0
	ld hl,variableTable-17
	ld (varTableEnd),hl
	ld hl,RAM_Root_Entry+17
	ld de,variableTable
	ld bc,18
	lddr
	;We've now created the root directory entry, this is needed for all top-level files
	;and thus their children.
	ld a,1
	ld (folderRAMmax),a
	;Now we must initalize flags
	ld hl,flags
	ld (hl),0
	ld de,flags+1
	ld bc,19
	ldir
	set driveActive,(iy+memoryFlags)		;Set RAM as active
	ld a,1		;Set the root folder / as active
	ld (folderCurrentRAM),a
	ld a,82h
	ld (nextRAMpage),a
	ld hl,8000h
	ld (nextRAMoffset),hl
	ret
RAM_Root_Entry:
	DB "          /",00h,00h,00h,40h,0,1,10000000b
	;Backwards loading
RAM_FAT_Checksum:
	;Creates a checksum in HL of the RAM
	ld hl,8000h
	ld ix,0
	ld bc,7FFEh
	ld d,l	;load D=0
Initialization_RAM_Checksum:
	ld e,(hl)
	add ix,de
	inc hl
	dec bc
	ld a,b
	or c
	jr nz,Initialization_RAM_Checksum
	push ix
	pop hl
	ret
Banked_Call_Write:
	push af
	ld a,7Fh
	out (6),a
	pop af
	push hl
	push de
	push bc
	ld hl,4BE9h
	ld c,(hl)
	inc hl
	ld b,(hl)
	inc hl
	ld de,8100h
	ldir
	pop bc
	pop de
	pop hl
	call 8100h
	push af
	ld a,7Dh
	out (6),a
	pop af
	ret
Banked_Call_1F:
	push af
	ld a,7Fh
	out (6),a
	ld c,(hl)
	inc hl
	ld b,(hl)
	inc hl
	ld de,8000h
	ldir
	pop af
	ld hl,Banked_Call_1F_Return
	push hl
	ld hl,4000h
	jp 8000h
Banked_Call_1F_Return:
	push af
	ld a,7Dh
	out (6),a
	pop af
	ret
GetCSC:
	;This works with the interrupt routine
	ld a,(keyCode)
	ld b,a
	xor a
	ld (keyCode),a
	ld a,b
	ret
DisplayCurrentFolder:
	;Displays the name of the current folder
	bit driveActive,(iy+memoryFlags)
	ret z		;nothing to display for flash
	;RAM FAT
	ld hl,variableTable-1
	ld a,(folderCurrentRAM)
Disp_Folder_RAM_Loop:
	cp (hl)
	jr z,Disp_Folder_RAM_Match
	ld de,-18
	add hl,de
	jr Disp_Folder_RAM_Loop
Disp_Folder_RAM_Match:
	ld de,-6
	add hl,de
	ld b,8
Disp_Folder_RAM_Display:
	ld a,(hl)
	cp 20h
	ret z
	push bc
	push hl
	call VPutMap
	pop hl
	dec hl
	pop bc
	djnz Disp_Folder_RAM_Display
	;Now for the extension
	ld a,(hl)
	cp 20h
	ret z
	ld a,'.'
	push hl
	call VPutMap
	pop hl
	ld b,3
Disp_Folder_RAM_Display_Extension:
	ld a,(hl)
	cp 20h
	ret z
	push bc
	push hl
	call VPutMap
	pop hl
	dec hl
	pop bc
	djnz Disp_Folder_RAM_Display_Extension
	ret
Cursor_Clear:
	ld a,(cursorX)
	push af
	ld a,1Fh
	call VPutMap_CursorIsOff
	pop af
	ld (cursorX),a
	res cursorOn,(iy+miscFlags)
	call GrBufCpy
	xor a
	ld (interruptCount),a
	or 1
	ret
Cursor_Show:
	;Display the cursor
	ld a,(cursorX)
	push af
	ld a,7Fh
	bit alphaOn,(iy+keyFlags)
	jr z,Cursor_Show_NoAlpha
	ld a,1Eh
Cursor_Show_NoAlpha:
	call VPutMap_CursorIsOff
	pop af
	ld (cursorX),a
	set cursorOn,(iy+miscFlags)
	jp GrBufCpy
Link_Receive:
	;Routine to get a byte from the link port and store it in A
	;Returns Z if failed, NZ if success
	in a,(9)		;link assist status port
	and 00011000b		;mask out all but the two buffer bits
	ret z			;If zero then there's no byte! Perhaps an error?
	in a,(0Ah)		;link assist input port
	ret			;Return byte in A
Link_Send:
	;Sends the byte in A over the link port
	ld c,a
	in a,(9)
	xor a
	out (8),a
	ld a,c
	out (0Dh),a
	ret
Flash_Erase:
	;Erases a page of flash, given in A
	cp 07Eh
	ret z
	ld b,a
	ld a,7Dh
	out (6),a
	ld a,b
	jp ErasePage
Flash_Write:
	cp 07Eh
	ret z
	res flashWrite,(iy+stupidFlags)
	push af
	ld a,7Dh
	out (6),a
	pop af
	jp WriteFlash
 INCLUDE "files.asm"
CEPTIC_Startup:
	ld a,3
	out (03h),a
	ld a,7Fh
	out (6),a
	ld a,77h
	out (4),a
	jp 80D5h

