# HG changeset patch # User William Astle # Date 1691302349 21600 # Node ID 2d52cd154ed11ca1e8fa4f8aa1f306d0820248de # Parent f492fa6f6dc8f0f123e478e67c82236463261b72 Split some code into separate files for easier management Because the source for lwbasic is so large, split it into several different files to make it easier to navigate and modify. This is part one of the split. diff -r f492fa6f6dc8 -r 2d52cd154ed1 src/consscr.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/consscr.s Sun Aug 06 00:12:29 2023 -0600 @@ -0,0 +1,85 @@ + *pragmapush list + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Console screen output driver +; +; Clear screen +console_clear ldb #0x60 ; VDG space character + ldx #textscreen ; point to text screen + stx console_curptr ; set cursor pointer to start of screen +console_clear0 stb ,x+ ; blank a character + cmpx #textscreen+0x200 ; end of screen? + blo console_clear0 ; brif not + rts +; Output NUL terminated string +console_outstr0 bsr console_outchr ; output the character +console_outstr lda ,x+ ; get byte from string + bne console_outstr0 ; brif not end of string + rts +; Output NUL terminated string followed by a newline +console_outstrn bsr console_outstr ; output the string + ; fallthrough intentional +; Output a newline (CR LF) +console_outnl lda #0x0d ; do the CR + bsr console_outchr + lda #0x0a ; do the LF + ; fallthrough intentional +; Output a single character to the screen; enter with character in A +console_outchr pshs d,x ; save registers + ldx console_curptr ; get current cursor pointer + cmpa #0x20 ; printable character? + blo console_outchr5 ; brif not + tsta ; is it a graphics block? + bmi console_outchr1 ; brif so - don't do anything to it + cmpa #0x40 ; number or most non-alpha characters? + blo console_outchr0 ; brif so - will need to flip bit 6 + cmpa #0x60 ; upper case? + blo console_outchr1 ; brif so - don't need to do anything to it + anda #0xdf ; clear bit 5 of lower case; moves it to bottom of character set +console_outchr0 eora #0x40 ; flip bit 6 - the "inversion" bit +console_outchr1 sta ,x+ ; stick it on screen +console_outchr2 stx console_curptr ; save new cursor pointer + cmpx #textscreen+0x200 ; end of screen? + blo console_outchr4 ; brif not + leax -32,x ; move pointer back one line + stx console_curptr + ldx #textscreen ; point to start of screen +console_outchr3 ldd 32,x ; get bytes from next line + std ,x++ ; stick them here + cmpx #textscreen+0x1e0 ; at last row? + blo console_outchr3 ; brif not + ldb #0x60 ; space character for VDG screen + bsr console_clear0 ; blank out last row (borrowing screen clear loop) +console_outchr4 puls d,x,pc ; restore registers and return +console_outchr5 cmpa #0x0c ; form feed? + bne console_outchr6 ; brif not + bsr console_clear ; clear screen + puls d,x,pc ; restore registers and return +console_outchr6 cmpa #0x0d ; carriage return? + bne console_outchr7 ; brif not + ldb console_curptr+1 ; get current screen pointer LSB + andb #0xe0 ; reset offset to start of line + stb console_curptr+1 ; save new pointer LSB + puls d,x,pc ; restore registers and return +console_outchr7 cmpa #0x0a ; line feed? + bne console_outchr8 ; brif not + ldx console_curptr ; get cursor pointer + leax 32,x ; move it forward exactly one line + bra console_outchr2 ; go update stuff check for scroll +console_outchr8 cmpa #0x08 ; backspace? + bne console_outchr9 ; brif not + cmpx #textscreen ; at start of screen? + beq console_outchr4 ; brif so - backspace does nothing + leax -1,x ; back up pointer (backspace is non-destructive) + bra console_outchr2 ; go update pointers, etc. +console_outchr9 cmpa #0x09 ; TAB character? + bne console_outchr4 ; brif not + ldb console_curptr ; get LSB of pointer + andb #7 ; 8 space tabs - only keep low 3 bits + lda #0x60 ; space character (tab is destructive) +console_outchra sta ,x+ ; put a space out + incb ; bump counter + cmpb #8 ; at next tab stop? + blo console_outchra ; brif not + bra console_outchr2 ; go update details and check for scroll + *pragmapop list diff -r f492fa6f6dc8 -r 2d52cd154ed1 src/defs.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/defs.s Sun Aug 06 00:12:29 2023 -0600 @@ -0,0 +1,208 @@ + *pragmapush list + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Various constants +console_curdel equ 10 ; delay between cursor blink cycles +keyb_bufflen equ 64 ; keyboard ring buffer length +keyb_repdeli equ 40 ; ticks before initial repeat (2/3 s) +keyb_repdelr equ 6 ; 10 repeats per second +keyb_caps equ 0x80 ; capslock enabled +keyb_alt equ 0x04 ; alt pressed +keyb_ctrl equ 0x02 ; ctrl pressed +keyb_shift equ 0x01 ; shift pressed +linebuffsize equ 0x100 ; the line input buffer (256 bytes) +stringstacknum equ 20 ; number of entries on the anonymous string descriptor stack +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Data structure used for calculations. Calculations are handled via structurs called value accumulators. A value +; accumulator consists of a data type flag (at the end of the structure) and a data area whose layout varies based +; on the actual data type. The layouts for each value type are described below. +; +; A value type that is NULL (not set to anything) has type 0 (valtype_none) and the rest should be zero. +; +; A value accumulator has the following structure for floating point: +; Offset Length Contents +; 0 1 fp exponent +; 1 4 fp mantissa +; 5 1 fp sign +; 6 1 value type +; +; A value accumulator has the following structure for integers: +; Offset Length Contents +; 0 1 *unsued* +; 1 4 integer value (two's complement) +; 5 1 *unused* +; 6 1 value type +; +; A value accumulator has the following structure for a string: +; Offset Length Contents +; 0 2 string length +; 2 2 *reserved for string data pointer expansion, must be zero* +; 4 2 string data pointer +; 6 1 value type +; +; Value type constants +valtype_none equ 0 ; unknown value type +valtype_int equ 1 ; integer (32 bit) value (signed) +valtype_float equ 2 ; float type (40 bit) value +valtype_string equ 3 ; string type (16 bit length, 16(32) bit data pointer +; Value accumulator structure definitions +val.type equ 6 ; value type offset +val.fpexp equ 0 ; fp exponent offset +val.fpmant equ 1 ; fp mantissa offset +val.fpsign equ 5 ; fp sign offset +val.int equ 1 ; integer offset +val.strlen equ 0 ; string length offset +val.strptr equ 4 ; string data pointer (low word) +val.size equ 7 ; size of a value accumulator +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ifdef COCO3 +; GIME INIT0 +GIME_COCO equ 0x80 ; Set for coco2 compatible mode (video display) +GIME_MMUEN equ 0x40 ; Set to enable MMU +GIME_IEN equ 0x20 ; GIME IRQ enable +GIME_FEN equ 0x10 ; GIME FIRQ enable +GIME_FExx equ 0x08 ; Enable constant RAM at 0xFExx (comes from block 0x3f) +GIME_SCS equ 0x04 ; Set to enable standard SCS (switches 0xFF5x) +GIME_ROME16 equ 0x00 ; 16K internal, 16K external ROM mode +GIME_ROME32 equ 0x03 ; 32K external ROM +GIME_ROMI32 equ 0x02 ; 32K internal ROM +; GIME INIT1 +GIME_TMRFAT equ 0x20 ; TIMER ticks approx every 279.365 ns +GIME_TMRSLOW equ 0x00 ; TIMER ticks approx every 63.695 µs +GIME_TASK0 equ 0x00 ; MMU task 0 +GIME_TASK1 equ 0x01 ; MMU task 1 +; GIME interrupt enable/status bits +GIME_ITIMER equ 0x20 ; TIMER interrupt (timer reaches 0) +GIME_IHBORD equ 0x10 ; HSYNC interrupt (falling edge) +GIME_IVBORD equ 0x08 ; VSYNC interrupt (falling edge) +GIME_ISERIAL equ 0x04 ; Falling edge of signal on pin 4 of serial port +GIME_IKEYBOARD equ 0x02 ; Interrupt if a 0 bit appears on bits 6-0 of PIA0.DA +GIME_ICART equ 0x01 ; Interrupt on falling edge of pin 8 of cartridge port +; GIME VMODE +GIME_BP equ 0x80 ; enable bit plane mode +GIME_BPI equ 0x20 ; colour burst phase inversion (composite output only) +GIME_MONO equ 0x10 ; disable colour burst (composite output only) +GIME_H50 equ 0x08 ; set to 50Hz operation +GIME_LPR1 equ 0x00 ; one line per row +GIME_LPR2 equ 0x02 ; two lines per row (also works on graphics) +GIME_LPR8 equ 0x03 ; 8 lines per row +GIME_LPR9 equ 0x04 ; 9 lines per row +GIME_LPR10 equ 0x05 ; 10 lines per row +GIME_LPR11 equ 0x06 ; 11 lines per row +GIME_LPRINF equ 0x07 ; "infinite" lines per row +; GIME VRES +GIME_LPF192 equ 0x00 ; 192 lines on screen +GIME_LPF200 equ 0x40 ; 200 lines on screen (actually 199 due to hardware bug) +GIME_LPF225 equ 0x60 ; 225 lines on screen +GIME_BPR16 equ 0x00 ; 16 bytes per row +GIME_BPR20 equ 0x04 ; 20 bytes per row +GIME_BPR32 equ 0x08 ; 32 bytes per row +GIME_BPR40 equ 0x0c ; 40 bytes per row +GIME_BPR64 equ 0x10 ; 64 bytes per row +GIME_BPR80 equ 0x14 ; 80 bytes per row +GIME_BPR128 equ 0x18 ; 128 bytes per row +GIME_BPR160 equ 0x1c ; 160 bytes per row +GIME_TXT32 equ 0x00 ; 32 characters per row +GIME_TXT40 equ 0x04 ; 40 characters per row +GIME_TXT64 equ 0x10 ; 64 characters per row +GIME_TXT80 equ 0x14 ; 80 characters per row +GIME_BPP1 equ 0x00 ; 1 bit per pixel +GIME_BPP2 equ 0x01 ; 2 bits per pixel +GIME_BPP4 equ 0x02 ; 4 bits per pixel +GIME_TXTATTR equ 0x01 ; text attributes enabled + endc + ifdef COCO3 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Stuff on the fixed memory page + org 0xfe00 + rmb 0xed ; unused +INT.FLAG rmb 1 ; validity flag +INT.SWI3 rmb 3 ; SWI3 bounce vector +INT.SWI2 rmb 3 ; SWI2 bounce vector +INT.FIRQ rmb 3 ; FIRQ bounce vector +INT.IRQ rmb 3 ; IRQ bounce vector +INT.SWI rmb 3 ; SWI bounce vector +INT.NMI rmb 3 ; NMI bounce vector + endc +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Hardware definitions for the I/O page + org 0xff00 +PIA0 equ * ; Keyboard PIA +PIA0.DA rmb 1 ; PIA0 data/direction A +PIA0.CA rmb 1 ; PIA0 control A +PIA0.DB rmb 1 ; PIA0 data/direction B +PIA0.CB rmb 1 ; PIA0 control B + rmb 28 ; mirror images of PIA0 +PIA1 equ * ; DA/misc stuff +PIA1.DA rmb 1 ; PIA1 data/direction A +PIA1.CA rmb 1 ; PIA1 control A +PIA1.DB rmb 1 ; PIA1 data/direction B +PIA1.CB rmb 1 ; PIA1 control B + rmb 28 ; mirror images of PIA1 + rmb 16 ; SCS/Disk controller + rmb 16 ; second half of SCS area + rmb 32 ; miscelaneous hardware + ifdef COCO3 + rmb 16 ; *reserved* (unused but the GIME drives them) +GIME.INIT0 rmb 1 ; basic GIME system config +GIME.INIT1 rmb 1 ; MMU task and timer rate +GIME.IRQ rmb 1 ; GIME IRQ enable/status register +GIME.FIRQ rmb 1 ; GIME FIRQ enable/status register +GIME.TIMER rmb 2 ; GIME programmable timer + rmb 2 ; *reserved* +GIME.VMODE rmb 1 ; GIME video mode setting +GIME.VRES rmb 1 ; GIME video resolution setting + rmb 1 ; *reserved* (used for MMU expansion on some memory boards) +GIME.BORDER rmb 1 ; GIME border colour +GIME.VSCROLL rmb 1 ; vertical scroll offset register/VDG screen mode variation +GIME.VOFFSET rmb 2 ; address of video memory (8 byte increments) +GIME.HOFFSET rmb 1 ; horizontal scroll offset +GIME.MMU equ * ; MMU registers (two tasks) +GIME.MMU0 rmb 8 ; MMU task 0 +GIME.MMU1 rmb 8 ; MMU task 1 +GIME.PALETTE rmb 16 ; Palette registers + else + rmb 64 ; unused on Coco 1/2 (GIME on Coco 3) + endc +SAMREG equ * ; the SAM configuration register +SAM.V0CLR rmb 1 ; SAM video mode bits +SAM.V0SET rmb 1 +SAM.V1CLR rmb 1 +SAM.V1SET rmb 1 +SAM.V2CLR rmb 1 +SAM.V2SET rmb 1 +SAM.F0CLR rmb 1 ; SAM screen address bits +SAM.F0SET rmb 1 +SAM.F1CLR rmb 1 +SAM.F1SET rmb 1 +SAM.F2CLR rmb 1 +SAM.F2SET rmb 1 +SAM.F3CLR rmb 1 +SAM.F3SET rmb 1 +SAM.F4CLR rmb 1 +SAM.F4SET rmb 1 +SAM.F5CLR rmb 1 +SAM.F5SET rmb 1 +SAM.F6CLR rmb 1 +SAM.F6SET rmb 1 +SAM.P1CLR rmb 1 ; SAM "page 1" selection (or extra memory type flag) +SAM.P1SET rmb 1 +SAM.R0CLR rmb 1 ; SAM R0 bit (address dependent speedup, not used on Coco3) +SAM.R0SET rmb 1 +SAM.R1CLR rmb 1 ; SAM R1 bit (full speedup/coco 3 speedup) +SAM.R1SET rmb 1 +SAM.M0CLR rmb 1 ; SAM M0/M1 bits (memory type, not used on Coco3) +SAM.M0SET rmb 1 +SAM.M1CLR rmb 1 +SAM.M1SET rmb 1 +SAM.TYCLR rmb 1 ; force ROM mode (map type 0) +SAM.TYSET rmb 1 ; set RAM mode (map type 1) + rmb 18 ; *MPU reserved* +CPU.SWI3 rmb 2 ; CPU SWI3 vector +CPU.SWI2 rmb 2 ; CPU SWI2 vector +CPU.FIRQ rmb 2 ; CPU FIRQ vector +CPU.IRQ rmb 2 ; CPU IRQ vector +CPU.SWI rmb 2 ; CPU SWI vector +CPU.NMI rmb 2 ; CPU NMI vector +CPU.RESET rmb 2 ; CPU RESET/startup vector + *pragmapop list diff -r f492fa6f6dc8 -r 2d52cd154ed1 src/init.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/init.s Sun Aug 06 00:12:29 2023 -0600 @@ -0,0 +1,268 @@ + *pragmapush list + *pragma list +START orcc #0x50 ; make sure interrupts are disabled if we come here in an unusual way + ifdef COCO3 + ldu #gime_inite ; point to end of GIME initializer + ldx #GIME.INIT0+(gime_inite-gime_init) ; point to end of GIME registers + ldb #gime_inite-gime_init ; number of bytes to transfer +initc0 lda ,-u ; copy byte to GIME (count down so we init MMU before turning it on) + sta ,-x + decb ; done? + bne initc0 ; brif not + endc + ldd #0xff34 ; initizer for below + tfr a,dp ; set DP to I/O page + setdp 0xff ; tell assembler about DP value + clr PIA0.CA ; set PIA0 A to direction mode + clr PIA0.CB ; set PIA0 B to direction mode + clr PIA0.DA ; set PIA0 A to all inputs (comparator, keyboard rows) + sta PIA0.DB ; set PIA0 B to all outputs (keyboard columns) + stb PIA0.CA ; set PIA0 A to data mode, interrupt disabled, MUX to source 0 + stb PIA0.CB ; set PIA0 B to data mode, interrupt disabled, MUX to source 0 + clr PIA1.CA ; set PIA1 A to direction mode + clr PIA1.CB ; set PIA1 B to direction mode + deca ; set PIA1 A bits 7-1 output (DAC, RS232), 0 input (cassette) + sta PIA1.DA + lda #0xf8 ;* set PIA1 B bits 7-3 output (VDG stuff), 2-0 input (single bit sound, + sta PIA1.DB ;* RS232 input, ram size input) + stb PIA1.CA ; set PIA1 A to data mode, interrupt disabled, cassette motor off + stb PIA1.CB ; set PIA1 B to data mode, interrupt disabled, sound off + lda #2 ; set RS232 output to "marking" (stop bit) + sta PIA1.DA + lda #16 ; clear 16 SAM register bits + ldu #SAMREG ; point to SAM register bits +init0 sta ,u++ ; clear SAM bit + deca ; done all? + bne init0 ; brif not +; set the SAM to point to the text screen, which the code will handle at any +; arbitrary 512 byte aligned address in memory + ifne (textscreen)&0x200 + sta SAM.F0SET + endc + ifne (textscreen)&0x400 + sta SAM.F1SET + endc + ifne (textscreen)&0x800 + sta SAM.F2SET + endc + ifne (textscreen)&0x1000 + sta SAM.F3SET + endc + ifne (textscreen)&0x2000 + sta SAM.F4SET + endc + ifne (textscreen)&0x4000 + sta SAM.F5SET + endc + ifne (textscreen)&0x8000 + sta SAM.F6SET + endc + ifdef COCO2B +; The following SAM configuration sequence is different from the one in the usual +; one used by the earlier models of the Coco because the Coco2B has the '785 variant +; of the SAM instead of the '783 variant. The '785 variant supports 16Kx4 RAMs which +; are used in Coco2B systems. Hence why there is a different version of this ROM +; just for the Coco2B. + clr PIA0.DB ; strobe RAM size low + ldb #4 ; is input low? + bitb PIA1.DB + beq init1 ; brif not + sta SAM.M0SET ; program SAM for 16Kx4 RAMs + sta SAM.P1SET + skip2 +init1 sta SAM.M1SET ; program SAM for 64Kx1 RAMs + else + ifndef COCO3 +; Detect the installed memory size so the SAM ('783 variant) can be correctly +; programmed for the installed memory. Note that this sequence is replaced with +; a different one for the Coco2B which has the '785 variant of the SAM. + ldb #0xff ; strobe RAM size high + stb PIA0.DB + ldb #4 ; mask for ram size check + bitb PIA1.DB ; is the bit set on ram size input? + beq init2 ; brif not - 4Kx1 RAMs + sta PIA0.DB ; clear RAM size output to see what happens (A is 0 from above) + bitb PIA1.DB ; is it set now? + beq init1 ; brif not - 64Kx1 RAMs + leau -2,u ; adjust pointer so we set the other RAM size bit for the SAM (16Kx1) +init1 sta -3,u ; set M0 (16Kx1) or M1 (64Kx1) + endc + endc +init2 tfr a,dp ; set DP to bottom of memory (A is 0 from above) + setdp 0 ; tell assembler about it + lds #textscreen ; put the stack just below the text screen + ifdef COCO3 +; Check if we need to do a ROM/RAM copy, which will happen if the interrupt vectors are +; not flagged valid OR the reset vector isn't valid + ldb INT.FLAG ; are the bounce vectors valid? + cmpb #0x55 + bne initc4 ; brif not - do ROM/RAM copy + ldb RSTFLG ; is reset vector valid? + bne initc2 ; brif not - check secondary location + ldx RSTVEC ; get reset vector + ldb ,x ; is it valid?\ + cmpb #0x12 + bne initc2 ; brif not +initc1 jmp ,x ; transfer control to warm start routine +initc2 clr GIME.MMU0 ; check again with block 0 in the direct page + ldb RSTFLG ; get new RSTFLG + cmpb #0x55 ; valid? + bne initc3 ; brif not + ldx RSTVEC ; get new RSTVEC + ldb ,x ; is it valid? + cmpb #0x12 + beq initc1 ; brif so - transfer control +initc3 ldb #0x38 ; restore MMU + stb GIME.MMU0 +initc4 ldx #initc6 ; point to helper + ldu #textscreen ; point to text screen + ldb #initc7-initc6 ; bytes to copy +initc5 lda ,x+ ; copy byte + sta ,u+ + decb ; done? + bne initc5 ; brif not + ldu #0x8000 ; point to start of ROM + jmp textscreen ; transfer control to helper in RAM +initc6 sta SAM.TYCLR ; drop to ROM mode + pulu d,x,y,s ; grab 8 bytes + sta SAM.TYSET ; go to RAM mode + pshu d,x,y,s ; stick the bytes in RAM + leau 8,u ; move to next 8 bytes + cmpu #0xfe00 ; end of stuff to copy? + blo initc6 ; brif not + jmp initc7 ; go back to mainline +initc7 lds #textscreen ; reset stack to somewhere safe + lda #0x12 ; activate ROM warm start handler + sta warmstart + ldx #INT.FLAG ; point to bounce vector destination + ldu #int_init ; point to initializer for bounce vectors + ldb #int_inite-int_init ; number of bytes to copy +initc8 lda ,u+ ; copy byte + sta ,x+ + decb ; done? + bne initc8 ; brif not +; now recheck for warm start in case ROM/RAM copy made things valid + endc + ldb RSTFLG ; is the reset vector valid? + cmpb #0x55 + bne coldstart ; brif not - do cold start + ldx RSTVEC ; get warm start routine pointer + ldb ,x ; does it start with NOP? + cmpb #0x12 + bne coldstart ; brif not - do cold start + jmp ,x ; transfer control to warm start routine + ifdef COCO3 +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; GIME register initializer +gime_init fcb GIME_COCO|GIME_MMUEN|GIME_FExx|GIME_SCS|GIME_ROMI32 ; enable MMU, SCS, constant page, internal ROM + fcb GIME_TASK0 ; use MMU task 0 + fcb 0 ; do not enable IRQ sources + fcb 0 ; do not enable FIRQ sources + fdb 0xfff ; set timer to max value + fdb 0 ; *reserved placeholder* + fcb 0,0,0,0 ; SG4 screen settings with black border + fcb 0x0f,0xe0,0x00,0x00 ; (puts screen in bottom 64K of memory) + fcb 0x38,0x39,0x3a,0x3b ; MMU task 0 (bottom of top 64K of RAM) + fcb 0x3c,0x3d,0x3e,0x3f ; (ROM shadow must be in 3c...3f) + fcb 0x38,0x39,0x3a,0x3b ; MMU task 1 (copy of task 0) + fcb 0x3c,0x3d,0x3e,0x3f + fcb 18,54,9,36,63,27,45,38 ; palette values (RGB) + fcb 0,18,0,63,0,18,0,38 +gime_inite equ * +int_init fcb 0x55 ; vectors valid flag + jmp SW3VEC ; bounce to stock ROM compatibility vector + jmp SW2VEC ; bounce to stock ROM compatibility vector + jmp FRQVEC ; bounce to stock ROM compatibility vector + jmp IRQVEC ; bounce to stock ROM compatibility vector + jmp SWIVEC ; bounce to stock ROM compatibility vector + jmp NMIVEC ; bounce to stock ROM compatibility vector +int_inite equ * + endc +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Cold start handling +coldstart ldx #dpstart ; point to start of direct page + ldd #0 ; set up for blanking +coldstart0 std ,x++ ; blank a couple of bytes + cmpx #textscreen ; end of low memory? + blo coldstart0 ; brif not + ifndef COCO3 +; This is the memory size detection sequence. This runs through memory starting at the bottom of memory +; and stops when it reaches something that can't be modified successfully. This is basically the same +; algorithm used by the stock ROM. It takes less space than doing a more pointed set of probes. The end +; result will be X pointing to the byte one below the top of RAM. This is intentional to ensure there +; is one writeable byte at the top of string space. Note that X will point to the byte after the end +; of the text screen when we get here. + ldx #heapstart ; point to start of heap +coldstart1 lda 2,x ; get original value at test location + coma ; invert all bits + sta 2,x ; write it to the memory location + cmpa 2,x ; did it take? + bne coldstart2 ; brif not + com 2,x ; restore memory byte + leax 1,x ; move pointer forward + bra coldstart1 ; go check next byte + else +; For the Coco3, we do not need to concern ourselves about where the top actual memory is so we don't +; bother doing a memory scan in the default 64K memory map. Because we always run from RAM, we can actually +; set the top of memory to the actual top of the 32K space without having to ensure there is an extra byte +; available above the string space. + ldx #ROMSTART-1 ; point to top of memory + endc +coldstart2 stx memtop ; save absolute top of memory + stx memsize ; save top of unreserved memory + stx stringtab ; mark string space as empty + leax -200,x ; allocate 200 bytes of string space + stx freetop ; save top of free memory + clr ,-x ; make a hole for the "end of call stack" flag + stx stackptr ; save the new call stack pointer + leas ,x ; put the actual stack below the above + ldx #heapstart ; point to start of free memory + clr ,x+ ; put a NUL before the start of the program + stx progtext ; put the start of the program there + clr ,x+ ; put a NULL pointer to mark end of program + clr ,x+ + stx vartab ; put start of integer variables at end of program + stx objecttab ; also put the start of large objects there + stx freestart ; mark the start of free memory + lda #keyb_caps ; enable caps lock but disable all other shift states + sta keyb_flags + ldx #warmstart ; set up warm start handler + stx RSTVEC + lda #0x55 ; activate warm start handler + sta RSTFLG + ldd #0x7e3b ; opcodes for JMP extended and RTI + ldx #irqhandler ; enable IRQ handler with a JMP at the vector + sta IRQVEC + stx IRQVEC+1 + sta FRQVEC ; initialize FIRQ handler with JMP + ldx #firqhandler + stx FRQVEC+1 + stb NMIVEC ; initialize NMI to RTI + stb SW3VEC ; initialize SWI3 to RTI + stb SW2VEC ; initialize SWI2 to RTI + stb SWIVEC ; initialize SWI to RTI + ldx #greeting ; display greeting + jsr console_outstr + bra warmstartb ; finish up initialization +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Warm start handling + ifdef COCO3 +warmstart fcb 0xff ; set to 0xff to force ROM/RAM copy on reset + else +warmstart nop ; flag warm start routine as valid + endc + jsr console_clear ; clear screen + clr filenum ; reset I/O channel to the screen +warmstartb jsr keyb_reset ; reset the keyboard + lda #0x35 ; enable VSYNC interrupt in PIA + sta PIA0.CB + andcc #0xaf ; enable interrupts at the cpu + jmp immediate ; go start immediate mode +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; System startup message +; (start with form feed to clear screen; saves 2 bytes over 'jsr console_clear' in cold start) +greeting fcc '\fLWBASIC VERSION 2022.0\r\n' + fcc 'COPYRIGHT (C) 2022 BY LOST\r\n' + fcc 'WIZARD ENTERPRISES INC.\r\n' + fcn '\n' + *pragmapop list diff -r f492fa6f6dc8 -r 2d52cd154ed1 src/irq.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/irq.s Sun Aug 06 00:12:29 2023 -0600 @@ -0,0 +1,51 @@ + *pragmapush list + *pragma nolist +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; IRQ handler +; +; Note that the interrupt flag in the PIA is cleared at the start of the interrupt handler. That means that if it takes +; a long time to process this interrupt, or processing this interrupt was delayed somewhat, it is far less likely that +; an interrupt gets missed. In that case, we may end up re-interrupting immediately on RTI, but it should reduce the +; number of missed interrupts. +irqhandler lda PIA0.CB ; was it VSYNC? + bmi irqhandler0 ; brif so + lda PIA0.DA ; clear HSYNC flag so we don't get stuck if it gets enabled + ifdef COCO3 + lda GIME.IRQ ; clear GIME IRQ state flags + endc + rti +irqhandler0 lda PIA0.DB ; clear VSYNC flag + clra ; make sure DP is pointing to the right place + tfr a,dp + lda console_blnkdel ; is the cursor blinking? + beq irqhandler1 ; brif not + dec console_blnkdel ; time to cycle cursor? + bne irqhandler1 ; brif not + lda #console_curdel ; reset blink counter + sta console_blnkdel + lda [console_curptr] ; get character at cursor + adda #0x10 ; move to next colour + ora #0x8f ; force it to be a full 4x4 colour block + sta [console_curptr] ; update cursor on screen +irqhandler1 jsr keyb_read ; go handle the keyboard + rti +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; FIRQ handler +; +; This handler is present to prevent accidentally enabling the interrupt and thus hanging to system. It may seem to be +; a waste of code space, but consider it a self defense situation. +firqhandler pshs a ; need a scratch register + ifdef COCO3 + lda GIME.FIRQ ; clear GIME FIRQ state flags + endc + lda PIA1.DA ; clear interrupt flags + lda PIA1.DB + lda PIA1.CA ; disable interrupts to prevent system hang + anda #0xfe + sta PIA1.CA + lda PIA1.CB + anda #0xfe + sta PIA1.CB + puls a ; restore register + rti + *pragmapop list diff -r f492fa6f6dc8 -r 2d52cd154ed1 src/keyb.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/keyb.s Sun Aug 06 00:12:29 2023 -0600 @@ -0,0 +1,255 @@ + *pragmapush list + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Check for BREAK; this needs to check the keyboard directly instead of just using the usual key fetching routine so +; we don't interfere with keyboard buffering if BREAK isn't pressed. We also need to scan the keyboard directly for this +; so we react even if the keyboard buffer is full. If BREAK is pressed, the keyboard buffer is emptied. +breakcheck lda #0xfb ; strobe column for BREAK + sta PIA0.DB + clra ; clear carry for no BREAK + lda PIA0.DA ; read rows + bita #0x40 ; is BREAK down? + bne breakcheck0 ; brif not - check for SHIFT-@ + sync ; wait for interrupt to scan keyboard + bsr keyb_clearbuff ; reset keyboard buffer + coma ; flag BREAK +breakcheck1 rts +breakcheck0 lda #0x7f ; check for SHIFT + sta PIA0.DB + lda PIA0.DA + bita #0x40 ; shift? + bne breakcheck1 ; brif not + lda #0xfe ; check for @ + sta PIA0.DB + lda PIA0.DA + bita #1 ; @? + bne breakcheck1 ; brif not + bsr keyb_clearbuff ; clear buffer +breakcheck2 sync ; wait for keyboard to actually be scanned + bsr keyb_getkey + bcs breakcheck2 ; brif no key down + bra breakcheck ; go do the break/pause check dance again +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Console keyboard input driver +; +; Reset the keyboard state, which means clearing the buffer and state flags +keyb_reset bsr keyb_clearbuff ; clear keyboard buffer + lda keyb_flags ; reset keyboard state flags but keep capslock + anda #keyb_caps + sta keyb_flags + clr keyb_joystate ; clear joystick button state + clr keyb_curscan ; stop any keyboard repeating + ldx #0xffff ; mark all key state as "unpressed" + stx keyb_state + stx keyb_state+2 + stx keyb_state+4 + stx keyb_state+6 + rts +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Empty the keyboard buffer +keyb_clearbuff ldx #keyb_buff ; point to start of buffer + stx keyb_buffr ; set both pointers to the start + stx keyb_buffw + rts +; Read character from keyboard ring buffer; return with C set if buffer empty; this doesn't actually need to have +; interrupts disabled because the interrupt only ever updates the write pointer and then only to increase it. As a +; result, worst case is that we don't detect the contents added to the buffer on this call and have to wait for the +; next. +keyb_getkey pshs x ; save register + ldx keyb_buffr ; get read pointer + cmpx keyb_buffw ; same as write pointer? + bne keyb_getkey0 ; brif not - we have a result + coma ; set carry for empty buffer + puls x,pc ; restore register and return +keyb_getkey0 lda ,x+ ; get character from buffer + cmpx #keyb_buff+keyb_bufflen ; did we run off end of buffer? + blo keyb_getkey1 ; brif not + ldx #keyb_buff ; reset to start +keyb_getkey1 stx keyb_buffr ; save new read pointer + andcc #0xfe ; flag key retrieved + puls x,pc ; restore register and return +; The PIA reading loop is specifically set up to NOT read PIA0.DB to avoid prematurely clearing the VSYNC interrupt flag +; since that could lead to missing interrupts. Reading PIA0.DA will clear the HSYNC interrupt flag but that's less of a +; problem because that interrupt is basically useless. +; +; As a note, doing the PIA read in a loop ends up using an extra 27 CPU cycles for the BCS instruction. However, it +; saves 70 code bytes. The trade off seems worth it in this case. +; +; Once keyboard state is read, we do the following: +; +; * update the state of SHIFT, CTRL, ALT +; * decode all other keys in a loop +keyb_read0a pshs b ; save flag bit + ldb a,y ; get state flag + bitb #0x40 ; did it change state? + bne keyb_read0d ; brif so + puls b,pc ; clean up and return +keyb_read0d andb #0xbf ; flag it as not changed + stb a,y + ldb a,u ; get current modifier state + eorb #0x40 ; flip the state bit + stb a,u ; save new state flags + bitb #0x40 ; Z set if not down + puls b ; get back flag bit + beq keyb_read0b ; brif key is pressed + comb ; invert bit flag + andb keyb_flags ; clear bit in flags + bra keyb_read0c ; finish up +keyb_read0b orb keyb_flags ; set the flag +keyb_read0c stb keyb_flags ; update flags + rts +keyb_read leas -9,s ; make temporary buffer + leay 1,s ; point to temporary state buffer + clra ;* set to 0xff with C clear; start by strobing no columns for joystick + deca ;* then rotate the 0 bit through to do the actual keyboard columns + ldu #keyb_state ; point to end of keyboard state buffer + sta PIA0.DB ; strobe no columns + ldb PIA0.DA ; get joystick button state + stb keyb_joystate ; save it for later when needed + andb #0x7f ; mask off comparator (pretend "button" down) + stb ,s ; save button/comparator state mask + rola ; set up for first column +keyb_read0 sta PIA0.DB ; set column strobe + ldb PIA0.DA ; read row data + eorb ,u+ ; set bits if state changed + andb ,s ; mask off comparator and active buttons + stb ,y+ ; save state change information + rola ; shift to next column + bcs keyb_read0 ; brif we haven't done the last column + sta PIA0.DB ; reset column strobe to none + ldd #0xff00|keyb_shift + bsr keyb_read0a + ldd #0xfc00|keyb_ctrl + bsr keyb_read0a + ldd #0xfb00|keyb_alt + bsr keyb_read0a +keyb_read3 ldd #0x0701 ; initialize bit probe and counter +keyb_read4 leay -1,y ; move pointers to next byte + leau -1,u +keyb_read5 bitb ,y ; did this key change state? + bne keyb_read7 ; brif so +keyb_read6 adda #8 ; adjust scan code + lslb ; shift bit probe + bpl keyb_read5 ; brif we haven't done all bits + ldb ,y ; update state flags for this byte + eorb ,u + stb ,u + ldb #1 ; reset bit probe + anda #0x07 ; reset scan code + deca ; adjust for next column + bpl keyb_read4 ; brif not - do another + leas 9,s ; clean up stack + ldb keyb_curscan ; is key repeating? + bne keyb_read9 ; brif so +keyb_reada rts +keyb_read7 bitb ,u ; get current state + bne keyb_read8 ; brif key pressed (make) + cmpa keyb_curscan ; is it the currently repeating key? + bne keyb_read6 ; brif not - don't need to do anything + clr keyb_curscan ; clear the current repeat + bra keyb_read6 +keyb_read8 sta keyb_curscan ; set the current scan code that is repeating + pshs d ; save current bit probe and scan code + ldb #keyb_repdeli ; intialize repeat delay + stb keyb_repdel + bsr keyb_tobuff ; decode key to buffer + puls d ; restore scan code and bit probe + bra keyb_read6 ; go handle the next bit +keyb_read9 dec keyb_repdel ; is it time to repeat it? + bne keyb_reada ; brif not + ldb #keyb_repdelr ; reset repeat delay + stb keyb_repdel + lda keyb_curscan ; get current scan code +keyb_tobuff tsta ; @? + beq keyb_tobuff7 ; brif so + cmpa #26 ; is it alpha or @? + bhi keyb_tobuff6 ; brif not + ldb keyb_flags ; get shift flags + bitb #keyb_ctrl|keyb_alt ; ALT or CTRL? + bne keyb_tobuff4 ; brif one or both + ora #0x60 ; make lower case + bitb #keyb_caps ; capslock enabled? + beq keyb_tobuff0 ; brif not + eora #0x20 ; flip to upper case +keyb_tobuff0 bitb #keyb_shift ; shifted? + beq keyb_tobuff1 ; brif not + eora #0x20 ; flip case if shifted +keyb_tobuff1 ldx keyb_buffw ; get write pointer for keyboard buffer + sta ,x+ ; put it in the buffer + cmpx #keyb_buff+keyb_bufflen ; end of buffer? + blo keyb_tobuff2 ; brif not + ldx #keyb_buff ; reset pointer to start +keyb_tobuff2 cmpx keyb_buffr ; did we run into the read pointer? + beq keyb_tobuff3 ; brif so - there wasn't room so don't save pointer + stx keyb_buffw ; update the write pointer +keyb_tobuff3 rts +keyb_tobuff4 bitb #keyb_alt ; is ALT? + beq keyb_tobuff1 ; brif not - scan code is CTRL- code + ora #0x80 ; set bit 7 for "ALT" codes + bitb #keyb_shift ; shifted? + beq keyb_tobuff5 ; brif not + ora #0x20 ; set bit 5 +keyb_tobuff5 bitb #keyb_ctrl ; ctrl? + beq keyb_tobuff1 ; brif not - stash it in the buffer + ora #0x40 ; set bit 6 for "ctrl + bra keyb_tobuff1 ; stash it the buffer +keyb_tobuff6 suba #26 ; codes above 26 down to 1; @ will be 0 +keyb_tobuff7 cmpa #6 ; is it "0"? + bne keyb_tobuff8 ; brif not + ldb keyb_flags ; get shift flags + bitb #keyb_shift|keyb_ctrl ; CTRL-0 or SHIFT-0? + beq keyb_tobuff8 ; brif not - not "capslock" + eorb #keyb_caps ; flip the capslock state + stb keyb_flags +keyb_tobuffa rts ; and don't put it in the buffer +keyb_tobuff8 cmpa #25 ; is it at or above ALT? + blo keyb_tobuff9 ; brif not + suba #2 ; close gap for ALT/CTRL +keyb_tobuff9 ldb #8 ;* 8 codes; multiply by 8 and move to B + mul ;* + ldx #keyb_codetab ; point to special code table + abx ; now X points to the base entry in the table + ldb keyb_flags ; get shift flags + andb #keyb_shift|keyb_ctrl|keyb_alt ; keep only shift/ctrl/alt + lda b,x ; fetch key code + beq keyb_tobuffa ; brif no code to return + bra keyb_tobuff1 ; go stash it in the buffer +; This is the keyboard code table; there are 8 bytes per entry in the following order: +; 0: unmodified +; 1: shift +; 2: ctrl +; 3: ctrl-shift +; 4: alt +; 5: alt-shift +; 6: alt-ctrl +; 7: alt-ctrl-shift +; +; No entries for ALT, CTRL, SHIFT, or letters +keyb_codetab fcb 0x40,0x13,0x40,0x40,0x80,0xa0,0xc0,0xe0 ; @ + fcb 0x5e,0x5f,0x00,0x00,0x00,0x00,0x00,0x00 ; + fcb 0x0a,0x5b,0x00,0x00,0x00,0x00,0x00,0x00 ; + fcb 0x08,0x15,0x00,0x00,0x00,0x00,0x00,0x00 ; + fcb 0x09,0x5d,0x00,0x00,0x00,0x00,0x00,0x00 ; + fcb 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20 ; + fcb 0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 0 (shift/ctrl variants shadowed above) + fcb 0x31,0x21,0x00,0x00,0x00,0x00,0x00,0x00 ; 1 ! + fcb 0x32,0x22,0x00,0x00,0x00,0x00,0x00,0x00 ; 2 " + fcb 0x33,0x23,0x00,0x00,0x00,0x00,0x00,0x00 ; 3 # + fcb 0x34,0x24,0x00,0x00,0x00,0x00,0x00,0x00 ; 4 $ + fcb 0x35,0x25,0x00,0x00,0x00,0x00,0x00,0x00 ; 5 % + fcb 0x36,0x26,0x00,0x00,0x00,0x00,0x00,0x00 ; 6 & + fcb 0x37,0x27,0x00,0x00,0x00,0x00,0x00,0x00 ; 7 ' + fcb 0x38,0x28,0x00,0x00,0x00,0x00,0x00,0x00 ; 8 ( + fcb 0x39,0x29,0x00,0x00,0x00,0x00,0x00,0x00 ; 9 ) + fcb 0x3a,0x2a,0x00,0x00,0x00,0x00,0x00,0x00 ; : * + fcb 0x3b,0x2b,0x00,0x00,0x00,0x00,0x00,0x00 ; ; + + fcb 0x2c,0x3c,0x00,0x00,0x00,0x00,0x00,0x00 ; , < + fcb 0x2d,0x3d,0x00,0x00,0x00,0x00,0x00,0x00 ; - = + fcb 0x2e,0x3e,0x00,0x00,0x00,0x00,0x00,0x00 ; . > + fcb 0x2f,0x3f,0x00,0x00,0x00,0x00,0x00,0x00 ; / ? + fcb 0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d ; + fcb 0x0c,0x5c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c ; + fcb 0x03,0x03,0x1b,0x1b,0x9b,0xbb,0xdb,0xfb ; + fcb 0x1c,0x1d,0x1c,0x1d,0x00,0x00,0x00,0x00 ; + fcb 0x1e,0x1f,0x1e,0x1f,0x00,0x00,0x00,0x00 ; + *pragmapop list diff -r f492fa6f6dc8 -r 2d52cd154ed1 src/lwbasic.s --- a/src/lwbasic.s Sun Jul 02 17:21:11 2023 -0600 +++ b/src/lwbasic.s Sun Aug 06 00:12:29 2023 -0600 @@ -28,944 +28,20 @@ skip2 macro noexpand fcb 0x8c ; opcode for CMPX immediate endm +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Include the various sub source files + include defs.s + include vars.s *pragmapop list -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Various constants -console_curdel equ 10 ; delay between cursor blink cycles -keyb_bufflen equ 64 ; keyboard ring buffer length -keyb_repdeli equ 40 ; ticks before initial repeat (2/3 s) -keyb_repdelr equ 6 ; 10 repeats per second -keyb_caps equ 0x80 ; capslock enabled -keyb_alt equ 0x04 ; alt pressed -keyb_ctrl equ 0x02 ; ctrl pressed -keyb_shift equ 0x01 ; shift pressed -linebuffsize equ 0x100 ; the line input buffer (256 bytes) -stringstacknum equ 20 ; number of entries on the anonymous string descriptor stack -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Data structure used for calculations. Calculations are handled via structurs called value accumulators. A value -; accumulator consists of a data type flag (at the end of the structure) and a data area whose layout varies based -; on the actual data type. The layouts for each value type are described below. -; -; A value type that is NULL (not set to anything) has type 0 (valtype_none) and the rest should be zero. -; -; A value accumulator has the following structure for floating point: -; Offset Length Contents -; 0 1 fp exponent -; 1 4 fp mantissa -; 5 1 fp sign -; 6 1 value type -; -; A value accumulator has the following structure for integers: -; Offset Length Contents -; 0 1 *unsued* -; 1 4 integer value (two's complement) -; 5 1 *unused* -; 6 1 value type -; -; A value accumulator has the following structure for a string: -; Offset Length Contents -; 0 2 string length -; 2 2 *reserved for string data pointer expansion, must be zero* -; 4 2 string data pointer -; 6 1 value type -; -; Value type constants -valtype_none equ 0 ; unknown value type -valtype_int equ 1 ; integer (32 bit) value (signed) -valtype_float equ 2 ; float type (40 bit) value -valtype_string equ 3 ; string type (16 bit length, 16(32) bit data pointer -; Value accumulator structure definitions -val.type equ 6 ; value type offset -val.fpexp equ 0 ; fp exponent offset -val.fpmant equ 1 ; fp mantissa offset -val.fpsign equ 5 ; fp sign offset -val.int equ 1 ; integer offset -val.strlen equ 0 ; string length offset -val.strptr equ 4 ; string data pointer (low word) -val.size equ 7 ; size of a value accumulator -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - ifdef COCO3 -; GIME INIT0 -GIME_COCO equ 0x80 ; Set for coco2 compatible mode (video display) -GIME_MMUEN equ 0x40 ; Set to enable MMU -GIME_IEN equ 0x20 ; GIME IRQ enable -GIME_FEN equ 0x10 ; GIME FIRQ enable -GIME_FExx equ 0x08 ; Enable constant RAM at 0xFExx (comes from block 0x3f) -GIME_SCS equ 0x04 ; Set to enable standard SCS (switches 0xFF5x) -GIME_ROME16 equ 0x00 ; 16K internal, 16K external ROM mode -GIME_ROME32 equ 0x03 ; 32K external ROM -GIME_ROMI32 equ 0x02 ; 32K internal ROM -; GIME INIT1 -GIME_TMRFAT equ 0x20 ; TIMER ticks approx every 279.365 ns -GIME_TMRSLOW equ 0x00 ; TIMER ticks approx every 63.695 µs -GIME_TASK0 equ 0x00 ; MMU task 0 -GIME_TASK1 equ 0x01 ; MMU task 1 -; GIME interrupt enable/status bits -GIME_ITIMER equ 0x20 ; TIMER interrupt (timer reaches 0) -GIME_IHBORD equ 0x10 ; HSYNC interrupt (falling edge) -GIME_IVBORD equ 0x08 ; VSYNC interrupt (falling edge) -GIME_ISERIAL equ 0x04 ; Falling edge of signal on pin 4 of serial port -GIME_IKEYBOARD equ 0x02 ; Interrupt if a 0 bit appears on bits 6-0 of PIA0.DA -GIME_ICART equ 0x01 ; Interrupt on falling edge of pin 8 of cartridge port -; GIME VMODE -GIME_BP equ 0x80 ; enable bit plane mode -GIME_BPI equ 0x20 ; colour burst phase inversion (composite output only) -GIME_MONO equ 0x10 ; disable colour burst (composite output only) -GIME_H50 equ 0x08 ; set to 50Hz operation -GIME_LPR1 equ 0x00 ; one line per row -GIME_LPR2 equ 0x02 ; two lines per row (also works on graphics) -GIME_LPR8 equ 0x03 ; 8 lines per row -GIME_LPR9 equ 0x04 ; 9 lines per row -GIME_LPR10 equ 0x05 ; 10 lines per row -GIME_LPR11 equ 0x06 ; 11 lines per row -GIME_LPRINF equ 0x07 ; "infinite" lines per row -; GIME VRES -GIME_LPF192 equ 0x00 ; 192 lines on screen -GIME_LPF200 equ 0x40 ; 200 lines on screen (actually 199 due to hardware bug) -GIME_LPF225 equ 0x60 ; 225 lines on screen -GIME_BPR16 equ 0x00 ; 16 bytes per row -GIME_BPR20 equ 0x04 ; 20 bytes per row -GIME_BPR32 equ 0x08 ; 32 bytes per row -GIME_BPR40 equ 0x0c ; 40 bytes per row -GIME_BPR64 equ 0x10 ; 64 bytes per row -GIME_BPR80 equ 0x14 ; 80 bytes per row -GIME_BPR128 equ 0x18 ; 128 bytes per row -GIME_BPR160 equ 0x1c ; 160 bytes per row -GIME_TXT32 equ 0x00 ; 32 characters per row -GIME_TXT40 equ 0x04 ; 40 characters per row -GIME_TXT64 equ 0x10 ; 64 characters per row -GIME_TXT80 equ 0x14 ; 80 characters per row -GIME_BPP1 equ 0x00 ; 1 bit per pixel -GIME_BPP2 equ 0x01 ; 2 bits per pixel -GIME_BPP4 equ 0x02 ; 4 bits per pixel -GIME_TXTATTR equ 0x01 ; text attributes enabled - endc - ifdef COCO3 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Stuff on the fixed memory page - org 0xfe00 - rmb 0xed ; unused -INT.FLAG rmb 1 ; validity flag -INT.SWI3 rmb 3 ; SWI3 bounce vector -INT.SWI2 rmb 3 ; SWI2 bounce vector -INT.FIRQ rmb 3 ; FIRQ bounce vector -INT.IRQ rmb 3 ; IRQ bounce vector -INT.SWI rmb 3 ; SWI bounce vector -INT.NMI rmb 3 ; NMI bounce vector - endc -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Hardware definitions for the I/O page - org 0xff00 -PIA0 equ * ; Keyboard PIA -PIA0.DA rmb 1 ; PIA0 data/direction A -PIA0.CA rmb 1 ; PIA0 control A -PIA0.DB rmb 1 ; PIA0 data/direction B -PIA0.CB rmb 1 ; PIA0 control B - rmb 28 ; mirror images of PIA0 -PIA1 equ * ; DA/misc stuff -PIA1.DA rmb 1 ; PIA1 data/direction A -PIA1.CA rmb 1 ; PIA1 control A -PIA1.DB rmb 1 ; PIA1 data/direction B -PIA1.CB rmb 1 ; PIA1 control B - rmb 28 ; mirror images of PIA1 - rmb 16 ; SCS/Disk controller - rmb 16 ; second half of SCS area - rmb 32 ; miscelaneous hardware - ifdef COCO3 - rmb 16 ; *reserved* (unused but the GIME drives them) -GIME.INIT0 rmb 1 ; basic GIME system config -GIME.INIT1 rmb 1 ; MMU task and timer rate -GIME.IRQ rmb 1 ; GIME IRQ enable/status register -GIME.FIRQ rmb 1 ; GIME FIRQ enable/status register -GIME.TIMER rmb 2 ; GIME programmable timer - rmb 2 ; *reserved* -GIME.VMODE rmb 1 ; GIME video mode setting -GIME.VRES rmb 1 ; GIME video resolution setting - rmb 1 ; *reserved* (used for MMU expansion on some memory boards) -GIME.BORDER rmb 1 ; GIME border colour -GIME.VSCROLL rmb 1 ; vertical scroll offset register/VDG screen mode variation -GIME.VOFFSET rmb 2 ; address of video memory (8 byte increments) -GIME.HOFFSET rmb 1 ; horizontal scroll offset -GIME.MMU equ * ; MMU registers (two tasks) -GIME.MMU0 rmb 8 ; MMU task 0 -GIME.MMU1 rmb 8 ; MMU task 1 -GIME.PALETTE rmb 16 ; Palette registers - else - rmb 64 ; unused on Coco 1/2 (GIME on Coco 3) - endc -SAMREG equ * ; the SAM configuration register -SAM.V0CLR rmb 1 ; SAM video mode bits -SAM.V0SET rmb 1 -SAM.V1CLR rmb 1 -SAM.V1SET rmb 1 -SAM.V2CLR rmb 1 -SAM.V2SET rmb 1 -SAM.F0CLR rmb 1 ; SAM screen address bits -SAM.F0SET rmb 1 -SAM.F1CLR rmb 1 -SAM.F1SET rmb 1 -SAM.F2CLR rmb 1 -SAM.F2SET rmb 1 -SAM.F3CLR rmb 1 -SAM.F3SET rmb 1 -SAM.F4CLR rmb 1 -SAM.F4SET rmb 1 -SAM.F5CLR rmb 1 -SAM.F5SET rmb 1 -SAM.F6CLR rmb 1 -SAM.F6SET rmb 1 -SAM.P1CLR rmb 1 ; SAM "page 1" selection (or extra memory type flag) -SAM.P1SET rmb 1 -SAM.R0CLR rmb 1 ; SAM R0 bit (address dependent speedup, not used on Coco3) -SAM.R0SET rmb 1 -SAM.R1CLR rmb 1 ; SAM R1 bit (full speedup/coco 3 speedup) -SAM.R1SET rmb 1 -SAM.M0CLR rmb 1 ; SAM M0/M1 bits (memory type, not used on Coco3) -SAM.M0SET rmb 1 -SAM.M1CLR rmb 1 -SAM.M1SET rmb 1 -SAM.TYCLR rmb 1 ; force ROM mode (map type 0) -SAM.TYSET rmb 1 ; set RAM mode (map type 1) - rmb 18 ; *MPU reserved* -CPU.SWI3 rmb 2 ; CPU SWI3 vector -CPU.SWI2 rmb 2 ; CPU SWI2 vector -CPU.FIRQ rmb 2 ; CPU FIRQ vector -CPU.IRQ rmb 2 ; CPU IRQ vector -CPU.SWI rmb 2 ; CPU SWI vector -CPU.NMI rmb 2 ; CPU NMI vector -CPU.RESET rmb 2 ; CPU RESET/startup vector -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Start of memory which has the direct page and other data. - org 0 -dpstart equ * ; start of direct page -zero rmb 2 ; constant zero word used for faster zeroing of 16 bit registers -binval rmb 2 ; arbitary binary value, usually a line number or integer -memtop rmb 2 ; absolute top of memory in 64K memory map -memsize rmb 2 ; top of memory not reserved -freetop rmb 2 ; top of free memory (bottom of string space) -stringtab rmb 2 ; bottom of used string space -stackptr rmb 2 ; bottom of the "stack frame" stack (the actual stack is below here) -progtext rmb 2 ; pointer to start of program text -vartab rmb 2 ; pointer to start of integer scalars -objecttab rmb 2 ; pointer to start of arrays and other variable sized objects -freestart rmb 2 ; pointer to start of unallocated memory -readlinenoecho rmb 1 ; if nonzero, the readline routine won't echo its input -console_curptr rmb 2 ; current cursor pointer for console driver -console_blnkdel rmb 1 ; cursor blink delay -console_truelc rmb 1 ; set to nonzero if the console supports true lower case (gfx, etc.) -filenum rmb 1 ; current input/output channel -fileeof rmb 1 ; flag for whether last read detected EOF -keyb_flags rmb 1 ; shift flags for the keyboard -keyb_joystate rmb 1 ; joystick button state -keyb_repdel rmb 1 ; repeat delay -keyb_curscan rmb 1 ; current repeating scan code -keyb_buffw rmb 2 ; keyboard ring buffer write pointer -keyb_buffr rmb 2 ; keyboard ring buffer read pointer -curline rmb 2 ; pointer to current line -contline rmb 2 ; pointer to line for CONT -contstmt rmb 2 ; interpretation pointer for CONT -curstmt rmb 2 ; start of statement currently being interpreted -endflag rmb 1 ; 00 = END, FF = STOP -stringstackptr rmb 2 ; anonymous string descriptor stack pointer -tok_skipkw rmb 1 ; flag for when skipping an unrecognized keyword -tok_skipdt rmb 1 ; flag for when processing DATA -tok_kwtype rmb 1 ; primary/secondary type flag for tokens -tok_kwnum rmb 1 ; the actual token number -tok_kwmatchl rmb 1 ; the length of the best match during lookup -tok_kwmatch rmb 2 ; the current best matched token number -val0 rmb val.size ; value accumulator 0 -val1 rmb val.size ; value accumulator 1 - rmb 0x71-* ; align RSTFLG/RSTVEC for stock ROM compatibility -RSTFLG rmb 1 ; 0x55 if RSTVEC is valid -RSTVEC rmb 2 ; points to warm start routine (must start with NOP) -inputptr rmb 2 ; pointer to current program execution location - rmb 0x100-* ; make sure the stuff that isn't direct page is outside of it -SW3VEC rmb 3 ; SWI3 vector (for compatibility) -SW2VEC rmb 3 ; SWI2 vector (for compatibility) -SWIVEC rmb 3 ; SWI vector (for compatibility) -NMIVEC rmb 3 ; NMI vector (for compatibility) -IRQVEC rmb 3 ; IRQ vector (for compatibility) -FRQVEC rmb 3 ; FIRQ vector (for compatibility) -keyb_state rmb 8 ; rollover table state -keyb_buff rmb keyb_bufflen ; the keyboard ring buffer -linebuff rmb linebuffsize ; the line input buffer -tokebuff rmb linebuffsize+50 ; make it as long as line buffer plus a margin -stringstack rmb 5*stringstacknum ; reserve space for the anonymous string descriptor stack -stringstackend equ * ; end of string stack buffer - ifne *&0x1ff - rmb 0x200-(*&0x1ff) - endc -textscreen rmb 0x200 ; the actual text screen (must be on 512 byte alignment) -heapstart equ * ; start of dynamically allocated stuff -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; The heap has the following items in order: -; -; Program text: preceded by a NUL and pointed to by progtext -; Variable table: pointed to by vartab; contains records for all scalar and array variables -; Free space: unused memory between the object table and the stack; pointed to by freestart -; The stack: grows downward from the bottom of string space, pointed to by the stack pointer, obviously -; String space: garbage collected non-constant string data pointed to by freetop -; Reserved memory: immediately above string space; pointed to by memsize -; Actual top of RAM: top of reserved memory; pointed to by memtop -; -; The variable table consists of several symbol tables defined as follows: -; -; Pointer Size of entry Variable types -; vartabint 4 Integer scalars -; vartablong 6 Long integer scalars -; vartabfloat 7 Floating point scalars -; vartabstring 6 String scalars -; -; Each entry starts with 2 bytes for the variable name followed by the data payload. org 0x8000 ; the hardware puts the ROMs here; it's not negotiable ROMSTART equ * -START orcc #0x50 ; make sure interrupts are disabled if we come here in an unusual way - ifdef COCO3 - ldu #gime_inite ; point to end of GIME initializer - ldx #GIME.INIT0+(gime_inite-gime_init) ; point to end of GIME registers - ldb #gime_inite-gime_init ; number of bytes to transfer -initc0 lda ,-u ; copy byte to GIME (count down so we init MMU before turning it on) - sta ,-x - decb ; done? - bne initc0 ; brif not - endc - ldd #0xff34 ; initizer for below - tfr a,dp ; set DP to I/O page - setdp 0xff ; tell assembler about DP value - clr PIA0.CA ; set PIA0 A to direction mode - clr PIA0.CB ; set PIA0 B to direction mode - clr PIA0.DA ; set PIA0 A to all inputs (comparator, keyboard rows) - sta PIA0.DB ; set PIA0 B to all outputs (keyboard columns) - stb PIA0.CA ; set PIA0 A to data mode, interrupt disabled, MUX to source 0 - stb PIA0.CB ; set PIA0 B to data mode, interrupt disabled, MUX to source 0 - clr PIA1.CA ; set PIA1 A to direction mode - clr PIA1.CB ; set PIA1 B to direction mode - deca ; set PIA1 A bits 7-1 output (DAC, RS232), 0 input (cassette) - sta PIA1.DA - lda #0xf8 ;* set PIA1 B bits 7-3 output (VDG stuff), 2-0 input (single bit sound, - sta PIA1.DB ;* RS232 input, ram size input) - stb PIA1.CA ; set PIA1 A to data mode, interrupt disabled, cassette motor off - stb PIA1.CB ; set PIA1 B to data mode, interrupt disabled, sound off - lda #2 ; set RS232 output to "marking" (stop bit) - sta PIA1.DA - lda #16 ; clear 16 SAM register bits - ldu #SAMREG ; point to SAM register bits -init0 sta ,u++ ; clear SAM bit - deca ; done all? - bne init0 ; brif not -; set the SAM to point to the text screen, which the code will handle at any -; arbitrary 512 byte aligned address in memory - ifne (textscreen)&0x200 - sta SAM.F0SET - endc - ifne (textscreen)&0x400 - sta SAM.F1SET - endc - ifne (textscreen)&0x800 - sta SAM.F2SET - endc - ifne (textscreen)&0x1000 - sta SAM.F3SET - endc - ifne (textscreen)&0x2000 - sta SAM.F4SET - endc - ifne (textscreen)&0x4000 - sta SAM.F5SET - endc - ifne (textscreen)&0x8000 - sta SAM.F6SET - endc - ifdef COCO2B -; The following SAM configuration sequence is different from the one in the usual -; one used by the earlier models of the Coco because the Coco2B has the '785 variant -; of the SAM instead of the '783 variant. The '785 variant supports 16Kx4 RAMs which -; are used in Coco2B systems. Hence why there is a different version of this ROM -; just for the Coco2B. - clr PIA0.DB ; strobe RAM size low - ldb #4 ; is input low? - bitb PIA1.DB - beq init1 ; brif not - sta SAM.M0SET ; program SAM for 16Kx4 RAMs - sta SAM.P1SET - skip2 -init1 sta SAM.M1SET ; program SAM for 64Kx1 RAMs - else - ifndef COCO3 -; Detect the installed memory size so the SAM ('783 variant) can be correctly -; programmed for the installed memory. Note that this sequence is replaced with -; a different one for the Coco2B which has the '785 variant of the SAM. - ldb #0xff ; strobe RAM size high - stb PIA0.DB - ldb #4 ; mask for ram size check - bitb PIA1.DB ; is the bit set on ram size input? - beq init2 ; brif not - 4Kx1 RAMs - sta PIA0.DB ; clear RAM size output to see what happens (A is 0 from above) - bitb PIA1.DB ; is it set now? - beq init1 ; brif not - 64Kx1 RAMs - leau -2,u ; adjust pointer so we set the other RAM size bit for the SAM (16Kx1) -init1 sta -3,u ; set M0 (16Kx1) or M1 (64Kx1) - endc - endc -init2 tfr a,dp ; set DP to bottom of memory (A is 0 from above) - setdp 0 ; tell assembler about it - lds #textscreen ; put the stack just below the text screen - ifdef COCO3 -; Check if we need to do a ROM/RAM copy, which will happen if the interrupt vectors are -; not flagged valid OR the reset vector isn't valid - ldb INT.FLAG ; are the bounce vectors valid? - cmpb #0x55 - bne initc4 ; brif not - do ROM/RAM copy - ldb RSTFLG ; is reset vector valid? - bne initc2 ; brif not - check secondary location - ldx RSTVEC ; get reset vector - ldb ,x ; is it valid?\ - cmpb #0x12 - bne initc2 ; brif not -initc1 jmp ,x ; transfer control to warm start routine -initc2 clr GIME.MMU0 ; check again with block 0 in the direct page - ldb RSTFLG ; get new RSTFLG - cmpb #0x55 ; valid? - bne initc3 ; brif not - ldx RSTVEC ; get new RSTVEC - ldb ,x ; is it valid? - cmpb #0x12 - beq initc1 ; brif so - transfer control -initc3 ldb #0x38 ; restore MMU - stb GIME.MMU0 -initc4 ldx #initc6 ; point to helper - ldu #textscreen ; point to text screen - ldb #initc7-initc6 ; bytes to copy -initc5 lda ,x+ ; copy byte - sta ,u+ - decb ; done? - bne initc5 ; brif not - ldu #0x8000 ; point to start of ROM - jmp textscreen ; transfer control to helper in RAM -initc6 sta SAM.TYCLR ; drop to ROM mode - pulu d,x,y,s ; grab 8 bytes - sta SAM.TYSET ; go to RAM mode - pshu d,x,y,s ; stick the bytes in RAM - leau 8,u ; move to next 8 bytes - cmpu #0xfe00 ; end of stuff to copy? - blo initc6 ; brif not - jmp initc7 ; go back to mainline -initc7 lds #textscreen ; reset stack to somewhere safe - lda #0x12 ; activate ROM warm start handler - sta warmstart - ldx #INT.FLAG ; point to bounce vector destination - ldu #int_init ; point to initializer for bounce vectors - ldb #int_inite-int_init ; number of bytes to copy -initc8 lda ,u+ ; copy byte - sta ,x+ - decb ; done? - bne initc8 ; brif not -; now recheck for warm start in case ROM/RAM copy made things valid - endc - ldb RSTFLG ; is the reset vector valid? - cmpb #0x55 - bne coldstart ; brif not - do cold start - ldx RSTVEC ; get warm start routine pointer - ldb ,x ; does it start with NOP? - cmpb #0x12 - bne coldstart ; brif not - do cold start - jmp ,x ; transfer control to warm start routine - ifdef COCO3 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; GIME register initializer -gime_init fcb GIME_COCO|GIME_MMUEN|GIME_FExx|GIME_SCS|GIME_ROMI32 ; enable MMU, SCS, constant page, internal ROM - fcb GIME_TASK0 ; use MMU task 0 - fcb 0 ; do not enable IRQ sources - fcb 0 ; do not enable FIRQ sources - fdb 0xfff ; set timer to max value - fdb 0 ; *reserved placeholder* - fcb 0,0,0,0 ; SG4 screen settings with black border - fcb 0x0f,0xe0,0x00,0x00 ; (puts screen in bottom 64K of memory) - fcb 0x38,0x39,0x3a,0x3b ; MMU task 0 (bottom of top 64K of RAM) - fcb 0x3c,0x3d,0x3e,0x3f ; (ROM shadow must be in 3c...3f) - fcb 0x38,0x39,0x3a,0x3b ; MMU task 1 (copy of task 0) - fcb 0x3c,0x3d,0x3e,0x3f - fcb 18,54,9,36,63,27,45,38 ; palette values (RGB) - fcb 0,18,0,63,0,18,0,38 -gime_inite equ * -int_init fcb 0x55 ; vectors valid flag - jmp SW3VEC ; bounce to stock ROM compatibility vector - jmp SW2VEC ; bounce to stock ROM compatibility vector - jmp FRQVEC ; bounce to stock ROM compatibility vector - jmp IRQVEC ; bounce to stock ROM compatibility vector - jmp SWIVEC ; bounce to stock ROM compatibility vector - jmp NMIVEC ; bounce to stock ROM compatibility vector -int_inite equ * - endc -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Cold start handling -coldstart ldx #dpstart ; point to start of direct page - ldd #0 ; set up for blanking -coldstart0 std ,x++ ; blank a couple of bytes - cmpx #textscreen ; end of low memory? - blo coldstart0 ; brif not - ifndef COCO3 -; This is the memory size detection sequence. This runs through memory starting at the bottom of memory -; and stops when it reaches something that can't be modified successfully. This is basically the same -; algorithm used by the stock ROM. It takes less space than doing a more pointed set of probes. The end -; result will be X pointing to the byte one below the top of RAM. This is intentional to ensure there -; is one writeable byte at the top of string space. Note that X will point to the byte after the end -; of the text screen when we get here. - ldx #heapstart ; point to start of heap -coldstart1 lda 2,x ; get original value at test location - coma ; invert all bits - sta 2,x ; write it to the memory location - cmpa 2,x ; did it take? - bne coldstart2 ; brif not - com 2,x ; restore memory byte - leax 1,x ; move pointer forward - bra coldstart1 ; go check next byte - else -; For the Coco3, we do not need to concern ourselves about where the top actual memory is so we don't -; bother doing a memory scan in the default 64K memory map. Because we always run from RAM, we can actually -; set the top of memory to the actual top of the 32K space without having to ensure there is an extra byte -; available above the string space. - ldx #ROMSTART-1 ; point to top of memory - endc -coldstart2 stx memtop ; save absolute top of memory - stx memsize ; save top of unreserved memory - stx stringtab ; mark string space as empty - leax -200,x ; allocate 200 bytes of string space - stx freetop ; save top of free memory - clr ,-x ; make a hole for the "end of call stack" flag - stx stackptr ; save the new call stack pointer - leas ,x ; put the actual stack below the above - ldx #heapstart ; point to start of free memory - clr ,x+ ; put a NUL before the start of the program - stx progtext ; put the start of the program there - clr ,x+ ; put a NULL pointer to mark end of program - clr ,x+ - stx vartab ; put start of integer variables at end of program - stx objecttab ; also put the start of large objects there - stx freestart ; mark the start of free memory - lda #keyb_caps ; enable caps lock but disable all other shift states - sta keyb_flags - ldx #warmstart ; set up warm start handler - stx RSTVEC - lda #0x55 ; activate warm start handler - sta RSTFLG - ldd #0x7e3b ; opcodes for JMP extended and RTI - ldx #irqhandler ; enable IRQ handler with a JMP at the vector - sta IRQVEC - stx IRQVEC+1 - sta FRQVEC ; initialize FIRQ handler with JMP - ldx #firqhandler - stx FRQVEC+1 - stb NMIVEC ; initialize NMI to RTI - stb SW3VEC ; initialize SWI3 to RTI - stb SW2VEC ; initialize SWI2 to RTI - stb SWIVEC ; initialize SWI to RTI - ldx #greeting ; display greeting - jsr console_outstr - bra warmstartb ; finish up initialization -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Warm start handling - ifdef COCO3 -warmstart fcb 0xff ; set to 0xff to force ROM/RAM copy on reset - else -warmstart nop ; flag warm start routine as valid - endc - jsr console_clear ; clear screen - clr filenum ; reset I/O channel to the screen -warmstartb jsr keyb_reset ; reset the keyboard - lda #0x35 ; enable VSYNC interrupt in PIA - sta PIA0.CB - andcc #0xaf ; enable interrupts at the cpu - jmp immediate ; go start immediate mode -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; System startup message -; (start with form feed to clear screen; saves 2 bytes over 'jsr console_clear' in cold start) -greeting fcc '\fLWBASIC VERSION 2022.0\r\n' - fcc 'COPYRIGHT (C) 2022 BY LOST\r\n' - fcc 'WIZARD ENTERPRISES INC.\r\n' - fcn '\n' -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Check for BREAK; this needs to check the keyboard directly instead of just using the usual key fetching routine so -; we don't interfere with keyboard buffering if BREAK isn't pressed. We also need to scan the keyboard directly for this -; so we react even if the keyboard buffer is full. If BREAK is pressed, the keyboard buffer is emptied. -breakcheck lda #0xfb ; strobe column for BREAK - sta PIA0.DB - clra ; clear carry for no BREAK - lda PIA0.DA ; read rows - bita #0x40 ; is BREAK down? - bne breakcheck0 ; brif not - check for SHIFT-@ - sync ; wait for interrupt to scan keyboard - bsr keyb_clearbuff ; reset keyboard buffer - coma ; flag BREAK -breakcheck1 rts -breakcheck0 lda #0x7f ; check for SHIFT - sta PIA0.DB - lda PIA0.DA - bita #0x40 ; shift? - bne breakcheck1 ; brif not - lda #0xfe ; check for @ - sta PIA0.DB - lda PIA0.DA - bita #1 ; @? - bne breakcheck1 ; brif not - bsr keyb_clearbuff ; clear buffer -breakcheck2 sync ; wait for keyboard to actually be scanned - bsr keyb_getkey - bcs breakcheck2 ; brif no key down - bra breakcheck ; go do the break/pause check dance again -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Empty the keyboard buffer -keyb_clearbuff ldx #keyb_buff ; point to start of buffer - stx keyb_buffr ; set both pointers to the start - stx keyb_buffw - rts -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; IRQ handler -; -; Note that the interrupt flag in the PIA is cleared at the start of the interrupt handler. That means that if it takes -; a long time to process this interrupt, or processing this interrupt was delayed somewhat, it is far less likely that -; an interrupt gets missed. In that case, we may end up re-interrupting immediately on RTI, but it should reduce the -; number of missed interrupts. -irqhandler lda PIA0.CB ; was it VSYNC? - bmi irqhandler0 ; brif so - lda PIA0.DA ; clear HSYNC flag so we don't get stuck if it gets enabled - ifdef COCO3 - lda GIME.IRQ ; clear GIME IRQ state flags - endc - rti -irqhandler0 lda PIA0.DB ; clear VSYNC flag - clra ; make sure DP is pointing to the right place - tfr a,dp - lda console_blnkdel ; is the cursor blinking? - beq irqhandler1 ; brif not - dec console_blnkdel ; time to cycle cursor? - bne irqhandler1 ; brif not - lda #console_curdel ; reset blink counter - sta console_blnkdel - lda [console_curptr] ; get character at cursor - adda #0x10 ; move to next colour - ora #0x8f ; force it to be a full 4x4 colour block - sta [console_curptr] ; update cursor on screen -irqhandler1 bsr keyb_read ; go handle the keyboard - rti -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; FIRQ handler -; -; This handler is present to prevent accidentally enabling the interrupt and thus hanging to system. It may seem to be -; a waste of code space, but consider it a self defense situation. -firqhandler pshs a ; need a scratch register - ifdef COCO3 - lda GIME.FIRQ ; clear GIME FIRQ state flags - endc - lda PIA1.DA ; clear interrupt flags - lda PIA1.DB - lda PIA1.CA ; disable interrupts to prevent system hang - anda #0xfe - sta PIA1.CA - lda PIA1.CB - anda #0xfe - sta PIA1.CB - puls a ; restore register - rti -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Console keyboard input driver -; -; Reset the keyboard state, which means clearing the buffer and state flags -keyb_reset bsr keyb_clearbuff ; clear keyboard buffer - lda keyb_flags ; reset keyboard state flags but keep capslock - anda #keyb_caps - sta keyb_flags - clr keyb_joystate ; clear joystick button state - clr keyb_curscan ; stop any keyboard repeating - ldx #0xffff ; mark all key state as "unpressed" - stx keyb_state - stx keyb_state+2 - stx keyb_state+4 - stx keyb_state+6 - rts -; Read character from keyboard ring buffer; return with C set if buffer empty; this doesn't actually need to have -; interrupts disabled because the interrupt only ever updates the write pointer and then only to increase it. As a -; result, worst case is that we don't detect the contents added to the buffer on this call and have to wait for the -; next. -keyb_getkey pshs x ; save register - ldx keyb_buffr ; get read pointer - cmpx keyb_buffw ; same as write pointer? - bne keyb_getkey0 ; brif not - we have a result - coma ; set carry for empty buffer - puls x,pc ; restore register and return -keyb_getkey0 lda ,x+ ; get character from buffer - cmpx #keyb_buff+keyb_bufflen ; did we run off end of buffer? - blo keyb_getkey1 ; brif not - ldx #keyb_buff ; reset to start -keyb_getkey1 stx keyb_buffr ; save new read pointer - andcc #0xfe ; flag key retrieved - puls x,pc ; restore register and return -; The PIA reading loop is specifically set up to NOT read PIA0.DB to avoid prematurely clearing the VSYNC interrupt flag -; since that could lead to missing interrupts. Reading PIA0.DA will clear the HSYNC interrupt flag but that's less of a -; problem because that interrupt is basically useless. -; -; As a note, doing the PIA read in a loop ends up using an extra 27 CPU cycles for the BCS instruction. However, it -; saves 70 code bytes. The trade off seems worth it in this case. -; -; Once keyboard state is read, we do the following: -; -; * update the state of SHIFT, CTRL, ALT -; * decode all other keys in a loop -keyb_read0a pshs b ; save flag bit - ldb a,y ; get state flag - bitb #0x40 ; did it change state? - bne keyb_read0d ; brif so - puls b,pc ; clean up and return -keyb_read0d andb #0xbf ; flag it as not changed - stb a,y - ldb a,u ; get current modifier state - eorb #0x40 ; flip the state bit - stb a,u ; save new state flags - bitb #0x40 ; Z set if not down - puls b ; get back flag bit - beq keyb_read0b ; brif key is pressed - comb ; invert bit flag - andb keyb_flags ; clear bit in flags - bra keyb_read0c ; finish up -keyb_read0b orb keyb_flags ; set the flag -keyb_read0c stb keyb_flags ; update flags - rts -keyb_read leas -9,s ; make temporary buffer - leay 1,s ; point to temporary state buffer - clra ;* set to 0xff with C clear; start by strobing no columns for joystick - deca ;* then rotate the 0 bit through to do the actual keyboard columns - ldu #keyb_state ; point to end of keyboard state buffer - sta PIA0.DB ; strobe no columns - ldb PIA0.DA ; get joystick button state - stb keyb_joystate ; save it for later when needed - andb #0x7f ; mask off comparator (pretend "button" down) - stb ,s ; save button/comparator state mask - rola ; set up for first column -keyb_read0 sta PIA0.DB ; set column strobe - ldb PIA0.DA ; read row data - eorb ,u+ ; set bits if state changed - andb ,s ; mask off comparator and active buttons - stb ,y+ ; save state change information - rola ; shift to next column - bcs keyb_read0 ; brif we haven't done the last column - sta PIA0.DB ; reset column strobe to none - ldd #0xff00|keyb_shift - bsr keyb_read0a - ldd #0xfc00|keyb_ctrl - bsr keyb_read0a - ldd #0xfb00|keyb_alt - bsr keyb_read0a -keyb_read3 ldd #0x0701 ; initialize bit probe and counter -keyb_read4 leay -1,y ; move pointers to next byte - leau -1,u -keyb_read5 bitb ,y ; did this key change state? - bne keyb_read7 ; brif so -keyb_read6 adda #8 ; adjust scan code - lslb ; shift bit probe - bpl keyb_read5 ; brif we haven't done all bits - ldb ,y ; update state flags for this byte - eorb ,u - stb ,u - ldb #1 ; reset bit probe - anda #0x07 ; reset scan code - deca ; adjust for next column - bpl keyb_read4 ; brif not - do another - leas 9,s ; clean up stack - ldb keyb_curscan ; is key repeating? - bne keyb_read9 ; brif so -keyb_reada rts -keyb_read7 bitb ,u ; get current state - bne keyb_read8 ; brif key pressed (make) - cmpa keyb_curscan ; is it the currently repeating key? - bne keyb_read6 ; brif not - don't need to do anything - clr keyb_curscan ; clear the current repeat - bra keyb_read6 -keyb_read8 sta keyb_curscan ; set the current scan code that is repeating - pshs d ; save current bit probe and scan code - ldb #keyb_repdeli ; intialize repeat delay - stb keyb_repdel - bsr keyb_tobuff ; decode key to buffer - puls d ; restore scan code and bit probe - bra keyb_read6 ; go handle the next bit -keyb_read9 dec keyb_repdel ; is it time to repeat it? - bne keyb_reada ; brif not - ldb #keyb_repdelr ; reset repeat delay - stb keyb_repdel - lda keyb_curscan ; get current scan code -keyb_tobuff tsta ; @? - beq keyb_tobuff7 ; brif so - cmpa #26 ; is it alpha or @? - bhi keyb_tobuff6 ; brif not - ldb keyb_flags ; get shift flags - bitb #keyb_ctrl|keyb_alt ; ALT or CTRL? - bne keyb_tobuff4 ; brif one or both - ora #0x60 ; make lower case - bitb #keyb_caps ; capslock enabled? - beq keyb_tobuff0 ; brif not - eora #0x20 ; flip to upper case -keyb_tobuff0 bitb #keyb_shift ; shifted? - beq keyb_tobuff1 ; brif not - eora #0x20 ; flip case if shifted -keyb_tobuff1 ldx keyb_buffw ; get write pointer for keyboard buffer - sta ,x+ ; put it in the buffer - cmpx #keyb_buff+keyb_bufflen ; end of buffer? - blo keyb_tobuff2 ; brif not - ldx #keyb_buff ; reset pointer to start -keyb_tobuff2 cmpx keyb_buffr ; did we run into the read pointer? - beq keyb_tobuff3 ; brif so - there wasn't room so don't save pointer - stx keyb_buffw ; update the write pointer -keyb_tobuff3 rts -keyb_tobuff4 bitb #keyb_alt ; is ALT? - beq keyb_tobuff1 ; brif not - scan code is CTRL- code - ora #0x80 ; set bit 7 for "ALT" codes - bitb #keyb_shift ; shifted? - beq keyb_tobuff5 ; brif not - ora #0x20 ; set bit 5 -keyb_tobuff5 bitb #keyb_ctrl ; ctrl? - beq keyb_tobuff1 ; brif not - stash it in the buffer - ora #0x40 ; set bit 6 for "ctrl - bra keyb_tobuff1 ; stash it the buffer -keyb_tobuff6 suba #26 ; codes above 26 down to 1; @ will be 0 -keyb_tobuff7 cmpa #6 ; is it "0"? - bne keyb_tobuff8 ; brif not - ldb keyb_flags ; get shift flags - bitb #keyb_shift|keyb_ctrl ; CTRL-0 or SHIFT-0? - beq keyb_tobuff8 ; brif not - not "capslock" - eorb #keyb_caps ; flip the capslock state - stb keyb_flags -keyb_tobuffa rts ; and don't put it in the buffer -keyb_tobuff8 cmpa #25 ; is it at or above ALT? - blo keyb_tobuff9 ; brif not - suba #2 ; close gap for ALT/CTRL -keyb_tobuff9 ldb #8 ;* 8 codes; multiply by 8 and move to B - mul ;* - ldx #keyb_codetab ; point to special code table - abx ; now X points to the base entry in the table - ldb keyb_flags ; get shift flags - andb #keyb_shift|keyb_ctrl|keyb_alt ; keep only shift/ctrl/alt - lda b,x ; fetch key code - beq keyb_tobuffa ; brif no code to return - bra keyb_tobuff1 ; go stash it in the buffer -; This is the keyboard code table; there are 8 bytes per entry in the following order: -; 0: unmodified -; 1: shift -; 2: ctrl -; 3: ctrl-shift -; 4: alt -; 5: alt-shift -; 6: alt-ctrl -; 7: alt-ctrl-shift -; -; No entries for ALT, CTRL, SHIFT, or letters -keyb_codetab fcb 0x40,0x13,0x40,0x40,0x80,0xa0,0xc0,0xe0 ; @ - fcb 0x5e,0x5f,0x00,0x00,0x00,0x00,0x00,0x00 ; - fcb 0x0a,0x5b,0x00,0x00,0x00,0x00,0x00,0x00 ; - fcb 0x08,0x15,0x00,0x00,0x00,0x00,0x00,0x00 ; - fcb 0x09,0x5d,0x00,0x00,0x00,0x00,0x00,0x00 ; - fcb 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20 ; - fcb 0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 0 (shift/ctrl variants shadowed above) - fcb 0x31,0x21,0x00,0x00,0x00,0x00,0x00,0x00 ; 1 ! - fcb 0x32,0x22,0x00,0x00,0x00,0x00,0x00,0x00 ; 2 " - fcb 0x33,0x23,0x00,0x00,0x00,0x00,0x00,0x00 ; 3 # - fcb 0x34,0x24,0x00,0x00,0x00,0x00,0x00,0x00 ; 4 $ - fcb 0x35,0x25,0x00,0x00,0x00,0x00,0x00,0x00 ; 5 % - fcb 0x36,0x26,0x00,0x00,0x00,0x00,0x00,0x00 ; 6 & - fcb 0x37,0x27,0x00,0x00,0x00,0x00,0x00,0x00 ; 7 ' - fcb 0x38,0x28,0x00,0x00,0x00,0x00,0x00,0x00 ; 8 ( - fcb 0x39,0x29,0x00,0x00,0x00,0x00,0x00,0x00 ; 9 ) - fcb 0x3a,0x2a,0x00,0x00,0x00,0x00,0x00,0x00 ; : * - fcb 0x3b,0x2b,0x00,0x00,0x00,0x00,0x00,0x00 ; ; + - fcb 0x2c,0x3c,0x00,0x00,0x00,0x00,0x00,0x00 ; , < - fcb 0x2d,0x3d,0x00,0x00,0x00,0x00,0x00,0x00 ; - = - fcb 0x2e,0x3e,0x00,0x00,0x00,0x00,0x00,0x00 ; . > - fcb 0x2f,0x3f,0x00,0x00,0x00,0x00,0x00,0x00 ; / ? - fcb 0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d,0x0d ; - fcb 0x0c,0x5c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c ; - fcb 0x03,0x03,0x1b,0x1b,0x9b,0xbb,0xdb,0xfb ; - fcb 0x1c,0x1d,0x1c,0x1d,0x00,0x00,0x00,0x00 ; - fcb 0x1e,0x1f,0x1e,0x1f,0x00,0x00,0x00,0x00 ; -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; Console screen output driver -; -; Clear screen -console_clear ldb #0x60 ; VDG space character - ldx #textscreen ; point to text screen - stx console_curptr ; set cursor pointer to start of screen -console_clear0 stb ,x+ ; blank a character - cmpx #textscreen+0x200 ; end of screen? - blo console_clear0 ; brif not - rts -; Output NUL terminated string -console_outstr0 bsr console_outchr ; output the character -console_outstr lda ,x+ ; get byte from string - bne console_outstr0 ; brif not end of string - rts -; Output NUL terminated string followed by a newline -console_outstrn bsr console_outstr ; output the string - ; fallthrough intentional -; Output a newline (CR LF) -console_outnl lda #0x0d ; do the CR - bsr console_outchr - lda #0x0a ; do the LF - ; fallthrough intentional -; Output a single character to the screen; enter with character in A -console_outchr pshs d,x ; save registers - ldx console_curptr ; get current cursor pointer - cmpa #0x20 ; printable character? - blo console_outchr5 ; brif not - tsta ; is it a graphics block? - bmi console_outchr1 ; brif so - don't do anything to it - cmpa #0x40 ; number or most non-alpha characters? - blo console_outchr0 ; brif so - will need to flip bit 6 - cmpa #0x60 ; upper case? - blo console_outchr1 ; brif so - don't need to do anything to it - anda #0xdf ; clear bit 5 of lower case; moves it to bottom of character set -console_outchr0 eora #0x40 ; flip bit 6 - the "inversion" bit -console_outchr1 sta ,x+ ; stick it on screen -console_outchr2 stx console_curptr ; save new cursor pointer - cmpx #textscreen+0x200 ; end of screen? - blo console_outchr4 ; brif not - leax -32,x ; move pointer back one line - stx console_curptr - ldx #textscreen ; point to start of screen -console_outchr3 ldd 32,x ; get bytes from next line - std ,x++ ; stick them here - cmpx #textscreen+0x1e0 ; at last row? - blo console_outchr3 ; brif not - ldb #0x60 ; space character for VDG screen - bsr console_clear0 ; blank out last row (borrowing screen clear loop) -console_outchr4 puls d,x,pc ; restore registers and return -console_outchr5 cmpa #0x0c ; form feed? - bne console_outchr6 ; brif not - bsr console_clear ; clear screen - puls d,x,pc ; restore registers and return -console_outchr6 cmpa #0x0d ; carriage return? - bne console_outchr7 ; brif not - ldb console_curptr+1 ; get current screen pointer LSB - andb #0xe0 ; reset offset to start of line - stb console_curptr+1 ; save new pointer LSB - puls d,x,pc ; restore registers and return -console_outchr7 cmpa #0x0a ; line feed? - bne console_outchr8 ; brif not - ldx console_curptr ; get cursor pointer - leax 32,x ; move it forward exactly one line - bra console_outchr2 ; go update stuff check for scroll -console_outchr8 cmpa #0x08 ; backspace? - bne console_outchr9 ; brif not - cmpx #textscreen ; at start of screen? - beq console_outchr4 ; brif so - backspace does nothing - leax -1,x ; back up pointer (backspace is non-destructive) - bra console_outchr2 ; go update pointers, etc. -console_outchr9 cmpa #0x09 ; TAB character? - bne console_outchr4 ; brif not - ldb console_curptr ; get LSB of pointer - andb #7 ; 8 space tabs - only keep low 3 bits - lda #0x60 ; space character (tab is destructive) -console_outchra sta ,x+ ; put a space out - incb ; bump counter - cmpb #8 ; at next tab stop? - blo console_outchra ; brif not - bra console_outchr2 ; go update details and check for scroll + *pragmapush list + *pragma nolist + include init.s + include keyb.s + include irq.s + include consscr.s + *pragmapop list ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; General I/O handling package ; diff -r f492fa6f6dc8 -r 2d52cd154ed1 src/vars.s --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/vars.s Sun Aug 06 00:12:29 2023 -0600 @@ -0,0 +1,86 @@ + *pragmapush list + *pragma list +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; Start of memory which has the direct page and other data. + org 0 +dpstart equ * ; start of direct page +zero rmb 2 ; constant zero word used for faster zeroing of 16 bit registers +binval rmb 2 ; arbitary binary value, usually a line number or integer +memtop rmb 2 ; absolute top of memory in 64K memory map +memsize rmb 2 ; top of memory not reserved +freetop rmb 2 ; top of free memory (bottom of string space) +stringtab rmb 2 ; bottom of used string space +stackptr rmb 2 ; bottom of the "stack frame" stack (the actual stack is below here) +progtext rmb 2 ; pointer to start of program text +vartab rmb 2 ; pointer to start of integer scalars +objecttab rmb 2 ; pointer to start of arrays and other variable sized objects +freestart rmb 2 ; pointer to start of unallocated memory +readlinenoecho rmb 1 ; if nonzero, the readline routine won't echo its input +console_curptr rmb 2 ; current cursor pointer for console driver +console_blnkdel rmb 1 ; cursor blink delay +console_truelc rmb 1 ; set to nonzero if the console supports true lower case (gfx, etc.) +filenum rmb 1 ; current input/output channel +fileeof rmb 1 ; flag for whether last read detected EOF +keyb_flags rmb 1 ; shift flags for the keyboard +keyb_joystate rmb 1 ; joystick button state +keyb_repdel rmb 1 ; repeat delay +keyb_curscan rmb 1 ; current repeating scan code +keyb_buffw rmb 2 ; keyboard ring buffer write pointer +keyb_buffr rmb 2 ; keyboard ring buffer read pointer +curline rmb 2 ; pointer to current line +contline rmb 2 ; pointer to line for CONT +contstmt rmb 2 ; interpretation pointer for CONT +curstmt rmb 2 ; start of statement currently being interpreted +endflag rmb 1 ; 00 = END, FF = STOP +stringstackptr rmb 2 ; anonymous string descriptor stack pointer +tok_skipkw rmb 1 ; flag for when skipping an unrecognized keyword +tok_skipdt rmb 1 ; flag for when processing DATA +tok_kwtype rmb 1 ; primary/secondary type flag for tokens +tok_kwnum rmb 1 ; the actual token number +tok_kwmatchl rmb 1 ; the length of the best match during lookup +tok_kwmatch rmb 2 ; the current best matched token number +val0 rmb val.size ; value accumulator 0 +val1 rmb val.size ; value accumulator 1 + rmb 0x71-* ; align RSTFLG/RSTVEC for stock ROM compatibility +RSTFLG rmb 1 ; 0x55 if RSTVEC is valid +RSTVEC rmb 2 ; points to warm start routine (must start with NOP) +inputptr rmb 2 ; pointer to current program execution location + rmb 0x100-* ; make sure the stuff that isn't direct page is outside of it +SW3VEC rmb 3 ; SWI3 vector (for compatibility) +SW2VEC rmb 3 ; SWI2 vector (for compatibility) +SWIVEC rmb 3 ; SWI vector (for compatibility) +NMIVEC rmb 3 ; NMI vector (for compatibility) +IRQVEC rmb 3 ; IRQ vector (for compatibility) +FRQVEC rmb 3 ; FIRQ vector (for compatibility) +keyb_state rmb 8 ; rollover table state +keyb_buff rmb keyb_bufflen ; the keyboard ring buffer +linebuff rmb linebuffsize ; the line input buffer +tokebuff rmb linebuffsize+50 ; make it as long as line buffer plus a margin +stringstack rmb 5*stringstacknum ; reserve space for the anonymous string descriptor stack +stringstackend equ * ; end of string stack buffer + ifne *&0x1ff + rmb 0x200-(*&0x1ff) + endc +textscreen rmb 0x200 ; the actual text screen (must be on 512 byte alignment) +heapstart equ * ; start of dynamically allocated stuff +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; The heap has the following items in order: +; +; Program text: preceded by a NUL and pointed to by progtext +; Variable table: pointed to by vartab; contains records for all scalar and array variables +; Free space: unused memory between the object table and the stack; pointed to by freestart +; The stack: grows downward from the bottom of string space, pointed to by the stack pointer, obviously +; String space: garbage collected non-constant string data pointed to by freetop +; Reserved memory: immediately above string space; pointed to by memsize +; Actual top of RAM: top of reserved memory; pointed to by memtop +; +; The variable table consists of several symbol tables defined as follows: +; +; Pointer Size of entry Variable types +; vartabint 4 Integer scalars +; vartablong 6 Long integer scalars +; vartabfloat 7 Floating point scalars +; vartabstring 6 String scalars +; +; Each entry starts with 2 bytes for the variable name followed by the data payload. + *pragmapop list