Enhanced BASIC on your system by Lee Davison
[Back]
Hardware.
EhBASIC can be made to work on nearly any 6502 system, it requires very little. The system it was developed on is a combination of my SBC and 6551 projects.Memory.
EhBASIC makes extensive use of page zero and some use of page 2. Some areas may be re-used as long as care is taken. Program and variable space is from $0300 up to whatever is available, the more the better. The interpreter can be ROM or RAM based and can be assembled to reside almost anywhere in memory, only minor changes need to be made.Software.
For minimal functionality the interpreter needs only two external routines, a character get routine and a character send routine.How to.For full functionality two other external routines, load and save, along with two interrupt service routines are needed.
Minimal set-up is required, most of the set-up is performed by the interpreter cold start routine.
The interpreter calls the system routines via RAM based vectors and, as long as the requirements for each routine are met, these can be changed on the fly if needs be.Example code.All the routines exit via an RTS.
The routines are ..
Also if you wish to use the ON {IRQ|NMI} commands ..
- Input
- This is a non halting scan of the input device. If a character is ready it should be placed in A and the carry flag set, if there is no character then A, and the carry flag, should be cleared.
- Output
- The character to be sent is in A and should not be changed by the routine. Also on return, the N and Z flags should reflect the character in A.
- Load
- This is entirely system dependant.
- Save
- This is entirely system dependant.
- Irq
- If no other valid interrupt has happened then this routine should, after checking that the interrupt is set-up, set the IRQ interrupt happened flag.
- Nmi
- If no other valid interrupt has happened then this routine should, after checking that the interrupt is set-up, set the NMI interrupt happened flag.
This is for a simple 6502 system with RAM from $0000 to $BFFF, the interpreter in ROM from $C000 to $EFFF (12k), an 6551 ACIA at $F000 and this code in a 2k ROM from $F800 to $FFFF
; Minimum monitor routines for extended BASIC. Has set-up and ; 6551 ACIA code, nothing else. LAB_0000 = $0000 ; BASIC warm start NmiBase = $D8 ; NMI handler flag byte ; = $D9 ; NMI handler addr low byte ; = $DA ; NMI handler addr high byte IrqBase = $DB ; IRQ handler flag byte ; = $DC ; IRQ handler addr low byte ; = $DD ; IRQ handler addr high byte ccflag = $0200 ; BASIC CTRL-C flag, 00 = en, 01 = dis ccbyte = ccflag+1 ; BASIC CTRL-C byte ccnull = ccbyte+1 ; BASIC CTRL-C byte timeout VECCC = ccnull+1 ; ctrl c check vector VECIN = VECCC+2 ; input vector VECOUT = VECIN+2 ; output vector VECLD = VECOUT+2 ; load vector VECSV = VECLD+2 ; save vector IRQ_vec = VECSV+2 ; IRQ/BRK jump NMI_vec = IRQ_vec+$0A ; NMI jump LANGROM = $C000 ; start of BASIC ROM A_rxd = $F000 ; ACIA receive data port A_txd = $F000 ; ACIA transmit data port A_sts = $F001 ; ACIA status port A_res = $F001 ; ACIA reset port A_cmd = $F002 ; ACIA command port A_ctl = $F003 ; ACIA control port *= $F800 ; reset vector points here RESET CLD ; clear decimal mode LDX #$FF ; load byte TXS ; set the stack ; initialise UART (6551 ACIA) STA A_res ; soft reset LDA #$8B ; set specific modes and functions STA A_cmd ; save to command register ; LDA #$1A ; 8-N-1, 2400 baud LDA #$1C ; 8-N-1, 4800 baud ; LDA #$1E ; 8-N-1, 9600 baud STA A_ctl ; set control register ; initialise page 2 variables LDY #PG2_END-PG2_TAB ; byte count PG2_LOOP LDA PG2_TAB-1,Y ; get byte STA VECIN-1,Y ; store in page 2 DEY ; decrement count BNE PG2_LOOP ; loop if not done LAB_SMSG LDA TAB_MSG,Y ; get byte from start-up message JSR OUTPUT ; call output routine INY ; next byte CPY #LAB_END-TAB_MSG-1 ; compare with loop limit BNE LAB_SMSG ; loop if not complete WAIT_LP JSR RINPUT ; call input routine BCC WAIT_LP ; loop if no key AND #$DF ; mask case bit (make upper case) CMP #"W" ; compare with 'W' (warm) BNE LAB_NWRM ; branch if not JMP LAB_0000 ; jump to warm start vector LAB_NWRM CMP #"C" ; compare with 'C' (cold) BNE WAIT_LP ; loop if not JMP LANGROM ; go do BASIC cold start ; now come the required BASIC routines ; scan the input device ; if byte available return carry set and byte in A ; else return carry clear and $00 in A RINPUT LDA A_sts ; get ACIA status AND #$08 ; mask rx buffer full flag CMP #$08 ; is bit set BNE RD_EXIT ; exit with Cb=0 if buffer empty LDA A_rxd ; get byte from ACIA data port (Cb=1) RD_EXIT RTS ; ; wait for ACIA and tx byte ; return sent byte in A and N and Z flags set OUTPUT PHA ; save A OUTLOOP LDA A_sts ; get status byte AND #$10 ; transmit data register empty? BEQ OUTLOOP ; loop if tx buffer full PLA ; restore A, set flags STA A_txd ; save to data port RTS ; ; load BASIC program routine, default (do nothing) SETLOD ; save BASIC program routine, default (do nothing) SETSAV RTS ; ; table of initial values for page 2 PG2_TAB .word RINPUT ; input vector .word OUTPUT ; output vector .word SETLOD ; load vector .word SETSAV ; save vector ; If you want to use the ON {IRQ|NMI} commands you will ; need this interrupt handling code. ; code needed to set the interrupt flags. ; will only set the happened flag the set-up bit is set. IRQ_CODE PHA ; save A LDA IrqBase ; get set-up byte LSR A ; shift bit to right ORA IrqBase ; OR with set-up byte STA IrqBase ; save set-up byte PLA ; restore A RTI NMI_CODE PHA ; save A LDA NmiBase ; get set-up byte LSR A ; shift bit to right ORA NmiBase ; OR with set-up byte STA NmiBase ; save set-up byte PLA ; restore A RTI END_CODE PG2_END ; start-up message TAB_MSG .byte "EhBASIC for 6502 (C) 2001 C/W?" LAB_END *= $FFFA ; 6502 vectors .word NMI_vec ; NMI vector set to BASIC NMI code .word RESET ; RES vector .word IRQ_vec ; IRQ vector set to BASIC IRQ code END