;;; -*- TI-Asm -*- ;;; ;;; Mimas - Assembly language IDE for the TI-83 Plus ;;; ;;; Copyright (C) 2010 Benjamin Moody ;;; ;;; This program is free software: you can redistribute it and/or ;;; modify it under the terms of the GNU General Public License as ;;; published by the Free Software Foundation; either version 3 of the ;;; License, or (at your option) any later version. ;;; ;;; This program is distributed in the hope that it will be useful, ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ;;; General Public License for more details. ;;; ;;; You should have received a copy of the GNU General Public License ;;; along with this program. If not, see . ;; ArchiveProgram: ;; ;; Save the current program to archive. Throw an error if there is ;; insufficient archive space available. ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - OP1, OP3 ArchiveProgram: ;; if program is already archived, nothing to do ld a,(curProgStartPage) or a ret nz ld hl,curProgFileName call ArcUnarcVar ;; fall through ;; ReloadProgram: ;; ;; Reload the current program, updating the current-program pointers ;; and curProgHeader. ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - OP1 ;; - ramCode ReloadProgram: ld hl,curProgFileName rst rMOV9TOOP1 ;; fall through ;; LoadProgram: ;; ;; Load a new program. Set up the current-program pointers, and copy ;; the program's header into RAM. ;; ;; Input: ;; - OP1 = program name ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - OP1 ;; - ramCode LoadProgram: ld de,curProgFileName BCALL _MovFrOP1 call ChkFindSymVarDataStart jr c,LoadProgram_NotFound call Add_AHL_2 ; skip program size ld (curProgStartPtr),hl ld (curProgStartPage),a ;; Load program header ld de,curProgHeader ld bc,PROGHEADER_LENGTH push de call FlashToRAM ;; Calculate number of symbols ld hl,(curProgHeader + PROGHEADER_SYMBOL_END) ld de,(curProgHeader + PROGHEADER_SYMBOL_START) or a sbc hl,de ld a,3 BCALL _DivHLByA ld (curProgSymbolCount),hl ;; Check if program signature is valid pop de ld hl,sourceFileSignature ld b,5 call CompStrsN ret z WARNING "FIXME: would be good to check that program header is sane" ;;; SYMBOL_START <= SYMBOL_STRING_START <= IMPORT_START <= ;;; SECTION_TABLE_START <= SECTION_TABLE_END <= size of program LoadProgram_Invalid: ld hl,emsg_FileInvalid jr LoadProgram_Error LoadProgram_NotFound: ld hl,emsg_FileNotFound LoadProgram_Error: ld de,curProgFileName + 1 call ThrowGeneralError ;; UNREACHABLE ;; LoadFirstSection: ;; ;; Set up pointers and buffers for reading the first section of the ;; current input file. ;; ;; Output: ;; - Carry flag set if input file has no sections ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - ramCode LoadFirstSection: ld hl,(curProgHeader + PROGHEADER_SECTION_TABLE_START) jr LoadSectionAtOffset ;; LoadNextSection: ;; ;; Set up pointers and buffers for reading the next section of the ;; input file. ;; ;; Output: ;; - Carry flag set if no more sections to read ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - ramCode LoadNextSection: ld hl,(curSectionOffset) ld bc,SECTHEADER_LENGTH add hl,bc LoadSectionAtOffset: ld de,(curProgHeader + PROGHEADER_SECTION_TABLE_END) or a sbc hl,de ccf ret c add hl,de ld (curSectionOffset),hl ld de,curSectionHeader ld bc,SECTHEADER_LENGTH ;; fall through ;; CopyProgramData: ;; ;; Read data from the current input file. ;; ;; Input: ;; - HL = offset into program file ;; - DE = buffer to store data ;; - BC = number of bytes to copy ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - ramCode CopyProgramData: call ProgramOffsetToAddress jq_ FlashToRAM ;; GetProgramDataByte: ;; ;; Get a single byte from the current input file. ;; ;; Input: ;; - HL = program offset ;; ;; Output: ;; - A = byte ;; ;; Destroys: ;; - F ;; - ramCode GetProgramDataByte: push hl call ProgramOffsetToAddress call Load_A_AHL pop hl ret ;; GetProgramData: ;; ;; Get a chunk of data from the current input file. If the ;; program is in Flash, the data will be copied to OP1. ;; ;; Input: ;; - HL = offset into program file ;; - BC = number of bytes to copy ;; ;; Output: ;; - HL points to data ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - OP1-??? ;; - ramCode GetProgramData: call ProgramOffsetToAddress bit 7,h ret nz ld de,OP1 push de call FlashToRAM pop hl ret ;; GetProgramInstr: ;; ;; Get a bytecode instruction from the current input file. If the ;; program is in Flash, the string will be copied to instrBuf. ;; ;; Input: ;; - HL = program offset to instruction ;; ;; Output: ;; - HL points to instruction ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - instrBuf ;; - ramCode GetProgramInstr: call ProgramOffsetToAddress bit 7,h ret nz ld de,instrBuf push de call InstrToRAM pop hl ret ;; InstrToRAM: ;; ;; Copy a bytecode instruction to RAM. ;; ;; Input: ;; - AHL = paged address of instruction (4000h <= HL <= 7FFFh) ;; - DE = destination buffer ;; ;; Destroys: ;; - AF, BC, DE, HL ;; - ramCode InstrToRAM: RAM_CODE_BEGIN InstrToRAM_end out (6),a ld c,(hl) res 7,c res 6,c inc c inc c ld b,0 InstrToRAM_Loop: ldi ret po bit 7,h jr z,InstrToRAM_Loop ld h,40h inc a out (6),a jr InstrToRAM_Loop InstrToRAM_end: ;; GetProgramSymbolOffset: ;; ;; Get the offset to a given symbol in the current program file, and ;; check if that offset is valid. ;; ;; Input: ;; - HL = symbol number ;; ;; Output: ;; - DE = symbol number ;; - HL = offset to symbol in program file (if valid) ;; - Carry flag clear if symbol number is out of bounds ;; ;; Destroys: ;; - F GetProgramSymbolOffset: ex de,hl GetProgramSymbolOffsetDE: ld hl,(curProgSymbolCount) scf sbc hl,de ret c ld hl,(curProgHeader + PROGHEADER_SYMBOL_START) add hl,de add hl,de add hl,de ret ;; GetProgramSymbolInfo: ;; ;; Get information about a symbol in the current program file. ;; ;; Input: ;; - HL = symbol number ;; ;; Output: ;; - Carry flag set if symbol does not exist ;; - HL = offset to the symbol's name from the start of the program ;; ;; Destroys: ;; - AF, DE GetProgramSymbolInfo: call GetProgramSymbolOffset ret c call ProgramOffsetToAddress call Load_DE_AHL call Inc_AHL call Load_A_AHL cp 1 ret c ; ld a,d ; res 6,d res 7,d ld hl,(curProgHeader + PROGHEADER_SYMBOL_STRING_START) add hl,de ret ;; GetProgramSymbolPtrWrite: ;; ;; Get the address of the given symbol's info block. The current ;; program will be moved into RAM if necessary. ;; ;; Input: ;; - HL = symbol number ;; ;; Output: ;; - HL = address of symbol info (3 bytes: string offset L, string ;; offset H + flags, ref count) ;; ;; Destroys: ;; - AF GetProgramSymbolPtrWrite: push de call GetProgramSymbolOffset call c,Error_Bytecode ld a,(curProgStartPage) or a jr z,ProgramOffsetToAddress_1 push bc ld bc,0 call ProgramInsertDeleteMem ex de,hl pop bc pop de ret ;; ProgramOffsetToAddress: ;; ;; Get the absolute address of a given offset in the input file. ;; ;; Input: ;; - HL = offset into program file ;; ;; Output: ;; - AHL = absolute address ;; ;; Destroys: ;; - F ProgramOffsetToAddress: push de ProgramOffsetToAddress_1: ex de,hl ld hl,(curProgStartPtr) ld a,(curProgStartPage) call Add_AHL_DE pop de ret ;; InsDelProgramCodeMem: ;; ;; Insert or delete memory into the current program section. The ;; current program will be unarchived if necessary. ;; ;; Input: ;; - HL = offset into program file to location where memory should be ;; inserted, or to location of the first byte to be deleted (must be ;; between (curSectionHeader + SECTHEADER_DATA_START) and ;; (curSectionHeader + SECTHEADER_DATA_END), inclusive) ;; - BC = number of bytes to insert (negative number to delete) ;; ;; Output: ;; - DE = address of first byte inserted ;; - BC = number of bytes inserted ;; ;; Destroys: ;; - AF, HL InsDelProgramCodeMem: call ProgramInsertDeleteMem push de ;; Update global pointers call ProgramInsDelUpdateHeaderForCode ;; Update this section table entry ld hl,(curSectionHeader + SECTHEADER_DATA_END) add hl,bc ld (curSectionHeader + SECTHEADER_DATA_END),hl push bc ld hl,(curSectionOffset) call ProgramOffsetToAddress ex de,hl ld hl,curSectionHeader ld bc,SECTHEADER_LENGTH ldir pop bc ;; Update later section table entries ld hl,(curSectionOffset) call ProgramInsDelUpdateSTab pop de ret ;; InsDelProgramStringMem: ;; ;; Insert or delete memory into the current program's string area. ;; The current program will be unarchived if necessary. ;; ;; Input: ;; - HL = offset into program file to location where memory should be ;; inserted, or to location of the first byte to be deleted (must be ;; between (curProgHeader + PROGHEADER_SYMBOL_STRING_START) and ;; (curProgHeader + PROGHEADER_SYMBOL_STRING_END), inclusive) ;; - BC = number of bytes to insert (negative number to delete) ;; ;; Output: ;; - DE = address of first byte inserted ;; - BC = number of bytes inserted ;; ;; Destroys: ;; - AF, HL InsDelProgramStringMem: push hl call ProgramInsertDeleteMem pop hl push de push hl ;; Update global pointers call ProgramInsDelUpdateHeaderForStrings pop hl push bc ;; Update symbols (symbol string pointers are relative to the ;; start of string memory) ld de,(curProgHeader + PROGHEADER_SYMBOL_STRING_START) or a sbc hl,de ; HL = offset into string memory ld b,h ld c,l ;; get address of start of symbol table (this will throw an ;; error if the symbol table is empty - a program's symbol ;; table should never, in fact, be empty at the time this ;; function is called) ld hl,0 call GetProgramSymbolPtrWrite ex de,hl ld hl,(curProgSymbolCount) ;; DE = address of start of symbol table ;; HL = number of symbols left to check ;; BC = position where bytes were allocated ;; (SP) = number of bytes allocated InsDelProgramStringMem_SymbolLoop: inc de ; -> offset H inc de ; -> ref count ld a,(de) ; if symbol is free, do nothing or a jr z,InsDelProgramStringMem_SymbolSkip ;; if symbol's string ptr >= BC, then we need to adjust it dec de ; -> offset H dec de ; -> offset L ld a,(de) sub c inc de ; -> offset H ld a,(de) sbc a,b jr c,InsDelProgramStringMem_SymbolNoAdjust ex (sp),hl dec de ; -> offset L ld a,(de) add a,l ld (de),a inc de ; -> offset H ld a,(de) adc a,h ld (de),a ex (sp),hl InsDelProgramStringMem_SymbolNoAdjust: inc de ; -> ref count InsDelProgramStringMem_SymbolSkip: inc de ; -> next symbol offset L dec hl ld a,h or l jr nz,InsDelProgramStringMem_SymbolLoop pop bc pop de ret ;; AppendProgramSymbol: ;; ;; Allocate a fresh symbol table entry in the current program. The ;; current program will be unarchived if necessary. ;; ;; Output: ;; - DE = address of first byte inserted ;; - BC = 3 ;; ;; Destroys: ;; - AF, HL AppendProgramSymbol: ld hl,(curProgHeader + PROGHEADER_SYMBOL_END) ld bc,3 call ProgramInsertDeleteMem ;; Update global pointers jr ProgramInsDelUpdateHeaderForSyms ;; InsDelProgramImportMem: ;; ;; Insert or delete memory into the current program's imports area. ;; The current program will be unarchived if necessary. ;; ;; Input: ;; - HL = offset into program file to location where memory should be ;; inserted, or to location of the first byte to be deleted (must be ;; between (curProgHeader + PROGHEADER_IMPORT_START) and ;; (curProgHeader + PROGHEADER_IMPORT_END), inclusive) ;; - BC = number of bytes to insert (negative number to delete) (must ;; be a multiple of 9) ;; ;; Output: ;; - DE = address of first byte inserted ;; - BC = number of bytes inserted ;; ;; Destroys: ;; - AF, HL InsDelProgramImportMem: call ProgramInsertDeleteMem ;; Update global pointers jr ProgramInsDelUpdateHeaderForImports ;; InsDelProgramSectionMem: ;; ;; Insert or delete memory into the current program's section table ;; area. The current program will be unarchived if necessary. ;; ;; Note: (curSectionOffset) will not be updated to reflect the new ;; offset of the current section, and thus should be considered ;; destroyed. ;; ;; Input: ;; - HL = offset into program file to location where memory should be ;; inserted, or to location of the first byte to be deleted (must be ;; between (curProgHeader + PROGHEADER_SECTION_TABLE_START) and ;; (curProgHeader + PROGHEADER_SECTION_TABLE_END), inclusive) ;; - BC = number of bytes to insert (negative number to delete) (must ;; be a multiple of SECTHEADER_LENGTH) ;; ;; Output: ;; - DE = address of first byte inserted ;; - BC = number of bytes inserted ;; ;; Destroys: ;; - AF, HL ;; - (curSectionOffset) InsDelProgramSectionMem: call ProgramInsertDeleteMem ;; Update global pointers jr ProgramInsDelUpdateHeaderForLateSections ;; ProgramInsDelUpdateHeaderForCode: ;; ;; Update program header pointers after inserting program code memory. ;; Program is assumed to be in RAM. ;; ;; Input: ;; - BC = number of bytes inserted ;; ;; Destroys: ;; - F, HL ProgramInsDelUpdateHeaderForCode: ld hl,(curProgHeader + PROGHEADER_SYMBOL_START) add hl,bc ld (curProgHeader + PROGHEADER_SYMBOL_START),hl ProgramInsDelUpdateHeaderForSyms: ld hl,(curProgHeader + PROGHEADER_SYMBOL_STRING_START) add hl,bc ld (curProgHeader + PROGHEADER_SYMBOL_STRING_START),hl ProgramInsDelUpdateHeaderForStrings: ld hl,(curProgHeader + PROGHEADER_CONSTANT_START) add hl,bc ld (curProgHeader + PROGHEADER_CONSTANT_START),hl ld hl,(curProgHeader + PROGHEADER_IMPORT_START) add hl,bc ld (curProgHeader + PROGHEADER_IMPORT_START),hl ProgramInsDelUpdateHeaderForImports: ld hl,(curProgHeader + PROGHEADER_SECTION_TABLE_START) add hl,bc ld (curProgHeader + PROGHEADER_SECTION_TABLE_START),hl ProgramInsDelUpdateHeaderForEarlySections: ld hl,(curSectionOffset) add hl,bc ld (curSectionOffset),hl ProgramInsDelUpdateHeaderForLateSections: ld hl,(curProgHeader + PROGHEADER_SECTION_TABLE_END) add hl,bc ld (curProgHeader + PROGHEADER_SECTION_TABLE_END),hl ProgramModifyHeaderNoArc: push bc push de ld hl,curProgHeader ld de,(curProgStartPtr) ld bc,PROGHEADER_LENGTH ldir pop de pop bc ret ;; ProgramInsDelUpdateSTab: ;; ;; Update section table offsets after inserting program code memory. ;; ;; Input: ;; - HL = offset to section into which bytes were inserted ;; - BC = number of bytes inserted ;; ;; Destroys: ;; - AF, DE, HL ProgramInsDelUpdateSTab: ld de,SECTHEADER_LENGTH + SECTHEADER_DATA_START ProgramInsDelUpdateSTab_Loop: add hl,de ld de,(curProgHeader + PROGHEADER_SECTION_TABLE_END) or a sbc hl,de ret nc add hl,de push hl call ProgramOffsetToAddress ;; update section start ld a,(hl) add a,c ld (hl),a inc hl ld a,(hl) adc a,b ld (hl),a inc hl ;; update section end ld a,(hl) add a,c ld (hl),a inc hl ld a,(hl) adc a,b ld (hl),a pop hl ld de,SECTHEADER_LENGTH jr ProgramInsDelUpdateSTab_Loop ;; ProgramInsertDeleteMem: ;; ;; Insert or delete memory from the current program file. The current ;; program will be unarchived if necessary. This routine will throw ;; an error if there is not enough RAM available to perform the ;; operation. ;; ;; (If BC = 0, no memory is inserted or deleted, but the program is ;; still unarchived if necessary. BC = 0 is the only time when it is ;; appropriate to call this routine directly, rather than using one of ;; the InsDelProgram*Mem routines.) ;; ;; Input: ;; - HL = offset to first byte to insert/delete ;; - BC = amount to insert / negative amount to delete ;; ;; Output: ;; - DE = address of first inserted byte / address of first byte ;; following deleted mem ;; - If memory was inserted, it is uninitialized ;; ;; Destroys: ;; - AF, HL ProgramInsertDeleteMem_Archived: push hl push bc push ix rst rPUSHREALO1 ld hl,ProgramInsertDeleteMem_Error call APP_PUSH_ERRORH ld hl,curProgFileName rst rMOV9TOOP1 BCALL _ChkFindSym ;; if file doesn't exist, or is not currently archived, this ;; is really bad and we should probably abort immediately ccf sbc a,a and b call z,LoadProgram_Invalid ;; use UnarchiveVar rather than Arc_Unarc since the latter ;; destroys all of OP1 and OP3 BCALL _UnarchiveVar call APP_POP_ERRORH call ReloadProgram BCALL _PopRealO1 pop ix pop bc pop hl ProgramInsertDeleteMem: ld a,(curProgStartPage) or a jr nz,ProgramInsertDeleteMem_Archived ex de,hl ;; check that insertion offset is sane ld hl,(curProgStartPtr) dec hl dec hl ld a,(hl) sub e inc hl ld a,(hl) inc hl sbc a,d jr nc,ProgramInsertDeleteMem_ValidOffset ;; if we ever get here, it's a bug BCALL _ErrDimension ;; UNREACHABLE ProgramInsertDeleteMem_ValidOffset: add hl,de push bc ld a,b add a,a jr c,ProgramInsertDeleteMem_Delete or c jr z,ProgramInsertDeleteMem_DoneHL call DoInsertMem jr ProgramInsertDeleteMem_Done ProgramInsertDeleteMem_Delete: xor a sub c ld e,a sbc a,a sub b ld d,a push hl BCALL _DelMem pop hl ProgramInsertDeleteMem_DoneHL: ex de,hl ProgramInsertDeleteMem_Done: pop bc ;; update program size ld hl,(curProgStartPtr) dec hl dec hl ld a,(hl) add a,c ld (hl),a inc hl ld a,(hl) adc a,b ld (hl),a ret ProgramInsertDeleteMem_Error: cp E_Memory ld hl,emsg_CannotUnarchive jq z,ThrowGeneralError JErrorNo: BCALL _JErrorNo ;; UNREACHABLE