* * This routine reads in a double argument, e.g. * ARG > ARG or ARG < ARG * * If the & extension is used in the source arg an * error will be generated. * If the & extension is used in the dest arg, * the subsequent arguments are placed in the * queue. * * A new address mode, () > arg, is now available. * The only routines which can use it are the * operator routines, so it is handled by this * routine. * PARENFLAG DFB 00 ;Parenthesis mode READDOUB LDA #00 STA PARENFLAG LDA LINEBUF,Y ;Check for () mode CMP #'(' BNE :NORMAL :PAREN LDA PARENFLAG BNE :BRA ;No nesting allowed INY JSR NEXTCHAR ;Get rid of any spaces JSR :NORMAL ;Read the inner arguments LDA ERROR BNE :RTS INC PARENFLAG ;Parenthesis mode LDA QSIZE ;Check for & inside the parens BNE :SRCERR LDA LINEBUF,Y ;Check for closing ) CMP #')' :BRA BNE :SRCERR INY JSR NEXTCHAR ;Find the director LDA LINEBUF,Y CMP #'>' ;Must be this one BNE :DESTERR JSR DEST2ARG ;Push dest (arg2) on the stack JSR PUSHARG JMP :LOOP ;And read remaining args into dest :NORMAL JSR READARG LDA ERROR BNE :RTS JSR NEXTCHAR ;Advance to next char BCC :ERR LDA LINEBUF,Y CMP #'&' ;Is this an extension? BNE :WAHKAR JSR SETQ ;Stick arg into queue INY JSR NEXTCHAR BCC :ERR LDA LINEBUF,Y CMP #'#' ;Can't be immediate extension! BNE :NORMAL :DESTERR LDA #16 ;(Extensions are always dests) STA ERROR :RTS RTS :WAHKAR CMP #'>' ;Is this arg source? BNE :WAHKA LDA QSIZE BNE :SRCERR ;Can't have extensions as SRC JSR SETSRC ;Set SOURCE=ARG :LOOP INY ;Advance past the > or & JSR NEXTCHAR BCC :ERR * GENDEST will catch this, and TEST needs it gone. * LDA LINEBUF,Y * CMP #'#' ;No immediate dests * BEQ :DESTERR JSR READARG LDA ERROR BNE :DONE JSR NEXTCHAR ;Maybe there's a & LDA LINEBUF,Y CMP #'&' BNE :CONT JSR SETQ ;If so, then put arg in queue BCC :LOOP ;...and advance! :CONT JMP SETDEST ;(and exit) :SRCERR LDA #22 ;Bad source STA ERROR RTS :WAHKA CMP #'<' BEQ :CONT2 LDA #2 STA ERROR RTS :CONT2 JSR SETDEST INY ;Advance past the < JSR NEXTCHAR BCC :ERR JSR READARG LDA ERROR BNE :DONE JSR NEXTCHAR ;Maybe there's a & LDA LINEBUF,Y CMP #'&' BEQ :SRCERR ;Oops :CONT3 JMP SETSRC ;(and exit) :ERR LDA #14 STA ERROR :DONE RTS * * BMOVE: Move a byte from one location to another * (SRC) -> (DEST) * BMOVE JSR READDOUB ;Read in the arguments LDA ERROR BNE :DONE LDA PARENFLAG BNE BERRY JSR GENSRC ;Now generate the proper code! :QLOOP LDA DINST ;Convert dest instr to STA AND #%10011111 STA DINST JSR GENDEST LDA QSIZE ;Handle extra instructions BEQ :DONE ;that may be in the queue JSR GETQ ;Get address out of queue BCS :DONE ;error on C=1 JSR SETDEST ;Set it as destination JMP :QLOOP :DONE RTS BERRY LDA #22 STA ERROR RTS * * WMOVE: Move a word (two sequential bytes) from * one location to another. This is basically * equivalent to * BMOVE ARG1 > ARG2 * BMOVE ARG1+1 > ARG2+1 * ITEMP DS 1 ;Just a handy temp storage WMOVE JSR READDOUB ;Read in the arguments LDA ERROR BNE :DONE LDA PARENFLAG ;Parenthesis mode not allowed BNE BERRY LDA QSIZE ;Need to be a little trickier STA ITEMP ;so we can reuse addresses. JSR GENSRC ;Now generate the proper code! :QLOOP LDA DINST ;Convert dest instr to STA AND #%10011111 STA DINST JSR GENDEST LDA ITEMP ;Handle extra instructions BEQ :DONE ;that may be in the queue SEC ;Update queue size SBC #6 STA ITEMP JSR DEST2ARG JSR SETQ ;Put current dest into queue JSR GETQ ;Get new address out of queue BCS :DONE ;error on C=1 JSR SETDEST ;Set it as destination JMP :QLOOP :DONE ;Now do the address+1 byte LDA SINST ;Handled differently if LDA # CMP #$A9 BNE :INCADD LDA SHI ;Use the high byte STA SLO JMP :CONT1 :INCADD INC SLO ;Increment the address BNE :CONT1 INC SHI CMP #$A5 ;Zero page mode? BNE :CONT1 ;It is possible that * LDA SINST ;addr equaled $00FF ORA #$08 ;Convert ZP->Absolute STA SINST :CONT1 JSR GENSRC :QLOOP2 ;Instruction is now set up properly INC DLO BNE :CONT2 INC DHI LDA DINST AND #$0F CMP #05 ;ZP? BNE :CONT2 LDA DINST ORA #$08 STA DINST :CONT2 JSR GENDEST LDA QSIZE BEQ :ALLDONE JSR GETQ ;Get address etc. BCS :DONE JSR SETDEST JMP :QLOOP2 :ALLDONE RTS * * The binary operators are all basically identical in * operation. Two variables need to be set up; see * the notes below for WOPER. * * (In particular see why it is DEST oper SRC -> DEST) * MASK DS 1 EXTRAOP DS 1 BOPER JSR READDOUB ;Read in the arguments LDA ERROR BNE :DONE * Because of the way & clauses are handled, the first * address is the first in the queue, and the current * address is the last one read. So we need to fix * that up. JSR DEST2ARG JSR SETQ ;1st arg is at front of queue JSR GETQ JSR SETDEST LDA PARENFLAG ;Check for () mode BEQ :NORMAL JSR SETQ ;Back in the queue JSR PULLARG ;Grab arg off of stack JSR SETDEST :NORMAL JSR GENDEST ;Now generate the proper code! LDA SINST ;Convert dest instr to ADC AND #%00011111 ;or whatever. ORA MASK STA SINST LDA EXTRAOP BEQ :SKIP JSR CODEOUT :SKIP JSR GENSRC ;ADC stuff * LDA #00 ;STA immediately, X is already * STA DXINST ;set correctly, so skip it. LDA PARENFLAG BNE :QCHECK ;Only STA to queue addresses :QLOOP LDA DINST ;Convert instruction to STA AND #%00011111 ORA #%10000000 STA DINST JSR GENDEST ;And STA it to dest. :QCHECK LDA QSIZE ;Handle extra instructions BEQ :DONE ;that may be in the queue JSR GETQ ;Get address out of queue BCS :DONE ;error on C=1 JSR SETDEST ;Set it as destination JMP :QLOOP :DONE RTS * * Since almost all the word operators have 90% of their * code in common, this is now a subroutine. Two variables * need to be set up, MASK and EXTRAOP. MASK is used to * convert LDA to whatever instruction it is supposed to * be, e.g. * LDA INST * AND #$00011111 * ORA MASK * EXTRAOP is for ADC and SBC, and is an extra opcode to * execute (in particular, CLC/SEC). If zero, it is * not output. * * Because of the way in which WSUB works, the roles * of DEST and SRC need to be interchanged; things are * still stored in DEST, but the operation is * DEST SRC -> DEST as opposed to SRC DEST -> DEST * WOPER JSR READDOUB ;Read in the arguments LDA ERROR BNE :DONE JSR DEST2ARG ;Again, make sure first address JSR SETQ ;is first. JSR GETQ JSR SETDEST LDA PARENFLAG ;Check for () mode BEQ :NORMAL JSR SETQ ;Back in the queue JSR PULLARG ;Grab arg off of stack JSR SETDEST ;It will be passed into the queue :NORMAL LDA QSIZE ;Need to be a little trickier STA ITEMP ;so we can reuse addresses. JSR GENDEST ;Start with DEST JSR GENOPER ;Generate ADC xxx STA xxx etc. :QLOOP LDA ITEMP ;Handle extra instructions BEQ :DONE ;that may be in the queue SEC ;Update queue size SBC #8 STA ITEMP JSR DEST2ARG ;DINST -> INST JSR SETQ ;Put current address into queue BCS :RTS JSR GETQ ;Get new address out of queue BCS :RTS ;error on C=1 JSR SETDEST ;Set it as destination LDA DINST ;Convert dest instr to STA AND #%00011111 ORA #%10000000 STA DINST JSR GENDEST JMP :QLOOP :DONE LDA #00 ;Now do the address+1 byte STA EXTRAOP ;No CLC/SEC second time LDA SINST AND #$0F ;Strip away any mask etc. CMP #$09 ;If immediate mode, then use BNE :INCADR ;the high byte. LDA SHI STA SLO JMP :CONT1 :RTS RTS :INCADR INC SLO ;Increment the address BNE :CONT1 INC SHI CMP #$05 ;Zero page mode? BNE :CONT1 ;It is possible that LDA SINST ;addr equaled $00FF ORA #$08 ;Convert ZP->Absolute STA SINST :CONT1 JSR DEST2ARG ;Get correct address back out. JSR SETQ BCS :ALLDONE :NORM2 JSR GETQ ;This is the first addy in the BCS :ALLDONE ;list now JSR SETDEST :NINC INC DLO ;Increment the address BNE :CONT3 INC DHI LDA DINST AND #$0F CMP #$05 ;Zero page mode? BNE :CONT3 ;It is possible that LDA DINST ;addr equaled $00FF ORA #$08 ;Convert ZP->Absolute STA DINST :CONT3 ;Now convert DEST back to LDA LDA DINST AND #$1F ORA #$A0 STA DINST JSR GENDEST JSR GENOPER :QLOOP2 LDA QSIZE BEQ :ALLDONE JSR GETQ ;Instruction is now set up properly BCS :ALLDONE ;i.e. to STA JSR SETDEST INC DLO BNE :CONT2 INC DHI LDA DINST AND #$0F CMP #$05 ;Zero page mode? BNE :CONT2 ;It is possible that LDA DINST ;addr equaled $00FF ORA #$08 ;Convert ZP->Absolute STA DINST :CONT2 JSR GENDEST JMP :QLOOP2 :ALLDONE RTS * * GENOPER generates the ADC xxx STA xxx piece of * code * * It actually does (Operation) SRC STA DEST * GENOPER LDA SINST AND #%00011111 ;Convert to ADC, etc. ORA MASK STA SINST LDA EXTRAOP BEQ :SKIP JSR CODEOUT :SKIP JSR GENSRC LDA PARENFLAG ;Skip STA if required BNE :RTS LDA DINST ;Convert to STA AND #%00011111 ORA #%10000000 STA DINST JSR GENDEST :RTS RTS * * BADD: Add SRC+DEST, result in DEST. * SRC + DEST -> DEST * BADD LDA #%01100000 STA MASK LDA #$18 ;CLC STA EXTRAOP JMP BOPER * * WADD: * SRC + DEST -> DEST * WADD LDA #%01100000 STA MASK LDA #$18 ;CLC STA EXTRAOP JMP WOPER * * BSUB * DEST - SRC -> DEST * BSUB LDA #$E0 STA MASK LDA #$38 ;SEC STA EXTRAOP JMP BOPER * * WSUB * Word subtract * WSUB LDA #$E0 STA MASK LDA #$38 STA EXTRAOP JMP WOPER * * BAND * SRC AND DEST -> DEST * BAND LDA #$20 STA MASK LDA #00 STA EXTRAOP JMP BOPER * * WAND * Word AND * WAND LDA #$20 STA MASK LDA #00 STA EXTRAOP JMP WOPER * * BOR * SRC OR DEST -> DEST * BOR LDA #$00 STA MASK STA EXTRAOP JMP BOPER * * WOR * Word OR * WOR LDA #$00 STA MASK STA EXTRAOP JMP WOPER * * BEOR * SRC EOR DEST -> DEST * BEOR LDA #$40 STA MASK LDA #00 STA EXTRAOP JMP BOPER * * WEOR * Word OR * WEOR LDA #$40 STA MASK LDA #00 STA EXTRAOP JMP WOPER