Name : ASM2.S End of file : 64,420 This file was generated using the DiskBrowser utility with minimal editing. It is meant for viewing purposes only. ORG $7800 REP 50 ; EdAsm Interpreter will transfer control here ; Assembler EQU * ;ENTRY ColdStrt JMP ExecAsm ; ; Patch the addr @ this offset with $60 (RTS) ; if user wants to use the letters A,X,Y as labels ; DW IsAXY ;Points to subrtn checking A,X,Y as labels ; DateStr ASC '30-APR-85 22:46' ; ResetEnt JSR GoMon ;Comes here when Apple RESET key is pressed ; ExecAsm JSR SaveZP TSX STX EIStack ;Save EdAsm Interpreter's H/W stack SEI ;Disable H/W interrupts JSR SetupVec JSR InitASM JSR DoPass1 JSR DoPass2 JSR PollKbd ; ; The ProDOS version of EdAsm does not ; support memory resident source file(s). ; CleanUp LDA DskSrcF ;Assembling a mem resident src file? BPL FlushObj ;Yes (Never taken) ; LDX FCTIndex CPX #InclFile BCC CleanUp2 BEQ CleanUp1 LDX #MacFile ;Close Macro file (if any) JSR ClsFile ; CleanUp1 LDX #InclFile ;Close INCLUDE file (if any) JSR ClsFile ; CleanUp2 LDX #ChnFile ;Close CHAIN file (if any) JSR ClsFile ; FlushObj JSR L99DF ;Flush obj code ; ListSymTbl BIT CancelF ;Suppress symbol table listing? BPL ListErrs ;Yes ; LDA EndSymT+1 ;Need to preserve this STA SavSTE ; during calcn # of free pages JSR DoPass3 ;Output symbol table etc JSR PollKbd AbortAsm LDA SavSTE STA EndSymT+1 ;Restore ; ListErrs LDA NbrErrs ;Any errors encountered? ORA NbrErrs+1 BEQ TellUser JSR PrSummry ;Yes ; TellUser JSR PrtEndAsm ;Tell user assembly process is ending ; EndAsm JSR PrtFF ;Do a form feed BIT DskListF ;Listing to file? BPL ExitASM ;No LDX #LstFile JSR ClsFileX ; ExitASM LDX EIStack TXS JSR SaveZP JSR SetupVec RTS REP 50 ; ; Comes here whenever EdAsm.Asm has to do an orderly ; exit as a result of errors which make continuation ; of the assembly process non-feasible ; ; (A)=keycode if PollKbd called prior to ; transfer of control ; CanclAsm INC CancelF ;Flag we have to stop BEQ ForceAbort CMP #CTRLB ;This code may not be executed BCC ListSymTbl BCS ExitASM ;Always ; ForceAbort BIT AbortF ;Was it user abort? BMI AbortNow ;Yes ; LDA #BEL ;Ring, ring JSR VidOut JSR VidOut JSR PrtCR BIT KBDSTROBE LDX #>AbortTxt-ASEndTxt JSR L986A WaitK1 LDA KBD ;Wait for keystroke BPL WaitK1 BIT KBDSTROBE ; AbortNow JSR CountErr ;Increment # of errors JMP CleanUp REP 50 ; SetupVec LDA SOFTEV LDX ResetEnt+1 STA ResetEnt+1 STX SOFTEV LDA SOFTEV+1 LDX ResetEnt+2 STA ResetEnt+2 STX SOFTEV+1 LDA SOFTEV+1 EOR #$A5 STA PWREDUP RTS REP 50 ; ; Comes here when Apple // RESET key ; is pressed during an assembly ; GoMon LDA RDROM2 TSX STX StackP LDX #$80 TXS JMP MONZ REP 50 ; ; We are at the end of an assembly session so print ; 1) # of warnings & errors if any ; 2) success if no errs ; 3) total # of lines assembled ; 4) Date ; 5) # of free pages ; PrtEndAsm JSR PutCR LDA #0 STA BCDNbr+2 LDA NbrWarns STA BCDNbr LDA NbrWarns+1 STA BCDNbr+1 ORA NbrWarns BEQ PrtErrs JSR PrtDecS ;Print BCD as dec str LDX #>WarnTxt-ASEndTxt;# of warnings in assembly JSR MsgPrtr ; PrtErrs LDA NbrErrs+1 STA BCDNbr+1 LDA NbrErrs STA BCDNbr ORA NbrErrs+1 BEQ GudAsm ;No errs JSR PrtDecS LDX #>ASErrTxt-ASEndTxt;# of errors in assembly JSR MsgPrtr JMP PrtCrMsg ; GudAsm LDX #>SuccTxt-ASEndTxt JSR MsgPrtr PrtCrMsg LDX #>CreatTxt-ASEndTxt JSR MsgPrtr ; LDX #0 PrtLoop LDA DateStr,X JSR PutC INX CPX #$10 ;16-1 BCC PrtLoop ; JSR PutCR LDX #>TotLnTxt-ASEndTxt JSR MsgPrtr LDA TotLines STA BCDNbr LDA TotLines+1 STA BCDNbr+1 LDA TotLines+2 STA BCDNbr+2 JSR PrtDecS ;Covert BCD into dec str & print JSR PutCR LDX #>FSPCTxt-ASEndTxt JSR MsgPrtr ; LDX EndSymT+1 ;Mem Page of Top of Symbol Table INX LDA #0 STA BCDNbr STA BCDNbr+1 STA BCDNbr+2 ; ; Count # of free mem pages btwn ends of ; Symbol table & Relocation Dictionary. ; The symbol table is build upwards from LoMem while ; the Relocation Dict is build downwards from MemTop. ; PrtLoop1 CPX RLDEnd+1 BEQ PrtFreeMem JSR L81A3 INX BNE PrtLoop1 ; PrtFreeMem JSR PrtDecS ;Print dec JSR PutCR doRTS RTS REP 50 ; Message Printer ; Entry: ; (X)=offset to message ; MsgPrtr LDA ASEndTxt,X CMP #SPACE BCC ChkEndMsg JSR PutC INX BNE MsgPrtr ChkEndMsg TAX ;end of msg? BNE doRTS JMP PutCR ;yes REP 50 ; SummaryStr STR 'YRAMMUS RORRE' ; ; Print summary of errors ; ErrTIdx = index into Save Error Info table ; PrSummry LDA #0 STA ErrTIdx ;Index into err table JSR PrtFF ;Do a Form Feed JSR PutCR ; LDX #$0D PrtLoop2 LDA SummaryStr,X JSR PutC DEX BPL PrtLoop2 ; ; Print out errors encountered ; PrtAsmErr LDA ErrTIdx CMP ErrNbr4 BCC PrtErrLin RTS ; PrtErrLin TAY ;Move index into Y-reg LDA ErrInfoT+3,Y STA BCDNbr LDA ErrInfoT+2,Y STA BCDNbr+1 ;line # LDA #0 STA BCDNbr+2 LDA ErrInfoT+1,Y TAX ;Index into ErrMsgT JSR PrtErrMsg LDA #'O' ;'OF ' JSR PutC LDA #'F' JSR PutC LDA #SPACE JSR PutC ; LDA ErrInfoT,Y ;bug? instr should be removed LDX #$06 PrtLoop3 LDA FileTxt,X JSR PutC DEX BPL PrtLoop3 ; LDA ErrInfoT,Y ;file # JSR PrByte JSR PutCR INY INY INY INY STY ErrTIdx JSR PollKbd BCS StopPrt ;Abort JMP PrtAsmErr ;next ; StopPrt PLA ;Dump RTS addr PLA JMP EndAsm REP 50 ; ; Error Handler/Reporter ; Register we have an assembler syntax error or warning ; NB. (ErrorF) is reset before a line is assembled ; Ref pg 217 for List of Assembler Errors ; Entry: ; (X) = error token ; Ret: ; (ErrorF) = $80 if error; unchanged if warning ; (Y) = unchanged ; Once an error is issued on a line, secondary errors are not ; reported. However, it's possible for the line to be ; flagged with more than 1 warning. ; RegAsmEW BIT ErrorF ;Has this line been flagged? BPL NewErrWarn ;No doRTS1 RTS ; NewErrWarn TXA LSR ;Is err token odd? BCC FlagErr ;No, considered as an error ; SEC ;Yes, treat as a warning SED LDA #0 ADC NbrWarns STA NbrWarns LDA NbrWarns+1 ADC #0 STA NbrWarns+1 CLD BIT LstWarns ;Suppress warnings? BPL doRTS1 ;Yes ; JSR DoAlert ;Alert user JMP doPause ; ; Flag as an error ; FlagErr DEC ErrorF ;Is err due to idfer not found during pass2? BEQ SkipIt ;Yes JSR SaveErrInfo ;No, save err info for this line SkipIt LDA #$80 ;Flag no more errs will be STA ErrorF ; reported for curr srcline JSR DoAlert FlagErrZ JSR CountErr ;Increment # of errors ; doPause LDX #$06 ;(X) used below in delay JSR IsVideo ;Output thru video? BNE PutCR ;No ; DelayLup LDA #0 STA RDROM2 JSR WAIT STA RDBANK2 DEX BNE DelayLup ; PutCR LDA #CR JMP PutC REP 50 ; ; Print *****, sound the bell and then print ; an error message ; (X)=error token ; (Y) preserved ; NB:Fall thru to the PrtErrMsg code ; DoAlert JSR PutCR TYA ;save (Y) PHA ;on stack LDA WinLeft ;Make sure any display STA PrtCol ; is inside our window ; LDY #5 LDA #'*' ;print 5 ;'s PrtLoop4 JSR PutC DEY BNE PrtLoop4 ; PLA TAY ;restore (Y) LDA PrSlot ;If slot # is 0, BEQ RingBell ; use std Apple ][ video CMP VidSlot ;Is 80-col card? BEQ RingBell ;Yes ; BIT RDROM2 JSR BELL1 ;Apple Monitor rtn BIT RDBANK2 JMP PrtBlnk ; RingBell LDA #BEL ;video output JSR PutC PrtBlnk LDA #SPACE JSR PutC REP 50 ; ; Print Error or Warnings ; ($7A6B) ; Entry: ; (X)=error token ; bits ; 7 ; 6-1 index into a table of ptrs to Error/Warning Messages ; 0 on=counted as warning, off=counted as error ; ; Range for index $00-$48 ; PrtErrMsg TXA AND #%01111110 ;Isolate the index TAX CPX #>ErrMsgTE-ErrMsgT+1 BCC PrtEM1 BRK PrtEM1 LDA ErrMsgT,X STA MsgP LDA ErrMsgT+1,X STA MsgP+1 TYA PHA ; LDY #0 PrtEMLoop LDA (MsgP),Y CMP #SPACE BCC L7A8E ;Skip embedded 0,1,CR JSR PutC INY BNE PrtEMLoop ; L7A8E LSR ;C=0 if a null-terminated line PHP ;Save Carry for later LDA VidSlot ;slot #0? BNE SkipIt2 ;No ; LDA #CR JSR MonCOUT ;Std Apple II 40-col video LDA WinLeft STA PrtCol SkipIt2 PLP PLA TAY ; LDX #$0E ;' ERROR IN LINE' BCC PrtLoop5 ;null-terminated line LDX #$08 PrtLoop5 LDA InLinTxt-1,X ;' IN LINE' JSR PutC DEX BNE PrtLoop5 NOP JMP PrtDecS REP 50 ; ; Increment # of errors ; CountErr SEC SED LDA #0 ADC NbrErrs STA NbrErrs LDA NbrErrs+1 ADC #0 STA NbrErrs+1 CLD RTS REP 50 ; ; (Y) & (X) preserved ; Save info for first 8/16 errors encountered ; X=error token ; SaveErrInfo LDA VidSlot ;Is slot #0? BNE NotStd ;No LDA #8*4 ;std 40-col video BNE Is2Many ;always NotStd LDA #16*4 ;File/Printer/80-col Is2Many CMP ErrNbr4 BCC doRTS2 ;Too many errs BEQ doRTS2 ; ; Use table @ $A0B2 for storing error info ; TYA PHA LDY ErrNbr4 ;multiple of 4 LDA FileNbr ;file # STA ErrInfoT,Y TXA ;errtoken AND #%01111110 ;Isolate the index STA ErrInfoT+1,Y LDA BCDNbr+1 ;line # STA ErrInfoT+2,Y LDA BCDNbr STA ErrInfoT+3,Y INY INY INY INY STY ErrNbr4 PLA TAY doRTS2 RTS REP 50 ; Bit table ; Bit01 DB $01 ;not used Bit02 DB $02 Bit08 DB $08 Bit10 DB $10 Bit40 DB $40 REP 50 ; ; Save zero page locations $60-$F1 ; SaveZP LDX #$92 BIT LCBANK2 ;2 successive writes BIT LCBANK2 SavLoop LDA Z60-1,X LDY SvZPArea-1,X STY Z60-1,X STA SvZPArea-1,X DEX BNE SavLoop BIT RDBANK2 RTS REP 50 ; ; ($7B13) Init Assembler module ; InitASM LDA #>ColdStrt STA HighMem STA MemTop LDA #ChnPNB STA SrcPathP LDA # drive 1 LDA #>OLDataB ;Only 16 bytes used STA OLBufAdr LDA #LstDBuf STA HighMem STA MemTop LDA # no label BEQ L7EDD ; ; This part of code checks for an idfer in the LABEL field ; Should be part of Lexer (Static semantic analysis) ; JSR RsvdId ;Chk for A,X,Y as 1st char of label JSR FindSym BCS NewLabel ;No such label TAX ;Sym found but has it been defined? BMI L7E94 ;No ; LDX #$02 ;Duplicate idfer JSR RegAsmEW LDA #$00 STA LabelF ;Flag no label field JMP L7EC8 ;(Y)-indexing lobyte? ; L7E94 STA SymFByte ;Symbol's curr flag byte DEY ;Index flag byte again AND #entry+fwdrefd ;0000 1001 BIT DummyF ;Are we in a DSECT? BMI L7E9F ;Yes ORA #relative L7E9F STA (SymP),Y ;save modified status of flag byte INY LDA PC ;Value associated w/symbol STA (SymP),Y INY LDA PC+1 STA (SymP),Y JMP L7EC8 ; ; New label ; NewLabel LDA #$00 STA SymFByte LDX #relative BIT DummyF ;Are we in a DUMMY section? BPL L7EBA ;No ; LDX #$00 ;abs L7EBA STX RelExprF LDA #$00 ;Initial flag byte to be JSR AddNode ; stored into Node BCC L7EC8 ;(Y)-indexing hibyte LDX #$0E ;Invalid identifier JSR RegAsmEW ; L7EC8 DEY DEY ;Indexing flag byte of symtbl entry TYA CLC ADC SymP STA SymFBP ;Point @ the symbol's flag byte LDA #0 ADC SymP+1 STA SymFBP+1 ; ; This part handles the mnemonic/psuedo opcode field ; LDY #0 ;Start w/1st char JSR L81F0 ;Skip over non-blanks BNE L7EE5 ;Got a CR ; L7EDD JSR NxtField ;We got at least 1 space so skip over them JSR HndlMnem BCC L7EF0 ;No errs ; L7EE5 LDX #$04 ;undefined opcode JSR RegAsmEW LDA #3 STA Length BNE L7F01 ;always ; L7EF0 CMP #$FF ;1st flag byte BEQ L7F04 ;Proceed to next line rec BIT ZAB ;SW16 opcodes? BVC L7EFE ;No BIT SW16F ;Are SW16 ops valid? BPL L7EFE DEC SW16F ;When (SW16F)=0, code gen problems may arise ; ; Looks like the above code which checks for SW16 ; validity will come here no matter what. ; To avoid (SW16F) decrementing to 0, use SW16 directive ; to set its value to $01. ; L7EFE JSR GInstLen ;Determine len of inst L7F01 JSR AdvPC ; so we can adjust PC ; L7F04 JSR NextRec ;Adv to next src line record JSR L81A3 ;Let user know we are doing something JMP Pass1Lup REP 50 ; DoPass2 INC PassNbr ;Flag we are in 2nd pass LDA #'*' STA RepChar LDA #-1 STA ListingF JSR PutCR JSR OpenSrc1 ;Re-open initial src file LDA GenF CMP #$80 ;Write obj code into mem? BNE Pass2Lup ;No ; LDA CurrORG ;These 4 inst serves no purpose since STA ObjPC ; its contents are changed when an LDA CurrORG+1 ; OBJ/ORG directive is declared STA ObjPC+1 ; Renamed as CodeLen if REL file ASL GenF ;$00 - Remove suspension ; ; Assemble each src line ; Pass2Lup JSR GSrcLin ;Any more src lines to assembled? BCC L7F33 RTS ; ; Init before each line is scanned/parsed ; L7F33 LDY #-1 STY ZAB ;=$FF INY ;=0 STY Length STY ErrorF STY LstCodeF STY NumCycles LDA SrcP STA Src2P ;Save a copy of ptr LDA SrcP+1 STA Src2P+1 ; to curr srcline ; BIT CondAsmF ;Assembling alt block? BMI L7F50 ;Yes, proceed to scan for alt blk BVC L7F57 ;If V=1, then we will be assembling ASL CondAsmF ; alt block so set flag to $80 ; L7F50 LSR ZAB ;Clear msb (=$7F) JSR L80F7 ;Do we have a FIN/ELSE? BCC L7F77 :No, skip assembling src line ; ; Assemble curr src line ; Should be the lexical analyser/scanner ; L7F57 LDA (SrcP),Y ;Pure comment line? CMP #'*' BEQ L7F77 CMP #' ;' BEQ L7F77 ;Yes, ignore curr src line ; ; Ignore the label field and go directly to ; the mnemonic field ; JSR L81F0 ;Skip over non-blanks BNE L7F6E ;Got a cr JSR NxtField ;Skip over 1 or more blanks JSR HndlMnem BCC L7F7A ; L7F6E LDX #$04 ;undefined opcode JSR RegAsmEW L7F73 LDX #3 STX Length L7F77 JMP L806F ; L7F7A STA ZAB ;1st flag byte after mnem/directive byte BIT Bit80 ;Directives? BEQ CodeGen ;No CMP #$83 ;1000 0011 BNE L7F88 JMP L807A ;Skip listing & storing generated code ; L7F88 CMP #$81 ;1000 0001 BNE L7F77 STA LstCodeF ;$81 - these control directives LDA ValExpr ; have expr result field which STA ERfield ; is printed to right of PC field LDA ValExpr+1 STA ERfield+1 JMP L806F ;list code, store generated code ; Bit80 DB $80 ; ; Prepare to generate code ; CodeGen JSR GInstLen ;Determine instr's len LDA #$27 ;0010 0111 STA LstCodeF LDX #0 LDA ModWrdL BIT Bit40 ;sw16 opcode? BEQ L7FCB ;No LDA SW16F BNE L7FB5 LDX #$42+1 ;odd-warning JSR RegAsmEW ;sw16 opcode ; ; This part is for SW16 ops ; LDX #$00 L7FB5 LDA SubTIdx TAY LDA OpcodeT,Y ;Get SW opcode L7FBB CMP #$10 ;Non-reg ops? BCC GenNow ;Yes ; JSR IsSW16Reg BNE L7F73 ;No LDA OpcodeT,Y ;Get sw16 reg opcode ORA ValExpr ;=Rn BNE GenNow ;always ; ; This part of the code is for 6502 ops and is used ; by the Code Generator to compute the index to the ; actual opcode within the OpcodeTable ; NB: Highly dependent on the 3 bytes following ; a mnemonic entry & arrangement data in the various ; tables like AModTbl, OpcodeT etc. See comments ; b4 MnemTbl for more info ; (A)=1st flag byte after a mnenmonic entry ; L7FCB AND #%00000101 ;zp,Y/JMP/JSR/(zp) ORA ModWrdH BEQ L7FED ;single byte ops (A)=0 LDA LenTIdx ;Index into inst len table BPL L7FD6 ;always! L7FD5 BRK L7FD6 CMP #9 ;0-8 (first 9 modes of AModTbl) BCC L7FED CMP #12 ;(abs,X) BNE L7FE5 JSR Is65C02 ;Are 65C02 opcodes allowed? BCS L8002 ;No BCC L7FE7 L7FE5 BCS L7FD5 ;CRASHED! ; ; On fall thru, (A)=9-11 => (abs), acc, zp,Y addr modes ; L7FE7 AND #%00000011 ;(A) -> 1-3 BNE L7FED ; LDA #2 ;JMP (abs,X) ; ; Single byte & branch ops don't have sub-tables ; Instead the (SubTIdx) is just the index into ; the opcode table. For these ops, (A) must be ; to 0 ; L7FED CLC ADC SubTIdx ;Calc the index into opcode table TAY LDA CycTimes,Y STA NumCycles LDA OpcodeT,Y ;get opcode BIT X6502F ;R 65C02 ops allowed? BMI GenNow ;Yes ; JSR IsC02Op ;Is the opcode valid? BCC GenNow ;Yes ; L8002 LDX #$48 ;65C02 addr mode/opcode JSR RegAsmEW JMP L7F73 ; ; Code Generation ; Relocation Dictionary entries are created for ; 1) all 6502 opcodes except branch & single byte ops ; 2) DFB,DDB,DW pseudo ops ; 3) SW16 pseudo ops ; GenNow STA GMC,X ;X=0 -> save opcode INX STX GMCIdx LDA ModWrdL BIT Bit08 ;branch instr? BNE L8038 ;Yes ; TXA ;X=1 on fall thru CMP Length ;Single byte ops? BCS L8025 ;Yes LDA ValExpr STA GMC,X INX LDA ValExpr+1 STA GMC,X INX ;unnecessary inst ; L8025 LDX Length DEX BEQ L806F ;Single byte ops LDA RelExprF ;Is expr's val abs? BEQ L806F ;Yes ; LDA #1 ;offset LDY #0 ;Little Endian (Reverse) JSR AddRLDEnt ;Make an RLD entry JMP L806F ; ; Branch instructions ; L8038 LDA ValExpr ;Branch target addr to STA ERfield ; be printed to right of LDA ValExpr+1 ; branch object code STA ERfield+1 LDA LstCodeF ORA #$80 STA LstCodeF JSR CalcDisp ; LDX GMCIdx LDA ModWrdL AND #$10 ;BRL/BSL? TAY BNE L8063 ;yes ; ; 6502/C02 ; LDA ValExpr ;(Y)=0 BPL L8058 ;Forward branch INC ValExpr+1 ;=0 L8058 LDA ValExpr+1 ;(ValExpr) has displacement byte BEQ L8063 LDX #$26 ;branch range err JSR RegAsmEW ; LDX GMCIdx L8063 LDA ValExpr STA GMC,X TYA ;6502 branch instr? BEQ L806F ;Yes INX LDA ValExpr+1 ;SW16 BSL/BRL STA GMC,X ; L806F JSR PrtAsmLn JSR StorGMC LDA Length JSR AdvPC ; L807A JSR PollKbd BCS L8088 JSR NextRec JSR L81A3 JMP Pass2Lup ;Assemble next srcline L8088 JMP CanclAsm REP 50 ; ; Chk if instruction is to be printed ; C=0 - Yes ; C=1 - No ; RVLsting CLC LDA ErrorF ;Was an error reported for this srcline? BNE doRTS5 ;Yes BIT CondAsmF ;Has this line been assembled? BPL L8098 ;Yes BIT LstUnAsm ;Print unasm src block? BPL L80A4 ;No L8098 BIT MacroF ;Is line a result of mac exp? BPL L80A0 ;No BIT LstExpMac ;List such lines? BPL L80A4 ;No L80A0 BIT ListingF ;Is listing ON? BMI doRTS5 ;Yes L80A4 SEC doRTS5 RTS REP 50 ; ; Print Assembled Line ; PrtAsmLn JSR RVLsting BCS doRTS6 ;No JSR ListCode ;Print generated code JSR LstSrcLn ;Print src stmt doRTS6 RTS REP 50 ; ; Store generated machine code ; StorGMC LDY Length ;# of bytes BEQ doRTS7 ; LDY #0 L80B8 LDA GMC,Y BIT GenF ;Is code generation suppressed? BMI doRTS7 ;Yes BVS L80C5 ;Write to disk STA (ObjPC),Y ;Write to mem BVC L80C8 ;Always L80C5 JSR Wr1Byte L80C8 INY CPY Length BNE L80B8 ;Next byte ; BIT GenF ;Did we do a mem store? BVS doRTS7 ;No, a disk store TYA JSR AdvObjPC doRTS7 RTS REP 50 ; ; ($80D6) (A)=byte to store in mem/disk ; StorByt BIT GenF ;Suppress code generation? BMI doRTS8 ;Yes BVS L80F1 ;Write to Disk LDY #0 STA (ObjPC),Y INC ObjPC BNE L80E6 INC ObjPC+1 ; L80E6 LDA ObjPC ;Are we out of mem? CMP HighMem LDA ObjPC+1 SBC HighMem+1 BCS L80F4 ;Yes doRTS8 RTS ; L80F1 JMP Wr1Byte ; L80F4 JMP L8282 ;err REP 50 ; ; ($80F7) Do we have a FIN/ELSE statement? ; Scan curr line for conditional block directives FIN/ELSE ; C=0 - no ; C=1 - yes ; (SrcP) & Y-reg preserved ; L80F7 STY SavIndY ;Index into field of src line LDA SrcP PHA LDA SrcP+1 PHA JSR L81F0 ;Look ahead for a space BNE L812D ;None found ; JSR SkipSpcs ;Skip until non-blank JSR AdvSrcP ;Now pointing @ pseudo code field ; LDX #3 ;Y=0 L810C JSR ChrGot CMP FINTxt,Y BNE L811A INY DEX BNE L810C BEQ L812A ;Got a hit ; L811A LDY #0 LDX #4 L811E JSR ChrGot CMP ELSETxt,Y BNE L812D INY DEX BNE L811E L812A SEC ;got a hit BCS L812E ;always ; L812D CLC L812E PLA STA SrcP+1 PLA STA SrcP LDY SavIndY RTS ; FINTxt ASC 'FIN' ELSETxt ASC 'ELSE' REP 50 ; Add an entry to the relocation entry dictionary table ; Entry: ; (CodeLen) - zeroed whenever the initial srcfile is read ; A=offset ; X=1,2; 1 - 8-bits, 2 - 16-bits ; Y=order of bytes 0=DW(low-hi), 1=DDB(hi-low) ; On 6502, normal order is lower 8 bits of a 16-bit ; value is stored in 1st byte and upper 8-bits in 2nd ; byte (pg 103). However, according to page 229, ; normal order is DDB. ; The Relocation Dictionary is build downwards from ; high mem towards the End of Symbol Table ; The initial start of the RLD is @ MemTop ; & is build downwards towards LoMem ; Each entry is 4 bytes ; AddRLDEnt BIT RelCodeF ;Gen REL code? BMI L8143 ;yes RTS ; L8143 PHA LDA RLDEnd ;Chk if there is enough mem SEC SBC #4 ; for 1 RLD entry (4 bytes) STA RLDEnd LDA RLDEnd+1 SBC #0 STA RLDEnd+1 ; LDA EndSymT CMP RLDEnd LDA EndSymT+1 SBC RLDEnd+1 BCC L8163 LDX #$12 ;Sym/RLD table full! JSR RegAsmEW JMP CanclAsm ; L8163 DEX ;Do we have a 2-byte operand? TXA ;NB. Acc=0 on fall thru. BNE L8170 ;Yes ; LDX Ret816F ;Are we using hi-8 bits? DEX BMI L8178 ;No, lo-8 bits with (A)=$00 LDA #$40 ;Yes BNE L8178 ;always ; ; Bits of the RLD flag byte are defined as follows: ; $80 - sizeof relocatable field ; $40 - Upper/Lower 8 if a 16-bit value ; $20 - Normal/reversed 2-byte field ; $10 - Field is EXTRN 16-bit reference ; $01 - "Not EO RLD" (Clear => EO RLD) ; L8170 TYA ;Y=0 or 1 ASL ASL ASL ASL ASL ;-> $00(Reverse) or $20 (Normal) ORA #$80 ;Sizeof relocatable field=2 bytes ; L8178 ORA #$01 ;Flag 'Not EO RLD' => more entries LDY GblAbsF BEQ L8180 ;ZDEF/ZREF ORA #$10 ;EXTRN 16-bit reference ; ; RLD entries are build downwards from high mem ; L8180 LDY #3 STA (RLDEnd),Y ;Set RLD flagbyte PLA ;Restore offset CLC ADC CodeLen ;Calc the offset in image DEY ;Y=2 STA (RLDEnd),Y LDA #0 ADC CodeLen+1 DEY ;Y=1 STA (RLDEnd),Y DEY ;Y=0 ; ; Set 4-th byte of an RLD entry. First we check if the symbol refers ; to an 8-bit or 16-bit address. If it's a 16-bit address ; then 4-th byte takes a valid value which is an ESD number. ; LDA GblAbsF ;ZDEF/ZREF? BNE L81A0 ;No => DEF/EXTRN (A)=ESD # ; ; The operand refers to an 8-bit value. Check if ; #addr16. If the former, return a 0 ; else return the low 8-bit value of the 16-bit ; address in 4-th byte of the RLD entry. ; LDA #0 LDX Ret816F ;-1,0,1 DEX BMI L81A0 ;It's # and CR for ProDOS ; WhiteSpc LDA (SrcP),Y CMP #SPACE BEQ doRet CMP #CR doRet RTS REP 50 ; ; This subrtn is part of Scanner ; There are 2 entry points viz ChrGet and ChrGot ; On entry: ; (Y) = index into the src line ; (SrcP) = Pointing somewhere within source line ; Ret: ; (A) - char (converted to uppercase if alphabetic) ; C=1 if char is non-alphabetic ; C=0 if char is alphabetic (A-Z, a-z) ; Z=1 if char is numeric digit (0-9) ; Z=0 if char is non-numeric ; V=1 if char is hexdec digit (0-9, A-F, a-f) ; V=0 if char is non-hexdec ; (X) - unchanged ; (Y) - incr by 1 if 1st entry point else unchanged ; ChrGet INY ChrGot LDA (SrcP),Y ;Get char fr src line STY ZPSaveY ;Save (Y) temporarily TAY ;Use char as an index as well as saving it in (Y) BPL L8211 ;Must be std ASCII or ; BRK ;else crash ; L8211 LDA CharMap1,Y ;Get flag byte PHA ;Save for later use TYA ;Get back char LDY ZPSaveY ;restore Y PLP ;Now set up Status reg - neat BPL doRet2 ;If (A)=$61-$7A (a-z) AND #$DF ; convert to upper case doRet2 RTS REP 50 ; ; This subrtn is part of Scanner ; Same logic as above except CharMap2 is used ; Entry: ; (Y) = index into src line ; Ret: ; (A)=char (uppercase if alphabetic) ; C=0 - alphanumeric char ; C=1 - non-alphanumeric char ; V=0 - non-hexdec char ; V=1 - hexdec char ; (X) - unchanged ; ChrGet2 INY ChrGot2 LDA (SrcP),Y STY ZPSaveY TAY BPL L8227 ; BRK ;source file must be std ASCII ; L8227 LDA CharMap2,Y ;Get the bit flags PHA TYA LDY ZPSaveY PLP ; and pop into Status reg BPL doRet3 AND #$DF doRet3 RTS REP 50 ; ; On entry ; (Y)=index into src line ; Ret: ; (Y)=0 ; src ptr pointing @ 1st char of the field ; (X) - unchanged ; NxtField LDA (SrcP),Y CMP #SPACE BNE L823D INY BNE NxtField ; L823D CLC TYA ADC SrcP STA SrcP LDA #0 TAY ;(Y)=0 ADC SrcP+1 STA SrcP+1 RTS REP 50 ; ; Set SrcP to beginning of next assembly src line ; Source Lines are terminated with a CR ; (X)-unchanged ; Ret with (Y)=0 & src ptr pointing @ 1st char of line ; NextRec LDY #0 L824D LDA (SrcP),Y INY ;NB: skip past char CMP #CR ; b4 comparision BNE L824D ; ; On fall thru, Y=# to advance ; AdvSrcP CLC TYA ADC SrcP STA SrcP LDA #0 TAY ;=0 ADC SrcP+1 STA SrcP+1 RTS REP 50 ; ; A=# to advance ; AdvPC CLC ADC PC STA PC BCC doRet4 INC PC+1 doRet4 RTS REP 50 ; ; A=# to advance ; AdvObjPC CLC ADC ObjPC ;code buf STA ObjPC BCC L8275 INC ObjPC+1 L8275 JMP L828A REP 50 ; ; Not referenced ; L8278 LDA MemTop CMP ObjPC LDA MemTop+1 SBC ObjPC+1 BCC L828A ; L8282 LDX #$36 ;Obj buf overflow JSR RegAsmEW JMP CanclAsm ; L828A LDA ObjPC ;Should not be >= HiMem CMP HighMem ; which was passed by Editor LDA ObjPC+1 SBC HighMem+1 BCS L8282 RTS ;================================================= ; ($8295) ; This subrtn is called periodically within a loop ; to check if user wants ; 1) to stop the assembly - Abort Mode ; 2) a pause during a listing - Pause Mode ; 3) turn listing on/off ; 4) to shift listing left/right for 40-col display ; Ret: ; C=1 if ctrl-C pressed ; PollKbd LDA KBD BMI L829C L829A CLC RTS ; L829C STA KBDSTROBE CMP #CTRLC+$80 BNE L82A7 DEC AbortF ;Pending SEC RTS ; L82A7 LDX PassNbr ;doing pass 1? BEQ L829A ;Yes CMP #BS+$80 BNE L82B9 ; ; EdAsm.ASM allows an 80-col listing to be viewed on a 40-col video screen ; Move the 40-col window one column to left edge of the 80-col listing ; LDA WinLeft BEQ L829A L82B3 DEC WinLeft DEC WinRight BNE L829A ;always ; L82B9 CMP #CTRLU+$80 ;RArrow BNE L82C9 ; ; Move the 40-col window one column to right edge of the 80-col listing ; L82BD INC WinLeft INC WinRight LDA WinLeft CMP #40 BCS L82B3 BCC L829A ;always ; L82C9 CMP #SPACE+$80 BEQ WaitK3 CMP #CTRLO+$80 BNE L82D6 SEC ROR ListingF ;Turn on listing CLC RTS ; L82D6 CMP #CTRLN+$80 BNE L829A LSR ListingF ;Turn off listing CLC RTS ; WaitK3 LDA KBD ;Get another keypress BPL WaitK3 ; before continuing CLC RTS ;================================================= Wait4CR BIT KBDSTROBE JSR PrtCR LDX #>ContTxt-ASEndTxt JSR L986A WaitK4 LDA KBD BPL WaitK4 BIT KBDSTROBE CMP #CR+$80 BNE WaitK4 JSR PrtCR RTS ;================================================= ; Compute relative addr of a branch op ; Ret: ; Val=Val-PC-Len ; CalcDisp SEC LDA ValExpr SBC Length TAX LDA ValExpr+1 SBC #0 ; TAY TXA SEC SBC PC STA ValExpr TYA SBC PC+1 STA ValExpr+1 RTS ;================================================= ; (A) = opcode ; Check if (A) is NCR 65C02 opcode ; C=1 - yes ; (X)-unchanged ; IsC02Op LDY #0 L8319 CMP L8327,Y BCC doRet5 BEQ doRet5 INY CPY #$12 BCC L8319 CLC doRet5 RTS ; Rockwell opcodes L8327 DB $04,$0C,$14,$1A,$1C,$34,$3C,$3A,$5A DB $64,$74,$7A,$80,$89,$9C,$9E,$DA,$FA ;================================================= ; Process mnemonic/pseudo opcode field ; Ret ; $AB) - 1st flag byte if not a directive ; - may be changed to $83 if data directives ; - $80 if macro invocation ; (A)=($AB) ; C=0 - succ ; C=1 - fail ; HndlMnem LDA #$80 STA ZAB JSR ChrGot BCC L8348 ;alphabetic char CMP #'.' ;If a DOT directive BNE L83AC LDA #'A'-1 ; use ASCII @ in place of dot L8348 SEC SBC #'A'-1 ASL TAX LDA Tbl1stLet,X STA MnemP LDA Tbl1stLet+1,X BEQ L839C ;No such opcode/directive w/this 1st letter STA MnemP+1 L8359 JSR ChrGot ;Note:msb of char=0 EOR (MnemP),Y ;Effectively comparing 7 bits ASL ;C=1 if last char of opcode was compared BNE L837E ;No hit L8361 INY ;Z=1 => 7 bits comparison above matched BCC L8359 ;Continue to cmp next char ; ; On fall thru, if C=1 then that was last char/byte of ; mnemonic entry & we have got a match ; JSR WhiteSpc ;sp/cr? BNE L8386 ;no LDA (MnemP),Y ;Get 1st flag byte STA ZAB BPL L837C ;Not a directive ; ; This part of the code handles directives by doing a jump via RTS ; (ZAB) has the directive's only flag byte which may be modified ; by the directive handler ; STY SavIndY ;Save index into Mnemonics table INY LDA (MnemP),Y ;Get RTS addr-1 (hibyte) PHA INY LDA (MnemP),Y PHA ;lobyte LDY SavIndY ;Restore index RTS L837C CLC ;6502/SW16 opcode RTS ; L837E LDA (MnemP),Y ;Skip rest of entry BMI L8385 ;Last byte of entry has msb=1 INY BNE L837E ; L8385 INY L8386 SEC ;Add 3 more bytes INY INY TYA ADC MnemP ; to skip STA MnemP BCC L8392 INC MnemP+1 ; L8392 LDY #0 ;Try next entry with JSR ChrGot EOR (MnemP),Y ASL BEQ L8361 ; the same first letter ; ; Not mnemonics/pseudo code/directive ; Assume it's a macro invocation ; L839C LDA MacroF ;Are macros allowed? BEQ L83AC ;No BMI L83A4 ;Invocation fr a macro defn file -> err BPL L83AE ;No, so it's ok ; L83A4 LDX #$18 ;Macro nesting L83A6 JSR RegAsmEW JMP DrtvDone L83AC SEC ;Flag it's an err RTS ; L83AE BIT DskSrcF ;Are we assembling fr disk? BPL L83A4 ;No JSR L9DF8 ;Incr line #? JSR LD3B4 ;Save ptr to next src line LDX #MacFile JSR L9D51 ;Save curr line # of src line JSR SetPNBuf ;Use macro PN buf LDA MacroPNB ;Len of maclib prefix STA MacPNLen BEQ L83CD ;No prefix was declared ; JSR L83F4 ;Form fullpathname of macro defn file JMP L83D0 ; L83CD JSR GetPNStr ;Get macro defn filename into MacroPNB buf L83D0 CMP #SPACE+1 ;Is it a space/cr? BCC L83DD ;Yes ; LDA MacPNLen STA MacroPNB ;Reset the len maclib prefix LDX #$34 BNE L83A6 ;Invalid delimiter error ; L83DD JSR AdvSrcP ;Point @ BO string parmlist LDX #$40 STX MacroF ;Flag a macro had been invoked LDX FCTIndex JSR Open4RW ;Open Macro defn file for reading LDA MacPNLen STA MacroPNB ;Set back to maclib name (neat trick) JSR L841A ;Parsed passed STR parms JMP DrtvDone ;================================================= ; Append macro name to MacroLib subdir/prefix ; to create a full pathname to macro defn file ; L83F4 LDX MacroPNB ;Get len byte of maclib prefix LDY #0 ;Starting fr 1st char of filename L83F9 JSR WhiteSpc ;Get a char fr src line BEQ L8416 ;sp/cr? JSR ToUpper CMP #SPACE BCS L8408 L8405 JMP L92D6 ;error ; L8408 INX STA MacroPNB,X INY CPX #64 BCC L83F9 JSR WhiteSpc BNE L8405 ;If not cr/space, too many L8416 STX MacroPNB ;Set len byte RTS ;================================================= ; String parameters in the operand field of the ; asm statement containing the macro name are parsed ; and stored into a 128-byte buf. To pass a comma, ; use $2C or $AC. ; Pg 115 ; C=0 parsing successful ; L841A LDA #0 STA MParmCnt ;# of string parms passed LDX #127 LDA #0 L8422 STA MacStrBuf,X ;zero buf DEX BPL L8422 ; LDY #0 JSR NxtField ;Point @ operand field JSR WhiteSpc BEQ doRet6 ;sp/cr ; L8432 LDA (SrcP),Y ;Get char fr passed string parm CMP #CR BEQ L8446 ;done CMP #',' ;If not a delimiter, BNE L8440 ; just copy it into our buf LDA #0 ;Replace w/0 as delimiter INC MParmCnt L8440 STA MacStrBuf,Y INY BNE L8432 ;Next char ; L8446 LDA #0 ;Place 0 as last delimiter STA MacStrBuf,Y INC MParmCnt LDA MParmCnt CMP #10 BCC doRet6 ;Any # of str parms can be passed LDA #9 ; but only 9 will be processed STA MParmCnt doRet6 RTS ;================================================= ; ($8458) We must determine the address mode of opcode ; Ret: ; Length of instruction opcode ;================================================= GInstLen STA ModWrdL ;1st flag byte INY LDA (MnemP),Y ;2nd flag byte - addr mode bits STA ModWrdH ; of this mnemonic INY LDA (MnemP),Y STA SubTIdx ;Index into sub-table of opcode table DEY DEY ;Moveback to 1st flag byte JSR NxtField ;Point @ operand field ; LDA #0 STA LenTIdx STA ValExpr ;val of operand if any STA ValExpr+1 ; LDA ModWrdL BIT ModWrdL BMI L84CE ;Directives/SET BIT Bit20 BNE L84D4 ;Implied BIT Bit08 BNE L84D9 ;Branch opcodes ; ; There are now thirteen X6502 addr modes to consider ; JSR GAdrMod ;Get an index to addr mode table BCS L84FE ;error ; ; Checks the returned/parsed addr mode against permitted modes ; ChkAMod STA LenTIdx ;=0-12 TAX LDA AModTbl,X ;Get the parsed addr mode ; CPX #8 BCC L849B ; ; When (X)=8-12, the addressing modes are: ; (zp), (abs), acc, zp,Y & (abs,X) ; AND ModWrdL ;1st flag byte AND #%00000111 ;Retain only these bits CMP AModTbl,X ;Is addr mode valid? BEQ L8502 ;Yes BNE L849F ;=> Further checks ; ; X=0-7 The bits of ModWrdH (2nd flag byte) are completely defined ; L849B BIT ModWrdH ;Is the returned mode valid? BNE L8502 ;Yes ; L849F CPX #11 ;Was mode parsed as zp,Y? BNE L84A7 ;No LDA #5 ;Force the mode as BNE ChkAMod ; abs,Y (for LDA/STA) ; L84A7 CPX #1 ;Was mode parsed as zp? BNE L84B5 ;nope LDA ModWrdL AND #%00010000 ;JMP/JSR? BEQ BadMode ;No LDA #0 ;Allow for JMP/JSR zp but BEQ ChkAMod ; convert 'em to JMP/JSR abs (always) ; L84B5 CPX #8 ;Was mode parsed as (zp)? BNE BadMode ;No LDA ModWrdL AND #%00010000 ;JMP? BEQ BadMode ;No LDA #9 BNE ChkAMod ;Convert to JMP (abs) (always) ; BadMode LDX #$1C ;addr mode error JSR RegAsmEW LDA #$00 STA LenTIdx ;Assume abs mode addressing BEQ L84FE ;always ; L84CE BVS L8513 ;=> SET directive LDA #$00 ;zero len BEQ L8511 ; for directives ;--- L84D4 LDA #1 ;Single byte opcodes BNE L8511 ;always ; Bit20 DB $20 ; ;--- Branch opcodes (both 65C02/SW16) ; L84D9 LDA #$00 ;There are no sub-tables for such STA LenTIdx ; opcodes so set this index to 0 LDX #2 ;len of instr LDA ModWrdL AND #$10 ;BSL/BRL? BEQ L84E6 ;No INX ;=3 L84E6 STX Length JSR EvalExpr LDA PassNbr BEQ L8513 BCC L8513 LDA NxtToken CMP #$34+$80 ;Invalid delimiter BNE L84FE TAX JSR RegAsmEW JMP L8513 ; L84FE LDA #3 ;len of instruction BNE L8511 ;always ; X=0-12 L8502 LDA ModWrdL BIT Bit40 ;sw16? BEQ L850E ;no LDA L851F,X ;Get instr len BNE L8511 ;always ; L850E LDA InstLenT,X ;Get instr len L8511 STA Length L8513 LDA Length RTS REP 50 ; ; (X)=index into addr mode table ; Not only this, it can be used to index an opcode within ; a sub-table of opcodes (eg ADCOps) by adding it to SubTIdx ; This table is highly dependent on the meaning of the ; bits of the 2 mnemonic flag bytes ; InstLenT DB $03 ;abs DB $02 ;zp DB $02 ;# DB $02 ;zp,X DB $03 ;abs,X DB $03 ;abs,Y DB $02 ;(zp),Y DB $02 ;(zp,X) DB $02 ;(zp) ; ; This sub-table is used by SW16 opcodes ; L851F DB $03 ;(abs) - CPIM DB $01 ;acc - SW16 Reg ops DB $02 ;zp,Y DB $03 ;(abs,X) ; ; bit flags used to check the validity of ; the parsed addressing mode ; AModTbl DB $01 ;abs DB $02 ;zp DB $04 ;imm DB $08 ;zp,X DB $10 ;abs,X DB $20 ;abs,Y DB $40 ;(zp),y DB $80 ;(zp,X) DB $03 ;(zp) ; DB $01 ;(abs) DB $02 ;acc DB $04 ;zp,Y DB $01 ;(abs,X) ;================================================= L8530 LDX #$34 ;invalid delimiter JSR RegAsmEW SEC RTS REP 50 ; ; This subrtn will parse the addressing mode of the ; operand of a 6502 mnemonic/SW16 psuedo opcode ; Ret ; (A)=index (0-12) use to get addr mode fr a table ; C=0 - succ ; C=1 - syntax error ; ; To trace this rtn, re-assemble the code by doing ; an ORG $5800 for the tables and code @ $D000 (ASM1.S) ; Under the EI interpreter, xload EDASM.ASM2,A$5800 ; xload bugbyter,a$1000 ; Enter MONitor and type 1000G ; GAdrMod LDX #0 ;X=index into the 2 tables LDY #0 ;Position @ start of operand L853B JSR ChrGot ;Y=index into operand text ORA #$80 CMP AModTkns,X BEQ L855E ;Got a hit ; LDA AModTkns,X ;Get a token BPL L8570 ;Not a char ; CMP #SPACE+$80 BNE L8554 ; ; Token is $A0 ; LDA #CR ;Is char a cr? CMP (SrcP),Y BEQ L8563 ;Yes, eol ; ; On fall thru, if token is $A0 and CR not found ; L8554 LDA AModCmds,X BEQ L855E ;=> next token & src char BMI L8583 ;Error token TAX ;Index to next token fr $D7D7 table to be BNE L853B ; used to cmp against SAME char of src code ; ; No fall thru here ; Proceed to get next token of $D7D7 table ; and next char of src to be compared ; L855E INX ;next token INY ;next src char JMP L853B ; ; Got a CR ; L8563 INX ;Prepare to look at next token DEY ;Index prev src char LDA AModTkns,X BEQ L856C ;$A0+cr followed by $00 BPL L858B ;$A0+cr followed by +ve byte value (always) ; L856C LDX #$0A ;expr syntax err- never reported! (LDA #$0A) BNE L8583 ;always - bug? ; L8570 BNE L858B ;token > 0 ; ; Got a $00 token ; STX SavIndX ;Save X JSR EvalExpr LDX SavIndX BCC L8554 ;No errs during evaluation LDA NxtToken AND #$7F CMP #$34 ;Invalid delimiter BNE L8589 ; ; (A) = error token ; L8583 TAX ;(X) overwritten! Is it a bug? PHA ;Save error token JSR RegAsmEW PLA L8589 SEC RTS ; L858B LSR ;If odd then BCC L8590 CLC ; ret to caller w/mod2 which RTS ; is an index to Adr Mode Table ; L8590 ASL ;Even, get back token first JSR L8598 ;Now, execute helper function BCC L855E ;Loop back to process next src char BCS L8554 ;Go get index to next token REP 50 ; ; Calls help subroutines (functions). ; Only 3 defined so far. ; Entry ; (A)=2,4,6 - index into subrtn table ; ; The helper functions with return the required values ; primarily the C bit ; L8598 STX SavIndX TAX ;Token is an index CPX #7 ;Only 3 subrtns currently BCC L85A0 BRK ; L85A0 LDA L85AE-1,X ;Prepare for JMP PHA LDA L85AE-2,X ;lobyte PHA JSR ChrGot ;Get curr char L85AB LDX SavIndX RTS ;Do the JMP now ; L85AE DW IsZPMod-1 DW IsAccMod-1 DW Is65C02-1 REP 50 ; ; Checks if expr is a 8-bit or 16-bit value ; For addressing modes involving zp ; Ret: ; C=0 - Yes ; C=1 - No ; IsZPMod LDA ExprAccF AND #%11101111 ;Clear EXTeRNal symbol bit ORA ValExpr+1 ;Is hi-byte of expr zero? BEQ L85CF ;Yes => 8-bit LDA ExprAccF AND #%00010000 ;Is EXTeRNal symbol bit set? BEQ L85C6 ;No LDA Ret816F ;EXTRN but is lo-byte being returned? BEQ L85C8 ;Yes L85C6 SEC ;16-bit RTS ; L85C8 LDX #$44+1 ;odd-warning JSR RegAsmEW ; (EXTRN used as ZXTRN) LDX SavIndX L85CF DEY ;Move back CLC RTS REP 50 ; ; Check a single 'A' in the operand field ; i.e. checking for accumulator mode ; Entry: ; (A)=char to check ; Ret: ; C=0 - Yes ; C=1 - No ; IsAccMod CMP #'A' BNE L85DD INY ;Look 1 char ahead JSR WhiteSpc ;Is the next char sp/cr? BEQ L85CF ;Yes, we have a single 'A' in operand field DEY ;No, just move back L85DD SEC RTS REP 50 ; ; Check if 65C02 opcodes are valid ; Only Status reg is changed ; Ret: ; C=0 - Yes ; C=1 - No ; NB. If X6502F off, LDA (ZP) is still considered ; valid. It is equivalent to LDA ZP ; Is65C02 BIT X6502F ;Are X6502 opcodes allowed? BMI L85CF ;Yes BPL L85DD ;always REP 50 ; ; Evaluate expressions. No check for numeric overflow ; Support for +,-,;,/ and bitwise AND ^, OR |,EOR ! ; Ref pg 89 for Expression Syntax adopted for Assembler ; ; Expression := [byteopr] Term [opr Term]...] ; byteopr := >, < ; ; Meaning of: ; ExprAccF - Expression's accumulated flag bits ; NxtToken - Use to chk for eo expr(sp/cr), comma, ) ; Error if -ve ; SavSEF - prev subexpr's RelExprF ; RelExprF - non-zero if subexpr is evaluated fr a relocatable addr ; - zero, it's fr an abs addr ; Ret ; (A)= ; C=0 - no errors parsing ; C=1 - err during eval ; ; NB. If relocatable code is generated, only +,- can be used ; EvalExpr LDA #$00 STA RelExprF ;Assume expr's val is absolute not relative STA ExprAccF STA NxtToken STA GblAbsF ;Assume ZDEF/ZREF JSR SkipSpcs ; ; Check for the presence of the byte operators ; Set (Ret816F) ; (-1) - 16-bits; 0 - low 8-bits, 1 - hi 8-bits ; LDA #-1 ;Default is to ret a 16-bit value STA Ret816F LDA (SrcP),Y CMP #'<' ;EDASM not MERLIN! BNE L8601 INY INC Ret816F ;=0 BEQ L8606 ;Proceed to set to 1 L8601 CMP #'>' BNE L8608 INY L8606 INC Ret816F ;0-lobyte, 1-hibyte ; L8608 CMP #'-' ;unary ops BEQ L8610 CMP #'+' BNE L8618 ;Get on with it ; L8610 LDA #0 STA ValExpr ;Returned value STA ValExpr+1 BEQ L8628 ;always ; L8618 JSR EvalTerm ;The leading term is treated differently LDA NxtToken ;Err? BMI L869C ;Yes ; LDA Accum STA ValExpr ;Partial result LDA Accum+1 STA ValExpr+1 L8627 INY ;Eval [opr term] L8628 LDA (SrcP),Y LDX #6 L862C CMP Operators,X BEQ L8636 DEX BPL L862C ;Chk next operator BMI L8662 ;No hit ; L8636 CPX #2 ;+/-? BCC L864E ;Yes ; ; Perform additional checks for the operators ; /,;,&,^,| which cannot operate on rel expr/sub-expr ; LDA RelExprF ;Is it a relative subexpr? BEQ L864E ;No, abs LDA PassNbr BEQ L864E BIT RelCodeF ;REL code output? BPL L864E ;No, BIN L8646 LDX #$08 ;rel exprn op JSR L87FB JMP L869C ; L864E BIT RelCodeF BPL L865C ;BIN BIT Ret816F ;Are we returning a 16-bit value? BMI L865C ;Yes LDA #$10 ;Was an EXTeRNal symbol used BIT ExprAccF ; during evaln? BNE L8646 ;Yes L865C JSR EvalSExpr ;Eval new sub expr JMP L8627 ;Next [opr term] ; L8662 LDX Ret816F ;-1,0,1 BMI L8674 ;Return 16-bit value BEQ L8670 ;Return val of lobyte ; LDA ValExpr ;Save lobyte STA Lower8 ; here and LDA ValExpr+1 ; return val of hibyte STA ValExpr ; by storing it here L8670 LDA #0 STA ValExpr+1 ; L8674 JSR GNToken ;Chk for comma, ) and cr/space ORA NxtToken ;In case of err STA NxtToken L867B LDA NxtToken DEY ;Index prev char CMP #$80 ;C=1 if err RTS REP 50 ; ; We are going to process a new subexpression ; after the operator ; X=0-6 ; EvalSExpr LDA RelExprF STA SavSEF ;Save it LDA #$00 ;Assume absolute value STA RelExprF LDA L888E,X ;Get JMP addr-1 hibyte PHA LDA L8895,X ;lo byte PHA INY JSR EvalTerm LDA NxtToken BNE L869A RTS ;Combine the 2 subexprs ; L869A PLA ;Dump JMP addr PLA L869C LDY #0 DB $24 L869F INY JSR ChrGot2 ;alphanumeric char? BCC L869F ;Yes, skip JSR GNToken ;Is it cr/space,comma,) BNE L869F ;No BEQ L867B ;always REP 50 ; ; Entry: ; (A)=char to check ; Ret: ; Z=1, (A)=0 if space/cr (white space) ; (A)=1 if char is , ; (A)=2 if char is ) ; Z=0, (A)=err token ; (Y)-unchanged ; GNToken JSR WhiteSpc PHP ;Save Z bit TAX ;Save char in X-reg LDA #$00 PLP ;Was is a cr/space? BEQ doRet7 ;Yes LDA #$01 CPX #',' BEQ doRet7 LDA #$02 CPX #')' BEQ doRet7 LDA #$34+$80 ;err token doRet7 RTS REP 50 ; ; Process a term where ; Term := Constant, Identifier ; If a term is an idfer, look up its value ; Ret: ; (Y)=index src line? ; (Accum)= Term's 16-bit value ; NB. Y-reg seems to have a dual purpose. To index the ; src line and to index an entry of the symbol table ; Its returned value must be monitored and adjust correctly ; Todo: Need to check this more closely. ; EvalTerm JSR AdvSrcP ;On ret, (Y)=0 STY Accum STY Accum+1 JSR ChrGot ;Get 1st char BCC L8716 ;Alphabetic char => idfer BEQ L86D6 ;Numeric char JMP L8781 ;Not alphanumeric ; ; Decimal constant ; L86D6 LDA (SrcP),Y ;Get numeric char SEC SBC #'0' ;$30-$39 -> 0-9 CLC ADC Accum STA Accum BCC L86E6 INC Accum+1 BEQ L870E ;Overflow L86E6 JSR ChrGet ;Look 1 char ahead BEQ Mul10 ;If numeric, continue DEY ;else move back and ret RTS ; ; The next char is numeric so the ; accumulated result must be x 10 ; before we loop back to process it ; Logic: 2R x 2 x 2 + 2R = 10R ; Mul10 JSR Mul2 ;2R BCS L870E LDA Accum+1 ;save temporarily PHA LDA Accum JSR Mul2 ;2R x 2 BCS L870D JSR Mul2 ;4R x 2 BCS L870D ADC Accum ;+ 2R STA Accum PLA ADC Accum+1 STA Accum+1 BCC L86D6 ;Loop back to process the next char PHA ;overflow L870D PLA L870E JMP L87F9 ;error ;= Mul2 ASL Accum ROL Accum+1 RTS ; ; Identifier ; L8716 JSR RsvdId ;Chk single A,X,Y BCC L871C RTS ;error ; L871C JSR FindSym BCS L8757 ;Idfer's not in symbol table TAX ;Save idfer's flag byte CLC BMI L8757 ;Idfer's undefined AND #external ;0001 0000 Is it declared as an EXTeRNal? BIT ExprAccF BEQ L8734 ;Ifder is not EXTeRNal STX SavFByt ;Save flag byte here while LDX #$40 ; we report Duplicate EXT/ENT JSR RegAsmEW LDX SavFByt ;Get flagbyte back L8734 TXA ; into (A) L8735 AND #external+fwdrefd;0001 0001 ORA ExprAccF STA ExprAccF TXA ;Test old flag byte AND #external ;0001 0000 BEQ L874A ;No, not EXTeRNal LDA PassNbr BEQ L8754 LDA (SymP),Y ;LoByte of value field STA GblAbsF ;0=>ZDEF/ZREF BNE L8754 ;Its ENTRY/EXTRN ; L874A LDA (SymP),Y ;Get value of symbolic idfer STA Accum ; & ret it here INY LDA (SymP),Y STA Accum+1 DEY L8754 DEY DEY RTS ; ; Identifer is undefined ; (A)-symbol's flag byte ; (Y)-indexing symbol's value field if symbol was found ; (Y)=0 if symbol not found ; L8757 LDX PassNbr BEQ L876F ;Its pass 1 BIT Bit02 ;Is No-such-label error? BEQ L8764 ;No INC ErrorF ;Flag as err since its pass 2 BNE L8769 ;=1 L8764 ORA #nosuchlabel ;0000 0010 DEY STA (SymP),Y ;Modified flag byte L8769 LDX #$00 ;Undefined idfer DEY ;what's this for? JMP L87FB ;Go report it ; L876F TAX ;(A)=flag byte LDA #fwdrefd ;0000 0001 BCC L8735 ;Symbol was found but undefined ORA ExprAccF ;Symbol not found STA ExprAccF LDA #undefined+fwdrefd;symbol's flag byte JSR AddNode DEY DEY DEY ;Indexing last char of symbolicname? RTS ; ; 1st char is non-alphanumeric ; Is it an ASCII char const? ; L8781 CMP #''' ;Opening single quote? BNE L879E ;No STY Accum+1 ;Zero the hibyte INY LDA (SrcP),Y ;Get char within quotes CMP #CR BNE L8791 JMP L880F ; L8791 ORA msbF STA Accum INY LDA (SrcP),Y ;Look for a CMP #$27 ; closing single quote BEQ doRet8 ;Got one DEY ;Move back doRet8 RTS ; ; Program counter reference ; L879E CMP #'*' ;Do we have a star? BNE L87AF ; LDA #relative ;Flag symbol's val is relative STA RelExprF ; & not an absolute addr LDA PC STA Accum LDA PC+1 STA Accum+1 RTS ; ; Checks for bin/octal/hexdec const ; L87AF CMP #'%' ;binary BNE L87B9 LDA #'2' LDX #$01 BNE L87CB ;always ; L87B9 CMP #'$' ;hexdec BNE L87C3 LDA #$C0 ;'@'+$80 LDX #$04 BNE L87CB ;always ; L87C3 CMP #'@' ;octal BNE L880F LDA #'8' LDX #$03 L87CB STA RadixCh ;=$32,$38,$C0 STX BitsDig ;=$01,$03,$04 ; ; Conversion starts here ; L87CF JSR ChrGet ;Is next char hexdec? BVC L8808 ;No CMP #'9'+1 BCC L87DA SBC #$07 ;'A'-'F' ($41-$46) -> $3A-$3F L87DA CMP RadixCh BCS L8808 ;Not valid LDX BitsDig CPX #$03 BEQ L87E8 ;Octal BCS L87E9 ;HexDec ; ASL ;binary ASL L87E8 ASL L87E9 ASL ASL ASL ASL ; ; binary x000 0000, octal xxx0 0000 hex xxxx 0000 ; (X)=# of shifts (% - 1, @ - 3, $ - 4) ; L87ED ASL ROL Accum ROL Accum+1 BCS L87F9 ;Overflow DEX BNE L87ED BEQ L87CF ;Process another numeral ; L87F9 LDX #$06 ;overflow L87FB STX NxtToken JSR RegAsmEW LDA #$80 ORA NxtToken STA NxtToken ;$80,$86,$88,$8A NOP RTS ; L8808 DEY ;Move back JSR ChrGot BVC L880F ;Char is not hexdec RTS ; L880F LDX #$0A ;expr syntax JMP L87FB ; ; ; operator ; ExprMUL JSR AdvSrcP STY ValExpr+2 ;zero these STY ValExpr+3 LDY #16 ;# of times L881D LDA ValExpr LSR BCC L882E ; CLC LDX #-2 L8825 LDA ValExpr+4,X ;$A1-$A2 ADC Accum+2,X ;$AF-$B0 STA ValExpr+4,X INX BNE L8825 ; L882E LDX #3 L8830 ROR ValExpr,X DEX BPL L8830 DEY BNE L881D RTS ; ; / operator ; ExprDIV JSR AdvSrcP STY ValExpr+2 STY ValExpr+3 ;zero these LDY #16 L8842 ASL ValExpr ;dividend ROL ValExpr+1 ROL ValExpr+2 ROL ValExpr+3 SEC LDA ValExpr+2 SBC Accum ; divisor TAX LDA ValExpr+3 SBC Accum+1 BCC L885C STX ValExpr+2 STA ValExpr+3 INC ValExpr L885C DEY BNE L8842 RTS ; ; - operator ; ExprSUB LDA RelExprF EOR SavSEF ;prev subexpr's RelExprF STA RelExprF LDA Accum+1 ;Do 1's complement EOR #$FF STA Accum+1 LDA Accum EOR #$FF SEC ;Proceed to add 1 BCS L887C ; giving 2's complement ; ; + operator ; ExprADD LDA SavSEF ;Get prev subexpr's RelExprF ORA RelExprF STA RelExprF CLC LDA Accum L887C ADC ValExpr STA ValExpr LDA Accum+1 ADC ValExpr+1 STA ValExpr+1 RTS ; Operators DB $2B ;+ DB $2D ;- DB $2A ;; DB $2F ;/ DB $21 ;! EOR DB $5E ;^ AND DB $7C ;| OR ; ; This table of JMP (via RTS) addresses is split into 2 parts ; L888E DB ExprADD-1 ;lobyte DB >ExprSUB-1 DB >ExprMUL-1 DB >ExprDIV-1 DB >ExprEOR-1 DB >ExprAND-1 DB >ExprORA-1 ; ; | operator bitwise OR ; ExprORA LDA Accum ORA ValExpr STA ValExpr LDA Accum+1 ORA ValExpr+1 STA ValExpr+1 RTS ; ; ^ operator bitwise AND ; ExprAND LDA Accum AND ValExpr STA ValExpr LDA Accum+1 AND ValExpr+1 STA ValExpr+1 RTS ; ; ! operator - bitwise EOR ; ExprEOR LDA Accum EOR ValExpr STA ValExpr LDA Accum+1 EOR ValExpr+1 STA ValExpr+1 RTS REP 50 ; ; Part of symbol table handler ; ($88C3) Find the key ; HeaderT-table of ptrs to singly list of keys with same hash value ; Ret: ; C=1 - Symbol not in table ; (Y)=0 ; C=0 - Symbol in table ; (A) = flag byte ; (Y)-indexing lobyte value field/indexing next char of src line ; ; PrvSymP would be set correctly for existing chains ; FindSym JSR HashFn ;Hash the label LDY HeaderT+1,X ;(X)=hashed value x 2 BEQ L8908 ;Empty slot => Not Found! ; ; Get ptr to 1st node in singly linked list (chain) ; LDA HeaderT,X FindLoop STA SymP STY SymP+1 STA PrvSymP STY PrvSymP+1 ; LDY #0 LDA (SymP),Y STA NxtSymP ;Point to next node INY LDA (SymP),Y ; in chain STA NxtSymP+1 ;If NIL ($0000) end of chain ; LDA #2 ;Skip past link pointer CLC ADC SymP ; to point @ the symbolic name STA SymP BCC L88EC ;This will allow us to use the INC SymP+1 ;same (Y) index for SrcP & SymP ; L88EC LDY #-1 ;Prepare to get 1st char of src line L88EE JSR ChrGet2 ORA #$80 CMP (SymP),Y BEQ L88EE ;Got a match, try next char AND #$7F ;Match last char of symbolic name CMP (SymP),Y ;Do we have a complete match? BNE L8902 ;No JSR ChrGet2 ;Maybe but is next char alphanumeric? BCS L890A ;No, probably a CR/SPACE => total match ; L8902 LDA NxtSymP ;On fall thru, a partial match LDY NxtSymP+1 ;End of this chain? BNE FindLoop ;No, continue with next node in chain L8908 SEC ;Flag symbolic name not found RTS ; L890A LDA (SymP),Y ;Get symbol's flag byte BMI L891A ;Not defined yet ; AND #%10111111 ;Set it to referenced STA (SymP),Y PHA ;Save flag byte AND #relative ;Retain this bit ORA RelExprF STA RelExprF PLA ;Restore ; L891A CLC ;Flag symbolic name found INY ;Indexing value field RTS ; or 1st char in next src line? REP 50 ; ; HashFn ; The Header Table can have at most 128 entries. Each ; entry is a 2-byte pointer (called a HEADER NODE) to a ; singly linked list of nodes (chain of nodes). ; Only the first 3 chars of a symbolic name are used ; by this hashing function. ; Ret: ; Y - preserved ; (X)=8-bit value which is used to index HeaderT ; HashFn TYA PHA ;save (Y) LDA #0 STA HashIdx ;zero the hash value JSR ChrGot2 ;1st char of label AND #%00000011 ;0000 00xx LSR ROL HashIdx LSR ROL HashIdx ;0000 00xx ; LDA HashIdx PHA ;save temporarily LDA #0 STA HashIdx JSR ChrGet2 ;Is 2nd char alphanumeric? BCC L8947 ;yes ; ; one-char label ; PLA ;Discard hashed value PLA ;restore Y-reg TAY PHA LDA (SrcP),Y ;Get char again ($41-$5A) AND #%00011111 ;$01-$1A (note: A,X,Y may be missing) ASL ASL JMP L897D ; L8947 AND #%00000111 ;0000 0yyy LSR ROL HashIdx LSR ROL HashIdx LSR ROL HashIdx ;=0000 0yyy ASL HashIdx ;=0000 yyy0 ASL HashIdx ;=000y yy00 PLA ;(A)=0000 00xx EOR HashIdx PHA ;(A)=000y yyxx LDA #$00 STA HashIdx JSR ChrGet2 ;Is 3rd char alphanumeric? BCC L8968 ;Yes PLA ;2-char label field ASL ASL ;0yyy xx00 BPL L897D ;always ; ; 3rd char ; L8968 AND #%00000111 ;0000 0zzz ASL ASL ASL ASL ASL ASL ROR HashIdx ;(HashIdx)=z000 0000 ASL ROR HashIdx ;(HashIdx)=zz00 0000 ASL ROR HashIdx ;(HashIdx)=zzz0 0000 LSR HashIdx ;(HashIdx)=0zzz 0000 PLA ;(A)=000y yyxx EOR HashIdx ; L897D ASL ;x2 to make hash value into an index STA HashIdx ; 0,2,4,...,254 TAX PLA ;restore (Y) TAY RTS REP 50 ; RsvdId JSR IsAXY ;Chk if reserved idfer BCC doRet9 ;No LDX #$1E ;Reserved idfer err JMP RegAsmEW REP 50 ; ; Chk for a single 'A','X','Y' in label/operand field ; C=1 - Yes ; (X) & (Y) - unchanged ; IsAXY JSR ChrGot2 ;Patch here if we want the letters CMP #'X' ; A,X,Y to be used as labels/operands BEQ L899F CMP #'A' BCC doRet9 BEQ L899F CMP #'Y' BNE L89A7 L899F JSR ChrGet2 ;Is next char alphanumeric? DEY ;Backup to 1st char BCC doRet9 ;Yes SEC RTS L89A7 CLC doRet9 RTS REP 50 ; ; ($89A9) Add a node ; Entry: ; (A)=initial value of flag byte of the Symbol ; ref pg 231 of manual for details ; Ret: ; C=0 - succ ; (Y)=index last byte of entry (Hi-byte) ; C=1 - fail ; The bits of the flag byte are defined as follows: ; $80 - undefined ; $40 - unreferenced ; $20 - relative to beginning of module ; $10 - External ; $08 - Entry ; $04 - macro (not implemented) ; $02 - No such label ; $01 - forward referenced ; Layout of Node ; ptr to next node in chain (set to NIL) ; symbolicname (variable in length) ; flag byte ; 16-bit value ; NB. 1) msb of all chars of symbolic name ; except the last one are on ; 2) The size of a node structure is not fixed. ; Symbolic names with the same hash value (collision) ; are connected together in a singly linked list. ; AddNode PHA ;Save flag byte LDY #0 JSR ChrGot BCC L89B4 SEC PLA RTS ; L89B4 LDX HashIdx ;Is there already a chain LDA HeaderT+1,X ; associated with this value? BNE L89C8 ;Yes LDA #>HeaderT ;Start a new singly linked list CLC ADC HashIdx ;=$xx STA PrvSymP ;Point @ $BCxx LDA #