;***********************************************************************
;*                 B B C   B A S I C   M O S R O M                     *
;*---------------------------------------------------------------------*
;*    doel           : Mosrom v4 voor BBC Basic Interpreter op         *
;*                     Atom-in-PC.                                     *
;*---------------------------------------------------------------------*
;*    filenaam       : bbcmos4.asm                                     *
;*    auteur         : Roland Leurs                                    *
;*                     The Atomic Development Studio                   *
;*    ontwikkeld     : maart 1998                                      *
;*    laatste update :                                                 *
;*---------------------------------------------------------------------*
;*    assembleren    : x6502 BBCMOS4                                   *
;*---------------------------------------------------------------------*
;*    oproep         : Laden als rom, initialiseren als extended reset *
;***********************************************************************

                org     $1000-16

header          .dw     header+16, init
                .dw     0,0,0,0,0,0

;***********************************************************************
;* Definitie van variabelen en constanten                              *
;***********************************************************************

program         equ $2000
mosextrom       equ $A000
systemvia       equ $B810
systemlatch     equ $B888
bbcbasic        equ $C000

clbuffer        equ $100                ; buffer voor *-commando
osvectors       equ $200                ; operating system vectoren
timer           equ $300                ; 10 bytes voor timer informatie


oswordparm      equ $A2                 ; adres parameterblok osword calls
oswordspace     equ $A4                 ; osword werkruimte (5 bytes)
xsave           equ $E4                 ; tijdelijke opslag x-reg o.a. scan
ysave           equ $E5                 ; tijdelijke opslag y-reg o.a. scan
semafoor        equ $FA                 ; semafoor voor pc communicatie
nietprinten     equ $FB                 ; karakter dat niet naar printer mag
irqaccu         equ $FC                 ; accu tijdens irq routine
erroradres      equ $FD                 ; adres laatste brk (2 bytes)
escvlag         equ $FF                 ; escape vlag


;***********************************************************************
;* MOSROM Entry adressen                                               *
;***********************************************************************

irq_entry       jmp irqv                ; spring naar irq/brk routine
nmi_entry       jmp nmiv                ; spring naar nmi routine


;***********************************************************************
;* Initialisatie routine                                               *
;***********************************************************************

init            jsr wissem              ; reset semafoor voor pc communicatie
                ldx #$1D                ; laadt index
initvec         lda vectab,x            ; lees vector inhoud
                sta osvectors+4,x       ; zet in vector gebied
                lda #$00                ; laadt 0
                sta timer,x             ; reset timer
                dex                     ; verlaag index
                bpl initvec             ; spring indien nog vectoren volgen
                sta escvlag             ; clear escape vlag (=&FF)
                txs                     ; reset stack pointer
                lda #$C0                ; writeprotect aan, OSRAM actief
                sta systemlatch
                lda #$0A                ; karakter dat niet naar printer mag
                sta nietprinten
                lda #<bbcbasic+$E       ; zet adres van laatste "foutmelding"
                sta erroradres
                lda #>bbcbasic
                sta erroradres+1
                lda mosextrom           ; test op aanwezigheid van mos ext rom
                cmp #$BE
                bne geenextrom          ; spring indien niet aanwezig
                jsr mosextrom+1         ; spring naar mos ext rom initroutine
geenextrom      lda bbcbasic+$15        ; laadt bbc basic release code
                cmp #'1'                ; test op release 1
                beq bbcmsg              ; spring indien geldige release code
                cmp #'2'                ; test op release 2
                beq bbcmsg              ; spring indien geldige release code
                jsr print               ; druk foutmelding af
                .db 12
                .db "BBC Basic interpreter not found",$0D,$0A
                .db "System halted ",$EA
                lda #$00                ; writeprotect uit
                sta systemlatch
                sta extresvec           ; disable bbc mode, na reset weer Atom
systemhalted    jmp systemhalted        ; geen basic, dan sterf maar af
bbcmsg          jsr print               ; druk welkomstekst af
                .db 22,1,17,3           ; initialeer mode en default kleur
                .db "BBC Basic Issue ",$EA
                lda bbcbasic+$15        ; laadt bbc basic release code
                jsr oswrch              ; druk release code af
                jsr print               ; vervolg met welkomstekst
                .db 13,10,10
                .db "MOS ROM V4.0  releasecode 98030105"
                .db 13,10,$EA
                lda mosextrom           ; test op aanwezigheid van mos ext rom
                cmp #$BE
                bne geenextmsg          ; spring indien niet aanwezig
                jsr mosextrom+4         ; druk mos ext rom melding af
geenextmsg      jsr osnewl              ; cursor naar volgende regel
                lda #$01                ; laadt rom service code
                jmp bbcbasic            ; start basic


;***********************************************************************
;* PC Communicatie routines                                            *
;***********************************************************************

zendv           pha                     ; bewaar byte op stack
                sta systemvia           ; stuur byte naar pc
zendv1          lda systemvia+$D        ; lees statusregister
                and #$10                ; test of byte gelezen is
                beq zendv1              ; spring indien nog niet gelezen
                pla                     ; haal byte weer van stack
                rts                     ; einde routine

leesv           lda systemvia+$D        ; lees statusregister
                and #$02                ; test of byte klaar staat
                beq leesv               ; spring indien geen byte van pc
                lda systemvia+$1        ; lees byte
                rts


;***********************************************************************
;* Console routines                                                    *
;***********************************************************************

; oswrch: schrijf karakter naar beeldscherm
wrchv           cmp #$00                ; test op $0
                bne wrchv1              ; spring indien geen $0
                jsr oszendbyte          ; voor $0 pccom#00 geven 
wrchv1          jmp oszendbyte          ; stuur byte naar pc

; osrdch: lees karakter van toetsenbord
rdchv           jsr scan                ; scan toetsenbord
                cmp #$00                ; toets gedrukt ?
                beq rdchv               ; nee, dan verder wachten
                rts                     ; einde routine

scan            php                     ; save processor status
                stx xsave               ; bewaar gebruikte registers
                sty ysave
                jsr zetsem              ; zet semafoor voor pc communicatie
                ldx #$00                ; default ascii waarde (geen toets)
                lda #$5D                ; geef scan commando aan pc
                jsr pccom
                jsr osleesbyte          ; lees toetsenbord status
                lsr a                   ; schuif toetsvlag in carry
                bcc endscan             ; einde routine als geen toets gedrukt
                jsr osleesbyte          ; lees ascii code van ingedrukte toets
                tax                     ; zet in x register
                jsr osleesbyte          ; lees scancode van ingedrukte toets
                tay                     ; zet in y register
                cpy #$0F                ; test op copy toets (=tab)
                bne scan_bs             ; spring als geen copy toets
                lda #$02                ; pccom $02: lees karakter op cursor
                jsr pccom
                jsr osleesbyte          ; lees resultaat
                tax                     ; zet in x register
                jmp endscan             ; einde routine
scan_bs         cpy #$0E                ; test op backspace toets
                bne scan_cur_u          ; spring indien geen backspace
                ldx #127                ; laadt delete code
                bne endscan             ; spring naar einde routine
scan_cur_u      cpx #$00                ; test op extended code
                bne endscan             ; spring als normale toets gedrukt is
                cpy #$48                ; cursor up?
                bne scan_cur_l          ; spring indien geen cursor up
                ldx #11                 ; laadt code voor cursor up
                bne endscan             ; spring naar einde routine
scan_cur_l      cpy #$4B                ; cursor left?
                bne scan_cur_r          ; spring indien geen cursor left
                ldx #8                  ; laadt code voor cursor left
                bne endscan             ; spring naar einde routine
scan_cur_r      cpy #$4D                ; cursor right?
                bne scan_cur_d          ; spring indien geen cursor right
                ldx #9                  ; laadt code voor cursor right
                bne endscan             ; spring naar einde routine
scan_cur_d      cpy #$50                ; cursor down?
                bne endscan             ; spring indien geen cursor down
                ldx #10                 ; laadt code voor cursor right
endscan         jsr wissem              ; reset semafoor voor pc communicatie
                txa                     ; zet ascii code in accu
                ldx xsave               ; herstel overige registers
                ldy ysave
                plp
                rts                     ; einde scan routine


;***********************************************************************
;* Operating system calls                                              *
;***********************************************************************

bytev           cmp #$1B                ; osbyte &1B
                bne bytev1A
                lsr semafoor            ; schuif semafoorstatus in carry
                rts                     ; einde routine
bytev1A         cmp #$1A                ; osbyte &1A
                bne bytev7E
                jmp wissem              ; ga semafoor wissen
bytev7E         cmp #$7E                ; osbyte &7E
                bne bytev83
                lda #$FF                ; wis escape vlag
                sta escvlag
                rts                     ; einde routine
bytev83         cmp #$83                ; osbyte &83
                bne bytev84
                ldx #<program           ; laadt OSHWM
                ldy #>program
                rts                     ; einde routine
bytev84         cmp #$84                ; osbyte &84
                bne bytevDA
                ldx #<mosextrom-1       ; laadt HIMEM
                ldy #>mosextrom-1
bytevDA0        rts                     ; einde routine
bytevDA         cmp #$DA                ; osbyte &DA
                beq bytevDA0
bytevxx         jmp not_implemented     ; call niet ondersteund


wordv           pha                     ; maak plaats op stack
                pha
                pha
                txa                     ; save registers
                pha
                tya
                pha
                tsx                     ; stack pointer naar x register
                lda $103,x              ; herstel oude accu (=call nummer)
                bmi worderr             ; spring indien ongeldig
                cmp #$0D                ; test op geldige call
                bpl worderr             ; spring indien verkeerd commando
                asl a                   ; verdubbel accu
                tay                     ; zet in indexregister
                sec                     ; set carry voor aftrekken
                lda wordtab,y           ; laadt adres
                sbc #1                  ; trek er 1 af ivm rts instructie
                sta $104,x              ; zet sprongadres op stack
                lda wordtab+1,y
                sbc #0
                sta $105,x
                pla                     ; herstel registers
                tay
                pla
                tax
                pla
                rts                     ; voer routine uit (!)
worderr         jmp not_implemented     ; anders foutmelding geven

wordtab         .dw wordv00, wordv01, wordv02, worderr, worderr
                .dw wordv05, wordv06, wordv07, worderr, worderr
                .dw worderr, worderr, worderr, worderr, worderr
                .dw worderr

; osword $00: Lees regel van standaard input device
wordv00         stx oswordparm          ; zet adres van inputbuffer
                sty oswordparm+1
                ldy #4                  ; laadt index
wordv00_0       lda (oswordparm),y      ; lees parameterblok
                sta oswordspace,y       ; zet in werkruimte
                dey                     ; verlaag index
                bpl wordv00_0           ; spring indien parameters volgen
                iny                     ; y=0
                bpl wordv00_4           ; spring altijd naar wordv00_3
wordv00_1       lda #$7                 ; genereer piepje
                dey                     ; verlaag y
wordv00_2       iny                     ; verhoog y
wordv00_3       jsr oswrch              ; spring naar schrijfroutine
wordv00_4       jsr osrdch              ; lees karakter van toetsenbord
                cmp #127                ; test op delete toets
                bne wordv00_5           ; spring indien geen delete
                cpy #0                  ; test op lege buffer
                beq wordv00_4           ; opnieuw bij delete op lege buffer
                dey                     ; anders pointer verlagen
                bcs wordv00_3           ; verwijder karakter van scherm
wordv00_5       cmp #21                 ; test op cancel (CTRL-U)
                bne wordv00_7           ; spring indien geen cancel
                tya                     ; zet pointer in accu
                beq wordv00_4           ; opnieuw bij cancel op lege buffer
                lda #$7F                ; laadt delete code
wordv00_6       jsr oswrch              ; verwijder karakter
                dey                     ; verlaag index
                bne wordv00_6           ; maak hele buffer leeg
                beq wordv00_4           ; begin opnieuw
wordv00_7       cmp #27                 ; test op escape
                beq wordv00_10          ; sprint naar escaperoutine
                sta (oswordspace),y     ; zet karakter in buffer
                cmp #$0D                ; test op return
                beq wordv00_9           ; spring naar afronding
                cpy oswordspace+2       ; test op maximale input lengte
                bcs wordv00_1           ; spring als buffer vol
                cmp oswordspace+3       ; test op laagste geldige teken
                bcc wordv00_8           ; spring indien ok
                cmp oswordspace+4       ; test op hoogste geldige teken
                beq wordv00_2           ; spring indien gelijk
                bcc wordv00_2           ; spring indien kleiner
wordv00_8       cmp #32                 ; test op spatie
                bcc wordv00_3           ; spring en druk af indien groter
                bcs wordv00_4           ; ga volgende lezen indien kleiner
wordv00_9       jsr osnewl              ; cursor naar volgende regel
                ldx #0                  ; reset x register
                clc                     ; clear carry (geen escape)
                rts                     ; einde routine
wordv00_10      ldx #$FF                ; zet escape vlag
                stx escvlag
                rts                     ; einde routine

; osword $01: lees systeem timer
wordv01         stx oswordparm          ; zet adres van parameterblok
                sty oswordparm+1
                ldy #4                  ; laadt index
wordv01_0       lda timer,y             ; lees timer gegevens
                sta (oswordparm),y      ; zet in parameter
                dey
                bpl wordv01_0           ; spring indien nog bytes volgen
                ldy oswordparm+1        ; herstel y register
                rts                     ; einde routine

; osword $02: zet systeem timer
wordv02         stx oswordparm          ; zet adres van parameterblok
                sty oswordparm
wordv02_0       lda (oswordparm),y      ; lees parameter gegevens
                sta timer               ; zet in timer
                dey
                bpl wordv02_0           ; spring indien nog bytes volgen
                ldy oswordparm+1        ; herstel y register
                rts                     ; einde routine

; osword $05: lees pc geheugen
wordv05         stx oswordspace         ; zet adres van parameterblok
                sty oswordspace+1
                jsr zetsem              ; wacht op pc toegang
                lda #$5B                ; commando $5B
                jsr pccom
                lda #$03                ; subfunctie 3
                jsr oszendbyte
                ldy #0                  ; reset index register
wordv05_0       lda (oswordspace),y     ; laadt offset / segment adres
                jsr oszendbyte          ; stuur naar pc
                iny                     ; verhoog index
                cpy #4                  ; vier bytes verzonden
                bne wordv05_0           ; nee, dan volgende byte sturen
                jsr osleesbyte          ; lees data van pc
                sta (oswordspace),y     ; zet data in parameterblok
                jmp wissem              ; reset semafoor en einde routine

; osword $06: schrijf pc geheugen
wordv06         stx oswordspace         ; zet adres van parameterblok
                sty oswordspace+1
                jsr zetsem              ; wacht op pc toegang
                lda #$5B                ; commando $5B
                jsr pccom
                lda #$04                ; subfunctie 4
                jsr oszendbyte
                ldy #0                  ; reset index register
wordv06_0       lda (oswordspace),y     ; laadt offset / segment adres / data
                jsr oszendbyte          ; stuur naar pc
                iny                     ; verhoog index
                cpy #5                  ; vier bytes verzonden
                bne wordv06_0           ; nee, dan volgende byte sturen
                jmp wissem              ; reset semafoor en einde routine

wordv07         stx oswordparm          ; zet adres van parameterblok
                sty oswordparm+1
                jsr zetsem              ; zet semafoor
                lda #$19                ; geef pc commando
                jsr pccom
                ldy #4                  ; index voor toonhoogte
                lda (oswordparm),y      ; lees toonhoogte
                jsr oszendbyte          ; stuur naar pc
                ldy #6                  ; index voor toonduur
                lda (oswordparm),y      ; lees toonduur
                jsr oszendbyte          ; stuur naar pc
                jmp wissem              ; reset semafoor en einde routine

;***********************************************************************
;* Diversen                                                            *
;***********************************************************************

; print string tot aan negatief byte
print           pla                     ; haal adres van stack
                sta $E8                 ; zet in print pointer
                pla
                sta $E9
print1          ldy #$00                ; reset indexregister
                inc $E8                 ; verhoog pointer
                bne print2              ; spring bij pagina overschreiding
                inc $E9
print2          lda ($E8),y             ; lees karakter
                bmi print3              ; spring indien einde string
                jsr oswrch              ; druk karakter af
                jmp print1              ; ga volgend karakter lezen
print3          jmp ($E8)               ; einde routine


; zet semafoor voor pc communicatie
zetsem          lda #$1B                ; laadt osbyte code
                jsr osbyte
                bcc zetsem              ; blijf dit doen totdat toegang vrij
                rts                     ; einde routine

wissem          lda #01                 ; reset semafoor
                sta semafoor
                rts                     ; einde routine

pccom           pha                     ; save commando nummer
                lda #0                  ; stuur $00 byte
                jsr oszendbyte          ; naar pc
                pla                     ; haal commando nummer weer op
                jmp oszendbyte          ; stuur naar pc

; skip spaties in command line buffer
skipspace0      iny                     ; verhoog command line pointer
skipspace1      lda clbuffer,y          ; lees karakter
                cmp #' '                ; test op spatie
                beq skipspace0          ; volgende lezen bij spatie
                rts                     ; anders einde routine

nmiv            pha                     ; save accu
                jmp (osvectors)         ; spring naar de NMI routine

irqv            sta irqaccu             ; save accu
                pla                     ; haal processor status van stack
                pha                     ; en zet weer terug
                and #$10                ; test interrupt of brk instructie
                bne brkv                ; spring bij een brk instructie
                jmp (osvectors+4)       ; spring naar irq1v bij interrupt

brkv            plp                     ; haal status van stack
                cli                     ; enable interrupts
                cld                     ; clear decimal flag
                pla                     ; haal lsb adres van stack
                sec                     ; zet carry voor aftrekken
                sbc #1                  ; trek er 1 af
                sta erroradres          ; zet low byte van error adres
                pla                     ; haal msb adres van stack
                sbc #0
                sta erroradres+1        ; zet high byte van error adres
                jmp (osvectors+2)       ; spring naar breakhandler

irq1v
irq2v           rti
filev           nop
argsv           nop
bgetv           nop
bputv           nop
gbpbv           nop
findv           nop

not_implemented brk                     ; Not implemented
                .db 255                 ; error 255
                .db "OS call not implemented"
                .db 0


;***********************************************************************
;* Systeemvectoren                                                     *
;***********************************************************************

                org $1FAA

vectab          .dw irq1v,irq2v,not_implemented,bytev,wordv,wrchv
                .dw rdchv, filev,argsv,bgetv,bputv,gbpbv,findv
                .dw leesv, zendv

oszendbyte      jmp (osvectors+$20)
osleesbyte      jmp (osvectors+$1E)
osfind          jmp (osvectors+$1C)
osgbpb          jmp (osvectors+$1A)
osbput          jmp (osvectors+$18)
osbget          jmp (osvectors+$16)
osargs          jmp (osvectors+$14)
osfile          jmp (osvectors+$12)
osrdch          jmp (osvectors+$10)
osasci          cmp #$0D
                bne oswrch
osnewl          lda #$0A
                jsr oswrch
                lda #$0D
oswrch          jmp (osvectors+$0E)
osword          jmp (osvectors+$0C)
osbyte          jmp (osvectors+$0A)
oscli           jmp (osvectors+$08)

                .db "RL",$98
extresvec       .db $F0,<init,>init
