view src/lwbasic.s @ 6:80b9b4503bb4

Adjust Coco 3 default MMU map for stock ROM compatibility It seems sensible to set up the default MMU mapping the same as the stock ROM does. Since the ROM area has to be up at the top of RAM anyway, there's no particular reason not to do that.
author William Astle <lost@l-w.ca>
date Fri, 04 Nov 2022 00:33:38 -0600
parents 80c18925436d
children b898c74f745c
line wrap: on
line source

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; LWBasic Version 0.1
; Copyright © 2022 Lost Wizard Enterprises Incorporated
;
; This is LWBasic, a replacement Basic ROM system for the TRS-80 Color Computer which
; is most definitely not binary compatible with the stock ROMs.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
                *pragmapush list
                *pragma nolist
                *pragma noexpandcond
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;                
; Utility macros
;
; skip next byte; flags preserved
skip1           macro noexpand
                fcb 0x21                        ; opcode for BRN
                endm
; skip next byte and load nonzero to A
skip1lda        macro noexpand
                fcb 0x86                        ; opcode for LDA immediate
                endm
; skip next byte and load nonzero to B
skip1ldb        macro noexpand
                fcb 0xc6                        ; opcoe for LDB immediate
                endm
; skip next 2 bytes; clobbers flags
skip2           macro noexpand
                fcb 0x8c                        ; opcode for CMPX immediate
                endm
                *pragmapop list
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Various constants
                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
                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)
                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)
                rmb 0xee                        ; unused
textscreen      rmb 0x200                       ; the actual text screen (must be on 512 byte alignment)
                org 0x8000                      ; the hardware puts the ROMs here; it's not negotiable
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-SAMREG)-16,u
                endc
                ifne (textscreen)&0x400
                sta (SAM.F1SET-SAMREG)-16,u
                endc
                ifne (textscreen)&0x800
                sta (SAM.F2SET-SAMREG)-16,u
                endc
                ifne (textscreen)&0x1000
                sta (SAM.F3SET-SAMREG)-16,u
                endc
                ifne (textscreen)&0x2000
                sta (SAM.F4SET-SAMREG)-16,u
                endc
                ifne (textscreen)&0x4000
                sta (SAM.F5SET-SAMREG)-16,u
                endc
                ifne (textscreen)&0x8000
                sta (SAM.F6SET-SAMREG)-16,u
                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
                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_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
                fcb 0xfff                       ; set timer to max value
                fdb 0                           ; *reserved placeholder*
                fcb 0,0,0,0                     ; SG4 screen settings with black border
                fcb 0x0f,0x00,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       
                ifndef COCO3
; Need to ensure the vectors are at 0xbff2
                zmb 0xbff2-*                    ; pad ROM up to the vector point
                fdb SW3VEC                      ; SWI3 vector
                fdb SW2VEC                      ; SWI2 vector
                fdb FRQVEC                      ; FIRQ vector
                fdb IRQVEC                      ; IRQ vector
                fdb SWIVEC                      ; SWI vector
                fdb NMIVEC                      ; NMI vector
                fdb START                       ; RESET vector (ROM entry point)
                endc
                ifdef COCO3
                zmb 0xfff2-*                    ; pad ROM to bottom of vectors
                fdb INT.SWI3                    ; SWI3 vector
                fdb INT.SWI2                    ; SWI2 vector
                fdb INT.FIRQ                    ; FIRQ vector
                fdb INT.IRQ                     ; IRQ vector
                fdb INT.SWI                     ; SWI vector
                fdb INT.NMI                     ; NMI vector
                fdb START                       ; RESET vector (ROM entry point)
                else
                zmb 0x10000-*                   ; pad ROM to full size
                endc