; 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