Krusader 1.2.1 ACIA...

Discuss software for the Apple 1/replica 1

Krusader 1.2.1 ACIA...

Postby fsafstrom » Mar Thu 15, 2007 10:24 pm

Thanks to Ken I was able to port Krusader to use ACIA in just an hour.

He told me to change the two subroutines for getting a char and to print a char and that is pretty much what I did.

The code is fairly big so I'm not posting the source...
You need the EWoz mon to load the Intel format.

Just load it and start @ $6100

Have fun...

Code: Select all
:10610000A91F8D03C0A90B8D02C0A90385F8A92082
:1061100085FFA96C85F9A21BBD7E6E20E96ECAD0F1
:10612000F7CA9A207B61D8A900855B20D861A20FAD
:106130008658865920C06EA93F20E96E20BB6E208C
:10614000C56EC908F0E0C90DF00820E96E9500E8B9
:10615000D0EDA50FF0D0A510F004C920D00EA20CF0
:10616000BD416EC50FF00ECAD0F64848A00368685E
:10617000208165D0B120E0614C2661A900A885FE90
:1061800091FEA5FF85FDA90085FA85FB85FC6020B1
:106190007B61A511D002A90191FE6020B561F0CC10
:1061A00020C06EA53FA63E4C816C20B561F0BD209D
:1061B000C06E6C3E00A202B50FF0084820EB686884
:1061C000E8F0AB60A5F5853EA5F6853F60A53E8568
:1061D000F5A53F85F660A920A22795FFCAD0FB60F0
:1061E000BD4D6E48BD596E4860207B614C6C62208D
:1061F0008261203162F003206763A215E8A000B13C
:10620000FCF02D20866320F465CAD0F120C56EC94C
:106210001BF01DC90DD0E3F0E320636320C06EA224
:1062200004B5FB20D66EE003D003209A6ECAD0F1ED
:1062300060A0008430A201B50FF025C920F007C985
:1062400024F003E8D0F1E630A924950F20756AE820
:10625000F05FA53E995400C8A53F995400C8D0D717
:10626000A4306020316288D04820DB62203162E8AF
:10627000F03F98D00620636318900320676320F2F4
:1062800063E0FFF0AB862FA5FD85518553A5FC8506
:106290005018652F85529002E65320B4622039636E
:1062A000A000B9000091FCC8C42FD0F620F465D03E
:1062B000CD4C6C61A2FCB5FE48E8D0FA206363388F
:1062C000A5FCE5508554A5FDE5518555E654D00261
:1062D000E655A2046895F9CAD0FA60203162F0D17F
:1062E0008430206763E0FFF0C8A5FC8552A5FD85DA
:1062F00053A5304AF00CA657A456E455D002C45416
:1063000090AFC8D001E886558454206763A5FC850A
:1063100050A5FD855120B462A000A655F00EB150E5
:106320009152C8D0F9E651E653CAD0F2A654F0080B
:10633000B1509152C8CAD0F860A655188A655185E7
:1063400051188A65538553E8A454F00E88F007B1BC
:1063500050915288D0F9B150915288C651C653CA53
:10636000D0ED60A9FF8555208261A454C4FAD006FF
:10637000A655E4FBF051A0FFC8B1FCD0FB98F04556
:10638000C820F465D0E420C06E862F200665C820A2
:10639000B16EA200B504F00620E96EE8D0F6A62F93
:1063A0006020C56EC909D002A920C920101AA868AA
:1063B000686868C008F03BC00DD00AE004F029A965
:1063C000009500F05CA2FF60E027101AC95E10166D
:1063D0003860C92EF0FAC930300CC93A30F2C941E0
:1063E0003004C95B30EA1860A902AA8500A90085BB
:1063F000016020D661A900851D20C06E20B16EA26B
:1064000004A90A20B46420DC64A504C93BF00DA9EA
:106410000E20B46420DC64A91D20B464A90020B45B
:1064200064A2008651A9208555A9048550A901853B
:106430005420EF64A404C03BD004A90BD0638A4865
:10644000186656A20338B50AE940A0054A665666A2
:106450005788D0F8CAD0EEA238BD026DC556D00715
:10646000BD3A6DC557F003CAD0EFCA8AC9FFD0192B
:10647000A50BC92ED00CA205A50CDD656EF009CACE
:10648000D0F868A0014C8165CAA8C868AA9400E841
:10649000A90F8550A901855420EF64862FE62FA906
:1064A0001D8550A9008554855520EF64E42FD00345
:1064B000CA95FF60855420A16390FB20E96E95008A
:1064C000E8C920F005E454D0ED60A554F0E8E454A8
:1064D000F0F7A920950020E96EE8D0EEB5FFC920BD
:1064E000F00720A163C920D0F99500E84CE96EA01F
:1064F00000B150F00BC555F0079500E8E650D0F11B
:10650000A5549500E86020D661A000A204B1FCF07B
:106510004DC902D005C8A900F046C901F006950092
:10652000E8C8D0E9A504C93BD004A20BD02DC8B15E
:10653000FCAACA863CE0381009984820B36B68A8CA
:10654000D006860CA92E850BC8A20FB1FCF011C98C
:1065500001D005C8A21DD0F39500E8C8D0EDA2FE79
:1065600095006020AC6520C06E20106720D065E8E3
:10657000F00FE0FFD0F6E658202867E8F0034C1053
:106580006720C06EA205BD6A6E20E96ECAD0F7987A
:10659000188A690388D0FBA8A203B96D6E20E96E42
:1065A000C8CAD0F6CAA559D0264C86632082618518
:1065B0005885EB85E985F5A5F885F620036786EA19
:1065C000A900852B85298546A4F9C8842A844760BB
:1065D000200665E0FEF01DE004F018A9008559854D
:1065E00058855A205C66E0FFF01DA000B1FCF00366
:1065F000C8D0F9C8A5FC844418654485FC9002E61F
:10660000FDE6FAD002E6FB60A43CB98D6DA63D180C
:106610007DC56DE00BF00EE002D011C028300DC03A
:1066200030B0096908C035D003186904204766C92D
:1066300000D0032047668AF0CECAF0CBA53EE00822
:106640003005204766A53FA00091F5E6F5D002E6AB
:10665000F66020C167E0FFD0AFA00260A504C93B8F
:10666000F0A5A60BE02ED00DA60CE04DD0034CCE2D
:1066700066E03DF047C920F00320F769A50BC92E5D
:10668000D0D0A200A50CC953F0198558209268E813
:10669000F00CA53EA60CE057F0A8A63FF0A9A00379
:1066A000A2FF60B50FC927D0F5E8B50FF0F0C927F4
:1066B000F009204766E00ED0F0F0E360855820D660
:1066C0006390DBA200209268E8F0D34CFA6920D6F0
:1066D0006390CBA000A50FF014C920F010200E6726
:1066E000A200A50F20756AE8F0B420CD6120F769FB
:1066F000E0FFF0C7202867E0FFF0C0209F6EA900F0
:10670000200E67A20086EE86ECA6F986ED6085581D
:10671000A5F6A6F5A458F00D48209A6E68E000D0C2
:106720000338E901CA4C816CA62BF0728659864564
:10673000A5F548A5F64820C065A000A55885488461
:106740005AB146C92ED0028558B146991D00C8C01D
:1067500006D0F6B14685F5C8B14685F6C8B146857E
:1067600054209669E0FFF047A55AF004A5549150D3
:1067700020DB68A000B1F5291FC910F022204B666C
:10678000A53E20426618A546690985469002E6475F
:10679000A5488558C645D0A16885F66885F560206E
:1067A0007A68E0FFF009A001A53E91F54C8567A04D
:1067B0000020BB6EB14620E96EC8C006D0F688D076
:1067C000D7A2FF863DA53CA60FF004E020D00EA284
:1067D00000205568E0FFD035A2014C5568E023F059
:1067E0000EA203205568E0FFF024A50F4C6768C98E
:1067F0002CF071A202C935F007205568E0FFF00DBA
:10680000863DCA209268E8F05BA53FD05760A200A1
:10681000A50FC928D001E820EB68E0FFF0EF20B613
:106820006AE0FFF0E8863DE006D00EA53CC928905E
:1068300008C930B004A20BD028A006B92F6EC53C01
:10684000D00EBE356EE43DF018BE3B6EE43DF01157
:1068500088D0E8A63DA53CDD736D9008DD806DB065
:1068600003863D60A2FF60A200863E863FC92AD013
:106870000620C46120156920EB6838A53EE5F58542
:106880003EA53FE5F6853FF004E63FD0D7C63EC6BD
:106890003E60B50FF0CEC927F0034CEB68E8A900C5
:1068A000853FB50F853EE8B50FC927D0B7E8B50FCE
:1068B000F07CC920F07848E8B50F206B6BE0FFD082
:1068C000026860855468C92BF009A5541849FF690E
:1068D000018554A55AF004A5549150A5541002C640
:1068E0003F18653E853E9002E63F608656B50FC96B
:1068F0003CF004C93ED0058558E8B50F20D263B0FE
:106900000920756AE0FFF024D00B862F207869E01B
:10691000FFF01BA62FE8B50F20D263B0F8C92BF00B
:1069200004C92DD00A20B668E0FFD0E9A00360A01A
:1069300000A558C93CF008C93ED006A53F853E8455
:106940003FB50F991D00F00AC920F006E8C8E00E17
:10695000D0EFA900991D00A456A924990F00C8A53D
:106960003FF003209C6BA53E209C6BA200B51D99B7
:106970000F00F0BAE8C8D0F5A000C006F01820D289
:10698000639009991D00E8B50FC8D0EEA920991DA4
:1069900000C8C006D0F8A91D8542A2008643A906FA
:1069A000852EA908852DA51DC92EF01120A46AF0F9
:1069B00013A006B140853EC8B140853F60A20320C8
:1069C000A46AD0EDA558D04F20C461A52A8551A551
:1069D00029A62BF00A1869099002E651CAD0F6855B
:1069E00050E62BA52BC9551032A91D855A8552207A
:1069F0005D6AC88A91506020C461A90485528542AD
:106A0000A2008643A906852EA504C92ED002A203A2
:106A100020A46AF00B6868A005D002A004A2FF6061
:106A2000A904A604E02EF01738A5E9E908B002C6CB
:106A3000EA85E9E6EBF0E48550A5EA8551D01EA58C
:106A4000ED8551A5ECA6EEF00A1869089002E65112
:106A5000CAD0F68550E6EEA5EEC92010BEA000848F
:106A600053A206B1529150C8CAD0F8A53E9150C861
:106A7000A53F915060C924D0A4841E20326BE0FF52
:106A8000F09B851DA000843FCACAB50FC924F0063B
:106A9000206B6B38B00320876B993E00C8C41DD0B3
:106AA000E7A41E60B5E98540B5EA8541B5EB852CC4
:106AB00020466BE0FF60A200A904B40FC028D004F8
:106AC000186903E84820326BA8CAA53CC921F00424
:106AD000C923D001C868E8F05688F003186906A8F1
:106AE000B50FF004C920D014A50FC928F041C00F7C
:106AF000103DC007F03930018898AA60C929D00B31
:106B0000A920850FE8B50FC92CD0D5B50FC92CD059
:106B10001EE8B50FC958F00DC959D013A50FC928E3
:106B2000F00D950DC8C8B50DC929F003E8D0B1A284
:106B3000FF60A000E8C820886BC9FFD0F7984AF032
:106B4000EEC903B0EA60A52CF0E5A200A0FFC8C41E
:106B50002EF0DEB140D142F0F5E8E42CF0D1A540B2
:106B600018652D854090E5E641B0E120886BC9FFAE
:106B7000F0BD4820876BCAC9FFD0026860854468B1
:106B80000A0A0A0A654460E8B50F4930C90A900844
:106B90006988C9FA9003290F60A9FF604820F06C4A
:106BA00020A46B68290F0930C93A90026906990F31
:106BB00000C860BD036D8556BD3B6D8557A200A919
:106BC00000A005065726562A88D0F86940950BA4E0
:106BD0005BF00320E96EE8E003D0E46020B561F0EB
:106BE0000320CD61A913852B20F66B209B6C85F5C6
:106BF00084F6C62BD0F220886CA1F5A84A90096AC9
:106C0000B014C9A2F01029874AAABDD26D90032002
:106C1000F06C290FD004A080A900AABD166E8529AA
:106C20002903852A9820AA6CA00048B1F520D66EC9
:106C3000A20120946CC42AC890F1A203865BC00410
:106C400090F068AA20B36B20926CA42AA206E003FD
:106C5000F01E0629900EBD236E20E96EBD296EF050
:106C60000320E96ECAD0E7865B608830E520D66EE7
:106C7000A529C9E8B1F590F2209E6CAAE8D001C818
:106C80009820D66E8A4CD66E20C06EA5F6A6F5204A
:106C9000816CA20320BB6ECAD0FA6038A52AA4F684
:106CA000AA10018865F59001C8608554298FC98AAA
:106CB000F0430AC910F037A5540A69802A0A291F2F
:106CC000692048A554299FF01B0AC920F010290605
:106CD000D02F682907C90310026902691F6068295B
:106CE0000769186068AABDCA6C6016211718A554F8
:106CF0004A4A4A4A6020EE6CC90ED00269FD690812
:106D0000606860821B8399821B839921A6A01B4B1C
:106D10001B4B99A6A6A0A4217314959514131515C1
:106D2000101013115412539D611C1C7C0B2B099DD8
:106D3000611B980C9364939D61214B2006204602B1
:106D40001202527242722CB208B048022670F070E1
:106D5000E0961226185286A6C6E68A62E468603279
:106D60003232308288E40602026086D8D8E4E43009
:106D70003046860030251924283428282128282345
:106D8000193430213834363030383430240818285B
:106D900038485868788898A8B8C8D8E8F88A9AAA6D
:106DA000BACAEA0040601030507090B0D0F01420A1
:106DB0004080A0C0E00121416181A1C1E1022242E5
:106DC0006282A2C2E20008000004141400100C1C2D
:106DD000182C042054300D800490032254330D806D
:106DE0000490042054330D8004900420543B0D8003
:106DF0000490002244330DC84400112244330DC8CE
:106E000044A9012244330D800490012244330D80B3
:106E100004902631879A002181820000594D919279
:106E2000864A859D2C292C23282459005824240087
:106E300022242535363704050502050504050A0B0D
:106E40000A0A4E4C58454D524449244156506161FE
:106E5000626262616B62FF656161E8EEDA6218A9E5
:106E6000DB6B1E629A8E4257533D4D203A5252457B
:106E70004D4E4541444453594E4F564653594D4E3D
:106E80004553534557204E454B20594220322E3111
:106E900020524544415355524B0DA92D4CE96E20CB
:106EA000C06EA200B50420E96EE8E006D0F620BB73
:106EB0006EA5FB20DF6EA5FA20D66EA9204CE96EE8
:106EC000A90D4CE96EAD01C02908F0F9AD00C0C9AB
:106ED000603002295F60484A4A4A4A20DF6E6829CA
:106EE0000F0930C93A90026906488D00C0AD01C053
:066EF0002910F0F96860B2
:006100019E
User avatar
fsafstrom
 
Posts: 154
Joined: Dec Tue 26, 2006 3:57 pm
Location: San Antonio, Texas

Re: Krusader 1.2.1 ACIA...

Postby hanso » Oct Tue 02, 2007 4:09 pm

fsafstrom wrote:Thanks to Ken I was able to port Krusader to use ACIA in just an hour.

He told me to change the two subroutines for getting a char and to print a char and that is pretty much what I did.

The code is fairly big so I'm not posting the source..


Can you show what changes and additions you made to the source? It will help me port Krusader to the Micro-KIM. And which assembler did you use?

Hans
hanso
 
Posts: 71
Joined: Sep Sat 22, 2007 1:35 pm
Location: Weesp The Netherlands

Postby fsafstrom » Oct Tue 02, 2007 5:36 pm

Hi Hans,

I used 6502.exe from http://home.pacbell.net/michal_k/6502.html
Since it was quite a while ago I did this I don't remember all details...
So I just went ahead and posted the whole source... ;-)

Code: Select all
; KRUSADER - An Assembly Language IDE for the Replica 1

; 6502 Version 1.2.1 - 27 February, 2007
; (c) Ken Wessen (ken.wessen@gmail.com)

; Notes:
;   - 8 bytes free (14 free if TABTOSPACE = 0)
;   - Entry points:
;      SHELL = $711C($F01C)
;      MOVEDN = $730E($F20E)
;      DEBUG = -($FE17)
;      XBRK = -($FE21) - debugger re-entry point
;      DSMBL = $7BDA($FADA)

TABTOSPACE = 1
UNK_ERR_CHECK = 0

MINIMONITOR = 0
DOTRACE = MINIMONITOR & 1
BRKAS2 = 1      ; if 1, BRK will assemble to two $00 bytes
         ; if set, then minimonitor will work unchanged
         ; for both hardware and software interrupts

   .org $6100
   .start MAIN

ACIA      = $C000
ACIA_CTRL   = ACIA+3
ACIA_CMD   = ACIA+2
ACIA_SR      = ACIA+1
ACIA_DAT   = ACIA

   
MONTOR   =$FF1F

; Constants

BS   =$08      ; backspace
SP   =$20      ; space
CR   =$0D      ; carriage return
LF   =$0A      ; line feed
ESC   =$1B      ; escape
INMASK  =$7F
   
LNMSZ   =$03
LBLSZ   =$06      ; labels are up to 6 characters
MNESZ   =$03      ; mnemonics are always 3 characters
ARGSZ   =$0E      ; arguments are up to 14 characters
COMSZ   =$0A      ; comments fill the rest - up to 10 characters

ENDLBL   =LNMSZ+LBLSZ+1
ENDMNE   =ENDLBL+MNESZ+1
ENDARG   =ENDMNE+ARGSZ+1
ENDLN   =ENDARG+COMSZ+1

SYMSZ   =$06      ; size of labels

LINESZ   =$27      ; size of a line
USESZ   =LINESZ-LNMSZ-1   ; usable size of a line
CNTSZ   =COMM-LABEL-1   ; size of content in a line
   
MAXSYM   =$20      ; at most 32 local symbols (256B) and
MAXFRF   =$55      ; 85 forward references (896B)
         ; globals are limited by 1 byte index => max of 256 (2K)
         ; global symbol table grows downwards
         
; Symbols used in source code

IMV   ='#'      ; Indicates immediate mode value
HEX   ='$'      ; Indicates a hex value
OPEN   ='('      ; Open bracket for indirect addressing
CLOSE   =')'      ; Close bracket for indirect addressing
PC   ='*'      ; Indicates PC relative addressing
LOBYTE   ='<'      ; Indicates lo-byte of following word
HIBYTE   ='>'      ; Indicates hi-byte of following word
PLUS   ='+'      ; Plus in simple expressions
MINUS   ='-'      ; Minus in simple expressions
DOT   ='.'      ; Indicates a local label
QUOTE   ='''      ; delimits a string
COMMA   =','
CMNT   =';'      ; indicates a full line comment

PROMPT   ='?'

EOL   =$00      ; end of line marker
EOFLD   =$01      ; end of field in tokenised source line
BLANK   =$02      ; used to mark a blank line

PRGEND   =$FE      ; used to flag end of program parsing
FAIL   =$FF      ; used to flag failure in various searches

; Zero page storage   
IOBUF   =$00      ; I/O buffer for source code input and analysis
LABEL   =$04      ; label starts here
MNE   =$0B      ; mnemonic starts here
ARGS   =$0F      ; arguments start here
COMM    =$1D      ; comments start here
FREFTL   =$29      ; address of forward reference table
FREFTH   =$2A
NFREF   =$2B      ; number of forward symbols
RECNM   =$2C      ; number of table entries
RECSZ   =$2D      ; size of table entries
RECSIG   =$2E      ; significant characters in table entries
XSAV   =$2F
YSAV   =$30
CURMNE   =$3C      ; Holds the current mne index
CURADM   =$3D      ; Holds the current addressing mode
LVALL   =$3E      ; Storage for a label value
LVALH   =$3F   
TBLL   =$40      ; address of search table
TBLH   =$41
STRL   =$42      ; address of search string
STRH   =$43
SCRTCH   =$44      ; scratch location
NPTCH   =$45      ; counts frefs when patching
PTCHTL   =$46      ; address of forward reference being patched
PTCHTH   =$47
FLGSAV   =$48

MISCL   =$50      ; Miscellaneous address pointer
MISCH   =$51      
MISC2L   =$52      ; And another
MISC2H   =$53   
TEMP1   =$54      ; general purpose storage
TEMP2   =$55   
TEMP3   =$56   
TEMP4   =$57
LMNE   =TEMP3      ; alias for compression and expansion routines
RMNE   =TEMP4
FRFLAG   =$58      ; if nonzero, disallow forward references
ERFLAG   =$59      ; if nonzero, do not report error line
HADFRF   =$5A      ; if nonzero, handled a forward reference
PRFLAG   =$5B

; want these to persist if possible when going into the monitor
; to test code etc, so put them right up high
XQT   =$E0

; these 6 locations must be contiguous
GSYMTL   =$E9      ; address of the global symbol table
GSYMTH   =$EA   
NGSYM   =$EB      ; number of global symbols
LSYMTL   =$EC      ; address of the local symbol table
LSYMTH   =$ED
NLSYM   =$EE      ; number of local symbols

; these 7 locations must be contiguous
REGS   =$F0
SAVP   =REGS
SAVS   =$F1
SAVY   =$F2
SAVX   =$F3
SAVA   =$F4
CURPCL   =$F5      ; Current PC
CURPCH   =$F6

CODEH   =$F8      ; hi byte of code storage area (low is $00)
TABLEH   =$F9      ; hi byte of symbol table area

; these 4 locations must be contiguous
LINEL   =$FA      ; Current source line number (starts at 0)
LINEH   =$FB      
CURLNL   =$FC      ; Current source line address
CURLNH   =$FD
      
SRCSTL   =$FE      ; source code start address
SRCSTH   =$FF   
   
; for disassembler
FORMAT   =FREFTL      ; re-use spare locations
LENGTH   =FREFTH
COUNT   =NFREF
PCL   =CURPCL
PCH   =CURPCH

; ****************************************
;    COMMAND SHELL/EDITOR CODE
; ****************************************

MAIN   
   LDA #$1F      ;* Init ACIA to 19200 Baud.
   STA ACIA_CTRL
   LDA #$0B      ;* No Parity.
   STA ACIA_CMD

   LDA #$03
   STA CODEH
   LDA #$20
   STA SRCSTH
   LDA #$6C
   STA TABLEH
   LDX #MSGSZ
.NEXT   LDA MSG-1,X
   JSR OUTCH
   DEX
   BNE .NEXT
   DEX
   TXS      ; reset stack pointer on startup
   JSR SHINIT   ; default source line and address data
;   JMP SHELL
; falls through to SHELL
        
; ****************************************
   
SHELL         ; Loops forever
         ; also the re-entry point
   CLD      ; just incase
   LDA #$00
   STA PRFLAG
   JSR FILBUF
   LDX #ARGS
   STX FRFLAG   ; set flags in SHELL
   STX ERFLAG
   JSR CRLF
   LDA #PROMPT
   JSR OUTCH   ; prompt
   JSR OUTSP   ; can drop this if desperate for 3 more bytes :-)
.KEY   JSR GETCH
   CMP #BS
   BEQ SHELL   ; start again
   CMP #CR
   BEQ .RUN
   JSR OUTCH
   STA IOBUF,X
   INX
   BNE .KEY   ; always branches
.RUN   LDA ARGS   
   BEQ SHELL   ; empty command line
   LDA ARGS+1   ; ensure command is just a single letter
   BEQ .OK
   CMP #SP
   BNE SHLERR
.OK   LDX #NUMCMD
.NEXT   LDA CMDS-1,X   ; find the typed command
   CMP ARGS
   BEQ GOTCMD
   DEX
   BNE .NEXT
   PHA      ; put dummy data on the stack
   PHA
SHLERR   
   LDY #SYNTAX
ERR2   PLA      ; need to clean up the stack
   PLA
   JSR SHWERR
   BNE SHELL
GOTCMD   JSR RUNCMD
   JMP SHELL   ; ready for next command

; ****************************************

SHINIT   
   LDA #$00
   TAY
   STA SRCSTL   ; low byte zero for storage area
   STA (SRCSTL),Y   ; and put a zero in it for EOP
TOSTRT         ; set LINEL,H and CURLNL,H to the start
   LDA SRCSTH
   STA CURLNH
   LDA #$00
   STA LINEL
   STA LINEH   ; 0 lines
   STA CURLNL
   RTS      ; leaves $00 in A
   
; ****************************************

PANIC
   JSR SHINIT
   LDA ARGS+2
   BNE .SKIP
   LDA #$01
.SKIP   STA (SRCSTL),Y   ; Y is $00 from SHINIT
   RTS

; ****************************************

VALUE   
   JSR ADDARG
   BEQ SHLERR
   JSR CRLF
   LDA LVALH
   LDX LVALL
   JMP PRNTAX
   
; ****************************************

RUN   
   JSR ADDARG
   BEQ SHLERR
   JSR CRLF
   JMP (LVALL)   ; jump to the address

; ****************************************

ADDARG         ; convert argument to address
   LDX #$02
   LDA ARGS,X
   BEQ .NOARG
   PHA
   JSR EVAL
   PLA
   ;CPX #FAIL
   INX
   BEQ ERR2;SHLERR
.NOARG   RTS

; ****************************************

PCTOLV
   LDA CURPCL
   STA LVALL
   LDA CURPCH
   STA LVALH
   RTS
   
; ****************************************

LVTOPC   
   LDA LVALL
   STA CURPCL
   LDA LVALH
   STA CURPCH
   RTS
      
; ****************************************

FILLSP
   LDA #SP
FILBUF         ; fill the buffer with the contents of A
   LDX #LINESZ
.CLR   STA IOBUF-1,X
   DEX
   BNE .CLR
   RTS
   
; ****************************************

RUNCMD   
   LDA CMDH-1,X
     PHA
     LDA CMDL-1,X
     PHA
     RTS

; ****************************************

NEW   
   JSR SHINIT
   JMP INSERT
   
; ****************************************

LIST         ; L    - list all
         ; L nnn - list from line nnn
   JSR TOSTRT
   JSR GETARG
   BEQ .PAGE   ; no args, list from start
   JSR GOTOLN   ; deal with arguments if necessary
.PAGE   LDX #$16-1   ; 22 lines per page
.LINE   INX
.NEXT   LDY #$00
   LDA (CURLNL),Y
   BEQ RET
   JSR PRNTLN
   JSR UPDTCL
   DEX      ; paging code
   BNE .NEXT
   JSR GETCH
   CMP #ESC   ; stop listing
   BEQ RET
   CMP #CR      ; CR for one more line
   BNE .PAGE   ; else one more page
   BEQ .LINE   ; always branches
   
; ****************************************

MEM   
   JSR TOEND   ; set CURLNL,H to the end
   JSR CRLF   
   LDX #$04
.LOOP   LDA CURLNL-1,X
   JSR OUTHEX
   CPX #$03
   BNE .SKIP
   JSR PRDASH
.SKIP   DEX
   BNE .LOOP
RET   RTS

; ****************************************

GETARG         ; get the one or two numeric arguments
         ; to the list, edit, delete and insert commands
         ; store them in TEMP1-4 as found
         ; arg count in Y or X has FAIL
   LDY #$00
   STY YSAV
   LDX #$01
.NEXT   LDA ARGS,X
   BEQ .DONE   ; null terminator
   CMP #SP      ; find the space
   BEQ .CVT
   CMP #HEX   ; or $ symbol
   BEQ .CVT
   INX
   BNE .NEXT
.CVT   INC YSAV   ; count args
   LDA #HEX
   STA ARGS,X   ; replace the space with '$' and convert
   JSR CONVRT
   ;CPX #FAIL
   INX
   BEQ LCLERR
   ;INX
   LDA LVALL
   STA TEMP1,Y
   INY
   LDA LVALH
   STA TEMP1,Y
   INY
   BNE .NEXT   ; always branches
.DONE   LDY YSAV
   RTS      ; m in TEMP1,2, n in TEMP3,4
   
; ****************************************

EDIT   
   JSR GETARG
   ;CPY #$01
   DEY
   BNE LCLERR
   JSR DELETE   ; must not overwrite the command input buffer
;   JMP INSERT
; falls through to INSERT

; ****************************************
   
INSERT   
   JSR GETARG   ; deal with arguments if necessary
   ;CPX #FAIL
   INX
   BEQ LCLERR
   ;CPY #$00   ; no args
   TYA
   BNE .ARGS
   JSR TOEND   ; insert at the end
   CLC
   BCC .IN
.ARGS   JSR GOTOLN   ; if no such line will insert at end
.IN   JSR INPUT   ; Get one line
   CPX #FAIL   ; Was there an error?
   BEQ RET;
   ; Save the tokenised line and update pointers
   ; tokenised line is in IOBUF, size X
   ; move up from CURLNL,H to make space
   STX XSAV   ; save X (data size)
   LDA CURLNH
   STA MISCH
   STA MISC2H
   LDA CURLNL
   STA MISCL   ; src in MISCL,H now
   CLC
   ADC XSAV
   STA MISC2L
   BCC .READY
   INC MISC2H   ; MISC2L,H is destination
.READY   JSR GETSZ
   JSR MOVEUP   ; do the move
   LDY #$00
   ; now move the line to the source storage area
   ; Y bytes, from IOBUF to CURLN
.MOVE   LDA IOBUF,Y
   STA (CURLNL),Y
   INY
   CPY XSAV
   BNE .MOVE
   JSR UPDTCL   ; update CURLNL,H
   BNE .IN      ; always branches

; ****************************************

LCLERR         ; local error wrapper
         ; shared by the routines around it
   JMP SHLERR

; ****************************************

GETSZ         ; SIZE = TEMP1,2 = lastlnL,H - MISCL,H + 1
   LDX #-$04
.LOOP   LDA CURLNH+1,X
   PHA      ; save CURLN and LINEN on the stack
   INX
   BNE .LOOP
   JSR TOEND
   SEC
   LDA CURLNL
   SBC MISCL
   STA TEMP1
   LDA CURLNH
   SBC MISCH
   STA TEMP2
   INC TEMP1
   BNE .SKIP
   INC TEMP2
.SKIP   LDX #$04
.LOOP2   PLA      ; get CURLN and LINEN from the stack
   STA LINEL-1,X
   DEX
   BNE .LOOP2
   RTS
   
; ****************************************

DELETE         ; Delete the specified range
         ; Moves from address of line arg2 (MISCL,H)
         ; to address of line arg1 (MISC2L,H)
   JSR GETARG
;   CPY #$00
   BEQ LCLERR
   STY YSAV
.DOIT   JSR GOTOLN   ; this leaves TEMP1 in Y and TEMP2 in X
   CPX #FAIL
   BEQ LCLERR
   LDA CURLNL
   STA MISC2L
   LDA CURLNH
   STA MISC2H   ; destination address is set in MISC2L,H
   LDA YSAV
   ;CMP #$01
   LSR
   BEQ .INC
   LDX TEMP4
   LDY TEMP3   ; Validate the range arguments
   CPX TEMP2   ; First compare high bytes
   BNE .CHK   ; If TEMP4 != TEMP2, we just need to check carry
   CPY TEMP1   ; Compare low bytes when needed
.CHK   BCC LCLERR   ; If carry clear, 2nd argument is too low
.INC   INY      ; Now increment the second argument
   BNE .CONT
   INX
.CONT   STX TEMP2
   STY TEMP1
   JSR GOTOLN
   LDA CURLNL
   STA MISCL
   LDA CURLNH
   STA MISCH
   JSR GETSZ
;   JMP MOVEDN
; falls through
   
; ****************************************
;   Memory moving routines
;  From http://www.6502.org/source/general/memory_move.html
; ****************************************

; Some aliases for the following two memory move routines

FROM   =MISCL      ; move from MISCL,H
TO   =MISC2L      ; to MISCL2,H
SIZEL   =TEMP1
SIZEH   =TEMP2

MOVEDN         ; Move memory down
   LDY #$00
   LDX SIZEH
   BEQ .MD2
.MD1   LDA (FROM),Y ; move a page at a time
   STA (TO),Y
   INY
   BNE .MD1
   INC FROM+1
   INC TO+1
   DEX
   BNE .MD1
.MD2   LDX SIZEL
   BEQ .MD4
.MD3   LDA (FROM),Y ; move the remaining bytes
   STA (TO),Y
   INY
   DEX
   BNE .MD3
.MD4   RTS
   
MOVEUP         ; Move memory up
   LDX SIZEH   ; the last byte must be moved first
   CLC      ; start at the final pages of FROM and TO
   TXA
   ADC FROM+1
   STA FROM+1
   CLC
   TXA
   ADC TO+1
   STA TO+1
   INX      ; allows the use of BNE after the DEX below
   LDY SIZEL
   BEQ .MU3
   DEY      ; move bytes on the last page first
   BEQ .MU2
.MU1   LDA (FROM),Y
   STA (TO),Y
   DEY
   BNE .MU1
.MU2   LDA (FROM),Y   ; handle Y = 0 separately
   STA (TO),Y
.MU3   DEY
   DEC FROM+1   ; move the next page (if any)
   DEC TO+1
   DEX
   BNE .MU1
   RTS       

; ****************************************

TOEND   
   LDA #$FF
   STA TEMP2   ; makes illegal line number
;   JMP GOTOLN   ; so CURLNL,H will be set to the end
; falls through

; ****************************************
   
GOTOLN         ; go to line number given in TEMP1,2
         ; sets CURLNL,H to the appropriate address
         ; and leaves TEMP1 in Y and TEMP2 in X
         ; if not present, return #FAIL in X
         ; and LINEL,H will be set to the next available line number
EOP   = LFAIL
GOTIT   = LRET
   JSR TOSTRT
.NXTLN         ; is the current line number the same
         ; as specified in TEMP1,2?
         ; Z set if equal
         ; C set if TEMP1,2 >= LINEL,H
   LDY TEMP1
   CPY LINEL
   BNE .NO
   LDX TEMP2
   CPX LINEH
   BEQ GOTIT
.NO   LDY #$FF
.NXTBT   INY      ; find EOL
   LDA (CURLNL),Y
   BNE .NXTBT
   TYA
   ;CPY #$00
   BEQ EOP      ; null at start of line => end of program
   INY
   JSR UPDTCL   ; increment CURLNL,H by Y bytes
   BNE .NXTLN   ; always branches
;.EOP   LDX #FAIL
;.GOTIT   RTS      ; address is now in CURLNL,H

; ****************************************

PRNTLN         ; print out the current line (preserve X)
   JSR CRLF
   STX XSAV
   JSR DETKN
   INY
   JSR PRLNNM
   LDX #$00
.PRINT   LDA LABEL,X
   BEQ .DONE   ; null terminator
   JSR OUTCH
   INX
   ;CPX #USESZ
   BNE .PRINT
.DONE   LDX XSAV
   RTS
      
; ****************************************

NEXTCH         ; Check for valid character in A
         ; Also allows direct entry to appropriate location
         ; Flag success with C flag
   JSR GETCH
   .if TABTOSPACE
   CMP #$09   ; is it a tab?
   BNE .SKIP
   LDA #SP
   .endif
.SKIP   CMP #SP      ; valid ASCII range is $20 to $5D
   BPL CHANM   ; check alpha numeric entries
   TAY
   PLA
   PLA
   PLA
   PLA      ; wipe out return addresses
   CPY #BS
   BEQ INPUT   ; just do it all again
.NOBS   CPY #CR
   BNE LFAIL
   CPX #LABEL   ; CR at start of LABEL means a blank line
   BEQ DOBLNK
   LDA #EOL
   STA IOBUF,X
   BEQ GOTEOL
LFAIL   LDX #FAIL   ; may flag error or just end
LRET   RTS
CHANM   CPX #LINESZ   ; ignore any characters over the end of the line
   BPL CHNO
   CMP #']'+1   ; is character is in range $20-$5D?
   BPL CHNO   ; branch to NO...
CHOK   SEC      ; C flag on indicates success
   RTS
CHKLBL   CMP #DOT   ; here are more specific checks
   BEQ CHOK
CHKALN   CMP #'0'   ; check alpha-numeric
   BMI CHNO   ; less than 0
   CMP #'9'+1
   BMI CHOK   ; between 0 and 9
CHKLET   CMP #'A'
   BMI CHNO   ; less than A
   CMP #'Z'+1   
   BMI CHOK   ; between A and Z
CHNO   CLC
   RTS      ; C flag off indicates failure
   
; ****************************************

DOBLNK   
   LDA #BLANK
   TAX      ; BLANK = #$02, and that is also the
   STA IOBUF   ; tokenised size of a blank line
   LDA #EOL   ; (and only a blank line)
   STA IOBUF+1
ENDIN   RTS   

INPUT   
   JSR FILLSP
   LDA #EOL   ; need this marker at the start of the comments
   STA COMM   ; for when return hit in args field
   JSR CRLF
   JSR PRLNNM
   LDX #LABEL   ; point to LABEL area
   LDA #ENDLBL
   JSR ONEFLD
   JSR INSSPC   ; Move to mnemonic field
   LDA LABEL
   CMP #CMNT
   BEQ .CMNT
   LDA #ENDMNE
   JSR ONEFLD
   JSR INSSPC   ; Move to args field
   LDA #ENDARG
   JSR ONEFLD
.CMNT   LDA #EOL
   JSR ONEFLD
GOTEOL   ;JMP TOTKN   
; falls through

; ****************************************

TOTKN         ; tokenise to IOBUF to calc size
         ; then move memory to make space
         ; then copy from IOBUF into the space
   LDX #$00
   STX MISCH
   LDA #SP
   STA TEMP2
   LDA #LABEL
   STA MISCL
   LDA #EOFLD
   STA TEMP1
   JSR TKNISE
   LDY LABEL
   CPY #CMNT
   BNE .CONT
   LDA #MNE
   BNE ISCMNT   ; always branches
.CONT   TXA      ; save X
   PHA      

;   JSR SRCHMN   ; is it a mnemonic?

SRCHMN        ; Search the table of mnemonics   for the mnemonic in MNE
         ; Return the index in A

CMPMNE         ; compress the 3 char mnemonic
         ; at MNE to MNE+2 into 2 chars
         ; at LMNE and RMNE
   CLC
   ROR LMNE      
   LDX #$03
.NEXT2   SEC
   LDA MNE-1,X
   SBC #'A'-1
   LDY #$05
.LOOP2   LSR
   ROR LMNE
   ROR RMNE
   DEY
   BNE .LOOP2
   DEX
   BNE .NEXT2

   LDX #NUMMN   ; Number of mnemonics
.LOOP   LDA LMNETB-1,X
   CMP LMNE
   BNE .NXT
   LDA RMNETB-1,X
   CMP RMNE
   BEQ .FND
.NXT   DEX
   BNE .LOOP
.FND   DEX      ; X = $FF for failure
;   RTS
   
   TXA
   CMP #FAIL
   BNE .FOUND
   LDA MNE      ; or a directive?
   CMP #DOT
   BNE .ERR
   LDX #NUMDIR
   LDA MNE+1
.NEXT   CMP DIRS-1,X
   BEQ .FDIR
   DEX
   BNE .NEXT
.ERR   PLA
   LDY #INVMNE
   JMP SHWERR
.FDIR   DEX
.FOUND   TAY      ; put mnemonic/directive code in Y
   INY      ; offset by 1 so no code $00   
   PLA      ; restore Y
   TAX
   STY IOBUF,X
   INX
   LDA #ARGS
   STA MISCL
   LDA #EOFLD
   STA TEMP1
   JSR TKNISE
   STX XSAV
   INC XSAV
   LDA #COMM
ISCMNT   STA MISCL
   LDA #EOL
   STA TEMP1
   STA TEMP2
   JSR TKNISE
   CPX XSAV
   BNE .RET
   DEX      ; no args or comments, so stop early
   STA IOBUF-1,X   ; A already holds $00
.RET    RTS   
   
ONEFLD         ; do one entry field
         ; A holds the end point for the field
   STA TEMP1   ; last position
.NEXT   JSR NEXTCH   ; catches ESC, CR and BS
   BCC .NEXT   ; only allow legal keys
   JSR OUTCH   ; echo
   STA IOBUF,X
   INX
   CMP #SP
   BEQ .FILL
   CPX TEMP1
   BNE .NEXT
.RET   RTS
.FILL   LDA TEMP1
   BEQ .NEXT   ; just treat a space normally
   CPX TEMP1   ; fill spaces
   BEQ .RET
   LDA #SP
   STA IOBUF,X
   JSR OUTCH
.CONT   INX
   BNE .FILL   ; always branches

; ****************************************
   
INSSPC   
   LDA IOBUF-1,X   ; was previous character a space?
   CMP #SP
   BEQ .JUMP
.GET   JSR NEXTCH   ; handles BS, CR and ESC
   CMP #SP
   BNE .GET   ; only let SP through
.JUMP   STA IOBUF,X   ; insert the space
   INX
   JMP OUTCH

TKNISE   
   LDY #$00
.NEXT   LDA (MISCL),Y
   BEQ .EOF
   CMP TEMP2
   BEQ .EOF   ; null terminator
   STA IOBUF,X
   INX
   INC MISCL
   BNE .NEXT
.EOF   LDA TEMP1
   STA IOBUF,X
   INX
   RTS

; ****************************************

DETKN         ; Load a line to the IOBUF
         ; (detokenising as necessary)
         ; On return, Y holds tokenised size
   JSR FILLSP
   LDY #$00
   LDX #LABEL
.LBL   LDA (CURLNL),Y
   BEQ .EOP   ; indicates end of program
   CMP #BLANK
   BNE .SKIP
   INY
   LDA #EOL
   BEQ .EOL
.SKIP   CMP #EOFLD
   BEQ .CHK
   STA IOBUF,X
   INX
   INY
   BNE .LBL
.CHK   LDA LABEL
   CMP #CMNT
   BNE .NEXT
   LDX #MNE
   BNE .CMNT   ; always branches
.NEXT   INY
   LDA (CURLNL),Y   ; get mnemonic code
   TAX
   DEX      ; correct for offset in tokenise
   STX CURMNE   ; store mnemonic for assembler
   CPX #NUMMN
   BPL .DIR
   TYA      ; save Y
   PHA   
   JSR EXPMNE
   PLA      ; restore Y
   TAY
   BNE .REST
.DIR   STX MNE+1
   LDA #DOT
   STA MNE
.REST   INY
   LDX #ARGS   ; point to ARGS area
.LOOP   LDA (CURLNL),Y
   BEQ .EOL   ; indicates end of line
   CMP #EOFLD
   BNE .CONT
   INY
   LDX #COMM   ; point to COMM area
   BNE .LOOP
.CONT   STA IOBUF,X
   INX
.CMNT   INY
   BNE .LOOP
.EOP   LDX #PRGEND
.EOL   STA IOBUF,X
   RTS

; ****************************************
;       ASSEMBLER CODE
; ****************************************

ASSEM         ; Run an assembly
   JSR INIT   ; Set the default values
   JSR CRLF
   JSR MYPRPC
.NEXT   JSR DO1LN   ; line is in the buffer - parse it
   ;CPX #FAIL
   INX
   BEQ SHWERR
   CPX #PRGEND+1   ; +1 because of INX above
   BNE .NEXT
   INC FRFLAG   ; have to resolve them all now - this ensures FRFLAG nonzero
   JSR PATCH   ; back patch any remaining forward references
   ;CPX #FAIL
   INX
   BEQ SHWERR
   JMP MYPRPC   ; output finishing module end address
;.ERR   JMP SHWERR

; ****************************************

SHWERR         ; Show message for error with id in Y
         ; Also display line if appropriate
   JSR CRLF
   LDX #ERPRSZ
.NEXT   LDA ERRPRE-1,X
   JSR OUTCH
   DEX
   BNE .NEXT
   TYA
   .if UNK_ERR_CHECK
   BEQ .SKIP
   CPY #MAXERR+1
   BCC .SHOW   ; If error code valid, show req'd string
.UNKWN   LDY #UNKERR   ; else show unknown error
    BEQ .SKIP
    .endif
.SHOW   CLC
   TXA      ; sets A to zero
.ADD   ADC #EMSGSZ
   DEY
   BNE .ADD
   TAY
.SKIP   LDX #EMSGSZ   
   .if UNK_ERR_CHECK
.LOOP   LDA ERRMSG,Y
   .else
.LOOP   LDA ERRMSG-EMSGSZ,Y
   .endif
   JSR OUTCH
   INY
   DEX
   BNE .LOOP
   ;LDX #FAIL
   DEX      ; sets X = #FAIL
   LDA ERFLAG
   BNE RET1
   JMP PRNTLN

; ****************************************
   
INIT
   JSR TOSTRT   ; leaves $00 in A
   STA FRFLAG
   STA NGSYM
   STA GSYMTL
   STA CURPCL   ; Initial value of PC for the assembled code
   LDA CODEH
   STA CURPCH
   JSR CLRLCL   ; set local and FREF table pointers
   STX GSYMTH   ; global table high byte - in X from CLRLCL
;   JMP INITFR
; falls through

; ****************************************

INITFR         ; initialise the FREF table and related pointers
   LDA #$00
   STA NFREF
   STA FREFTL
   STA PTCHTL
   LDY TABLEH
   INY
   STY FREFTH
   STY PTCHTH
RET1   RTS
      
; ****************************************

DO1LN   
   JSR DETKN
   CPX #PRGEND
   BEQ .ENDPR
   CPX #LABEL   ; means we are still at the first field => blank line
   BEQ .DONE
   LDA #$00
   STA ERFLAG
   STA FRFLAG
   STA HADFRF
   JSR PARSE
   CPX #FAIL
   BEQ DORTS
.CONT   LDY #$00
.LOOP   LDA (CURLNL),Y
   BEQ .DONE
   INY
   BNE .LOOP
.DONE   INY      ; one more to skip the null
.ENDPR   ;JMP UPDTCL
; falls through

; ****************************************

UPDTCL         ; update the current line pointer
         ; by the number of bytes in Y
   LDA CURLNL
   STY SCRTCH
   CLC
   ADC SCRTCH   ; move the current line pointer forward by 'Y' bytes
   STA CURLNL
   BCC INCLN
   INC CURLNH   ; increment the high byte if necessary
INCLN   
   INC LINEL
   BNE DORTS
   INC LINEH
DORTS   RTS      ; global label so can be shared
   
; ****************************************

MKOBJC         ; MNE is in CURMNE, addr mode is in CURADM
         ; and the args are in LVALL,H
         ; calculate the object code, and update PC
   LDY CURMNE   
   LDA BASE,Y   ; get base value for current mnemonic
   LDX CURADM
   CLC
   ADC OFFSET,X   ; add in the offset
   CPX #ABY   ; handle exception
   BEQ .CHABY
   CPX #IMM
   BNE .CONT
   CPY #$28   ; immediate mode need to adjust a range
   BMI .CONT
   CPY #$2F+1
   BCS .CONT
   ADC #ADJIMM   ; carry is clear
   ;BNE .CONT   
.CHABY   CPY #$35
   BNE .CONT
   CLC
   ADC #ADJABY
.CONT   JSR DOBYTE   ; we have the object code
   .IF BRKAS2
   CMP #$00
   BNE .MKARG
   JSR DOBYTE
   .ENDIF
.MKARG         ; where appropriate, the arg value is in LVALL,H
         ; copy to ARGS and null terminate
   TXA      ; quick check for X=0
   BEQ DORTS   ; IMP - no args
   DEX
   BEQ DORTS   ; ACC - no args
   LDA LVALL   ; needed for .BYT handling
   ; word arg if X is greater than or equal to ABS
   CPX #ABS-1
   BMI DOBYTE   ; X < #ABS   
DOWORD   JSR DOBYTE
   LDA LVALH
DOBYTE   LDY #$00
   STA (CURPCL),Y
;   JMP INCPC
; falls through

; ****************************************

INCPC         ; increment the PC
   INC CURPCL
   BNE .DONE   ; any carry?
   INC CURPCH   ; yes
.DONE   RTS

; ****************************************
   
CALCAM         ; work out the addressing mode
   JSR ADDMOD   
   CPX #FAIL
   BNE MKOBJC
   LDY #ILLADM   ; Illegal address mode error
   RTS
   
PARSE         ; Parse one line and validate
   LDA LABEL
   CMP #CMNT
   BEQ DORTS   ; ignore comment lines
   LDX MNE      ; first need to check for an equate
   CPX #DOT
   BNE .NOEQU
   LDX MNE+1
   CPX #MOD   ; Do we have a new module?
   BNE .NOMOD
   JMP DOMOD
.NOMOD   CPX #EQU
   BEQ DOEQU
.NOEQU   CMP #SP      ; Is there a label?
   BEQ .NOLABL   
   JSR PCSYM   ; save the symbol value - in this case it is the PC
.NOLABL   LDA MNE      
   CMP #DOT   ; do we have a directive?
   BNE CALCAM    ; no
   
; ****************************************
   
DODIR   
   LDX #$00   ; handle directives (except equate and module)
   LDA MNE+1
   CMP #STR
   BEQ DOSTR
   STA FRFLAG   ; Disallows forward references
   JSR QTEVAL
   ;CPX #FAIL
   INX
   BEQ DIRERR
   LDA LVALL
   LDX MNE+1
   CPX #WORD
   BEQ DOWORD
   LDX LVALH
   BEQ DOBYTE
DIRERR   LDY #SYNTAX
   LDX #FAIL
   RTS
DOSTR   LDA ARGS,X
   CMP #QUOTE
   BNE DIRERR   ; String invalid
.LOOP   INX
   LDA ARGS,X
   BEQ DIRERR   ; end found before string closed - error
   CMP #QUOTE
   BEQ DIROK
   JSR DOBYTE   ; just copy over the bytes
   CPX #ARGSZ   ; can't go over the size limit
   BNE .LOOP
   BEQ DIRERR   ; hit the limit without a closing quote - error
DIROK   RTS

; ****************************************

DOEQU   
   ;LDA LABEL
   STA FRFLAG
   JSR CHKALN   ; label must be global
   BCC DIRERR   ; MUST have a label for an equate
   LDX #$00
   JSR QTEVAL   ; work out the associated value
   ;CPX #FAIL
   INX
   BEQ DIRERR
   JMP STRSYM
   
; ****************************************

DOMOD         ; Do we have a new module?
   ;LDA LABEL
   JSR CHKALN   ; must have a global label
   BCC DIRERR
   LDY #$00
   LDA ARGS
   BEQ .STORE
   CMP #SP
   BEQ .STORE
.SETPC   JSR ATOFR   ; output finishing module end address (+1)
   LDX #$00   ; set a new value for the PC from the args
   LDA ARGS
   JSR CONVRT
   ;CPX #FAIL
   INX
   BEQ DIRERR
   JSR LVTOPC
.STORE   JSR PCSYM
   CPX #FAIL
   BEQ DIROK
   JSR PATCH
   CPX #FAIL
   BEQ DIROK
   JSR SHWMOD
   LDA #$00   ; reset patch flag
   JSR ATOFR   ; output new module start address
;   JMP CLRLCL
; falls through

; ****************************************

CLRLCL         ; clear the local symbol table
   LDX #$00   ; this also clears any errors
   STX NLSYM   ; to their starting values
   STX LSYMTL
   LDX TABLEH   ; and then the high bytes
   STX LSYMTH
   RTS

; ****************************************

ATOFR   STA FRFLAG
;   JMP MYPRPC
; falls through
   
; ****************************************

MYPRPC   
   LDA CURPCH
   LDX CURPCL
   LDY FRFLAG   ; flag set => print dash and minus 1
   BEQ .NODEC
   PHA
   JSR PRDASH
   PLA
   CPX #$00
   BNE .SKIP   ; is X zero?
   SEC
   SBC #$01
.SKIP   DEX
.NODEC   JMP PRNTAX

; ****************************************

PATCH         ; back patch in the forward reference symbols
         ; all are words
   LDX NFREF
   BEQ .RET   ; nothing to do
   STX ERFLAG   ; set flag
.STRPC   STX NPTCH
   LDA CURPCL   ; save the PC on the stack
   PHA
   LDA CURPCH
   PHA   
   JSR INITFR
.NEXT   LDY #$00
   LDA FRFLAG
   STA FLGSAV   ; so I can restore the FREF flag
   STY HADFRF
   LDA (PTCHTL),Y
   CMP #DOT
   BNE .LOOP
   STA FRFLAG   ; nonzero means must resolve local symbols
.LOOP   LDA (PTCHTL),Y   ; copy symbol to COMM
   STA COMM,Y
   INY
   CPY #SYMSZ
   BNE .LOOP
   LDA (PTCHTL),Y   ; get the PC for this symbol
   STA CURPCL
   INY
   LDA (PTCHTL),Y
   STA CURPCH
   INY
   LDA (PTCHTL),Y
   STA TEMP1   ; save any offset value
   JSR DOLVAL   ; get the symbols true value
   CPX #FAIL   ; value now in LVALL,H or error
   BEQ .ERR   
   LDA HADFRF   ; if we have a persistent FREF
   BEQ .CONT   ; need to copy its offset as well
   LDA TEMP1 
   STA (MISCL),Y   ; falls through to some meaningless patching...
   ;SEC      ; unless I put these two in
   ;BCS .MORE
.CONT   JSR ADD16X   
   LDY #$00
   LDA (CURPCL),Y   ; get the opcode
   AND #$1F   ; check for branch opcode - format XXY10000
   CMP #$10
   BEQ .BRA
   JSR INCPC   ; skip the opcode
.SKIP   LDA LVALL
   JSR DOWORD
.MORE   CLC
   LDA PTCHTL   ; move to the next symbol
   ADC #SYMSZ+3
   STA PTCHTL
   BCC .DECN
   INC PTCHTH
.DECN   LDA FLGSAV
   STA FRFLAG
   DEC NPTCH
   BNE .NEXT
.DONE   PLA
   STA CURPCH   ; restore the PC from the stack
   PLA
   STA CURPCL
.RET   RTS
.BRA   JSR ADDOFF   ; BRA instructions have a 1 byte offset argument only
   CPX #FAIL
   BEQ .ERR
   LDY #$01   ; save the offset at PC + 1
   LDA LVALL
   STA (CURPCL),Y
   JMP .MORE
.ERR   LDY #$00
   JSR OUTSP
.LOOP2   LDA (PTCHTL),Y   ; Show symbol that failed
   JSR OUTCH
   INY
   CPY #SYMSZ
   BNE .LOOP2
   DEY      ; Since #UNKSYM = #SYMSZ - 1
   BNE .DONE   ; always branches
   
; ****************************************

ADDMOD         ; Check the arguments and work out the
         ; addressing mode
         ; return mode in X
   LDX #$FF   ; default error value for mode
   STX CURADM   ; save it
   LDA CURMNE
   LDX ARGS   ; Start checking the format...
   BEQ .EOL
   CPX #SP
   BNE .NOTSP
.EOL   LDX #IMP   ; implied mode - space
   JSR CHKMOD   ; check command is ok with this mode
   CPX #FAIL   ; not ok
   BNE .RET   ; may still be accumulator mode though
   LDX #ACC   ; accumulator mode - space
   JMP CHKMOD   ; check command is ok with this mode
.NOTSP   CPX #IMV   ; immediate mode - '#'
   BEQ .DOIMM
   LDX #REL
   JSR CHKMOD   ; check if command is a branch
   CPX #FAIL
   BEQ .NOTREL
   LDA ARGS
   JMP DOREL
.DOIMM   CMP #$2C   ; check exception first - STA
   BEQ BAD
   LDX #IMM
   CMP #$35   ; check inclusion first - STX
   BEQ .IMMOK
   JSR CHKMOD   ; check command is ok with this mode
   CPX #FAIL
   BEQ .RET
.IMMOK   STX CURADM   ; handle immediate mode
   ;LDX #01   ; skip the '#'
   DEX      ; X == IMM == 2
   JSR QTEVAL
   INX
   BEQ BAD
   LDA LVALH
   BNE BAD
   ;LDX #IMM
.RET   RTS
.NOTREL LDX #0      ; check the more complicated modes
   LDA ARGS
   CMP #OPEN   ; indirection?
   BNE .CONT   ; no
   INX      ; skip the '('
.CONT   JSR EVAL
   CPX #FAIL
   BEQ .RET
   JSR FMT2AM   ; calculate the addressing mode from the format
   CPX #FAIL
   BEQ .RET
   STX CURADM
;   JMP CHKEXS
; falls through

; ****************************************

CHKEXS         ; Current addressing mode is in X
   CPX #ZPY   ; for MNE indices 28 to 2F, ZPY is illegal
   BNE .CONT   ; but ABY is ok, so promote byte argument to word
   LDA CURMNE
   CMP #$28
   BCC .CONT
   CMP #$2F+1
   BCS .CONT   
   LDX #ABY   ; updated addressing mode
   BNE OK
.CONT   LDY #SPCNT   ; check special includes
.LOOP   LDA SPINC1-1,Y   ; load mnemonic code
   CMP CURMNE
   BNE .NEXT
   LDX SPINC2-1,Y   ; load addressing mode
   CPX CURADM
   BEQ OK      ; match - so ok
   LDX SPINC3-1,Y   ; load addressing mode
   CPX CURADM
   BEQ OK      ; match - so ok
.NEXT   DEY
   BNE .LOOP
   LDX CURADM
;   BNE CHKMOD   ; wasn't in the exceptions table - check normally
; falls through

; ****************************************

CHKMOD   LDA CURMNE   ; always > 0
   CMP MIN,X   ; mode index in X
   BCC BAD      ; mnemonic < MIN
   CMP MAX,X   ; MAX,X holds actually MAX + 1
   BCS BAD      ; mnemonic > MAX
OK   STX CURADM   ; save mode
   RTS
   
; ****************************************

BAD   LDX #FAIL   ; Illegal addressing mode error
   RTS
DOREL   
   LDX #$00
   STX LVALL
   STX LVALH
   CMP #PC      ; PC relative mode - '*'
   BNE DOLBL
   JSR PCTOLV
   JSR XCONT   
;   JMP ADDOFF   ; just do an unnecessary EVAL and save 3 bytes
DOLBL   JSR EVAL   ; we have a label
ADDOFF   SEC      ; calculate relative offset as LVALL,H - PC
   LDA LVALL
   SBC CURPCL
   STA LVALL
   LDA LVALH
   SBC CURPCH
   STA LVALH
   BEQ DECLV   ; error if high byte nonzero
   INC LVALH   
   BNE BAD      ; need either $00 or $FF
DECLV   DEC LVALL
   DEC LVALL
RELOK   RTS      ; need to end up with offset value in LVALL   
;ERROFF   LDX #FAIL
;   RTS
   
; ****************************************
   
QTEVAL         ; evaluate an expression possibly with a quote
   LDA ARGS,X
   BEQ BAD
   CMP #QUOTE
   BEQ QCHAR
   JMP EVAL
QCHAR   INX
   LDA #$0
   STA LVALH   ; quoted char must be a single byte
   LDA ARGS,X   ; get the character
   STA LVALL
   INX      ; check and skip the closing quote
   LDA ARGS,X   
   CMP #QUOTE
   BNE BAD
   INX
   LDA ARGS,X
   BEQ XDONE
   CMP #SP
   BEQ XDONE
;   JMP DOPLMN
; falls through

; ****************************************

DOPLMN         ; handle a plus/minus expression
         ; on entry, A holds the operator, and X the location
         ; store the result in LVALL,H
   PHA      ; save the operator
   INX      ; move forward
   LDA ARGS,X   ; first calculate the value of the byte
   JSR BYT2HX
   CPX #FAIL
   BNE .CONT
   PLA
;   LDX #FAIL   ; X is already $FF
.RET   RTS
.CONT   STA TEMP1   ; store the value of the byte in TEMP1
   PLA
   CMP #PLUS
   BEQ .NONEG
   LDA TEMP1
   CLC      ; for minus, need to negate it
   EOR #$FF
   ADC #$1
   STA TEMP1
.NONEG   LDA HADFRF
   BEQ .SKIP
   LDA TEMP1   ; save the offset for use when patching
   STA (MISCL),Y   
.SKIP   ;JMP ADD16X
; falls through

; ****************************************

ADD16X         ; Add a signed 8 bit number in TEMP1
         ; to a 16 bit number in LVALL,H
         ; preserve X (thanks leeeeee, www.6502.org/forum)
   LDA TEMP1   ; signed 8 bit number
   BPL .CONT
   DEC LVALH   ; bit 7 was set, so it's a negative
.CONT   CLC   
   ADC LVALL
   STA LVALL   ; update the stored number low byte
   BCC .EXIT
   INC LVALH   ; update the stored number high byte
.EXIT   RTS

; ****************************************

EVAL         ; Evaluate an argument expression
         ; X points to offset from ARGS of the start
         ; on exit we have the expression replaced
         ; by the required constant
   STX TEMP3   ; store start of the expression
   LDA ARGS,X
   CMP #LOBYTE
   BEQ .HASOP
   CMP #HIBYTE
   BNE .DOLBL
.HASOP   STA FRFLAG   ; disables forward references when there
   INX      ; is a '<' or a '>' in the expression
   LDA ARGS,X
.DOLBL   JSR CHKLBL   ; is there a label?
   BCS .LBL   ; yes - get its value
   JSR CONVRT   ; convert the ASCII
   CPX #FAIL
   BEQ XERR   
   BNE XCONT   
.LBL   STX XSAV   ; move X to Y
   JSR LB2VAL   ; yes - get its value
   CPX #FAIL
   BEQ XDONE
   LDX XSAV
XCONT   INX      ; skip the '$'
   LDA ARGS,X   ; Value now in LVALL,H for ASCII or LABEL
   JSR CHKLBL
   BCS XCONT   ; Continue until end of label or digits
   ;STX TEMP4   ; Store end index
   CMP #PLUS
   BEQ .DOOP
   CMP #MINUS
   BNE XCHKOP
.DOOP   JSR DOPLMN
   CPX #FAIL
   BNE XCONT
XERR   LDY #SYNTAX   ; argument syntax error
XDONE   RTS   
XCHKOP   LDY #$00
   LDA FRFLAG
   CMP #LOBYTE
   BEQ .GETLO
   CMP #HIBYTE
   BNE .STORE
   LDA LVALH   ; move LVALH to LVALL
   STA LVALL
.GETLO   STY LVALH   ; keep LVALL, and zero LVALH
.STORE   LDA ARGS,X   ; copy rest of args to COMM
   STA COMM,Y
   BEQ .DOVAL   
   CMP #SP
   BEQ .DOVAL
   INX
   INY
   CPX #ARGSZ
   BNE .STORE
.DOVAL   LDA #$00
   STA COMM,Y
   LDY TEMP3   ; get start index
   LDA #HEX   ; put the '$" back in so subsequent code
   STA ARGS,Y   ; manages the value properly
   INY
   LDA LVALH
   BEQ .DOLO
   JSR HX2ASC
.DOLO   LDA LVALL
   JSR HX2ASC
   LDX #$00   ; bring back the rest from IOBUF
.COPY   LDA COMM,X
   STA ARGS,Y   ; store at offset Y from ARGS
   BEQ XDONE
   INX
   INY
   BNE .COPY   
      
; ****************************************

LB2VAL         ; label to be evaluated is in ARGS + X (X = 0 or 1)
   LDY #$00
.NEXT   CPY #LBLSZ   ; all chars done
   BEQ DOLVAL
   JSR CHKLBL   ; has the label finished early?
   BCC .STOP
   STA COMM,Y   ; copy because we need exactly 6 chars for the search
   INX      ; COMM isn't used in parsing, so it
   LDA ARGS,X   ; can be treated as scratch space
   INY      
   BNE .NEXT
.STOP   LDA #SP      ; label is in COMM - ensure filled with spaces
.LOOP   STA COMM,Y   ; Y still points to next byte to process
   INY
   CPY #LBLSZ
   BNE .LOOP
DOLVAL   LDA #<COMM   ; now get value for the label
   STA STRL
   LDX #$00   ; select global table (#>COMM)
   STX STRH
   LDA #SYMSZ
   STA RECSIG
   LDA #SYMSZ+2
   STA RECSZ   ; size includes additional two bytes for value
   LDA COMM
   CMP #DOT
   BEQ .LOCAL   ; local symbol
   JSR SYMSCH
   BEQ .FREF   ; if not there, handle as a forward reference
.FOUND   LDY #SYMSZ
   LDA (TBLL),Y   ; save value
   STA LVALL
   INY
   LDA (TBLL),Y
   STA LVALH
   RTS   
.LOCAL         ; locals much the same
   LDX #$03   ; select local table
   JSR SYMSCH
   BNE .FOUND   ; if not there, handle as a forward reference
.FREF   LDA FRFLAG   ; set when patching
   BNE SYMERR   ; can't add FREFs when patching
   JSR PCTOLV   ; default value   to PC
   LDA FREFTH   ; store it in the table
   STA MISCH
   LDA FREFTL   ; Calculate storage address
   LDX NFREF
   BEQ .CONT   ; no symbols to skip
.LOOP   CLC      
   ADC #SYMSZ+3   ; skip over existing symbols
   BCC .SKIP
   INC MISCH   ; carry bit set - increase high pointer
.SKIP   DEX
   BNE .LOOP
.CONT   STA MISCL   ; Reqd address is now in MISCL,H
   INC NFREF   ; Update FREF count
   LDA NFREF
   CMP #MAXFRF   ; Check for table full
   BPL OVFERR
   LDA #COMM
   STA HADFRF   ; non-zero value tells that FREF was encountered
   STA MISC2L
   JSR STORE   ; Store the symbol
   INY
   TXA      ; X is zero after STORE
   STA (MISCL),Y   
   RTS      ; No error      
   
; ****************************************
   
PCSYM
   JSR PCTOLV
;   JMP STRSYM
   
; ****************************************
   
STRSYM         ; Store symbol - name at LABEL, value in MISC2L,H
   LDA #LABEL
   STA MISC2L
   STA STRL
   LDX #$00
   STX STRH
   LDA #SYMSZ
   STA RECSIG   
   LDA LABEL   ; Global or local?
   CMP #DOT
   BNE .SRCH   ; Starts with a dot, so local
   LDX #$03
.SRCH   JSR SYMSCH
   BEQ STCONT   ; Not there yet, so ok
.ERR   PLA
   PLA
SYMERR   LDY #UNKSYM   ; missing symbol error
   BNE SBAD
   ;LDX #FAIL
   ;RTS
OVFERR   LDY #OVRFLW   ; Symbol table overflow   error
SBAD   LDX #FAIL
   RTS
STCONT   LDA #LABEL
   LDX LABEL   ; Global or local?
   CPX #DOT
   BEQ .LSYM   ; Starts with a dot, so local
   SEC      ; Store symbol in global symbol table   
   LDA GSYMTL   ; Make space for next symbol
   SBC #SYMSZ+2   ; skip over existing symbols
   BCS .CONTG   ; Reqd address is now in GSYMTL,H
.DWNHI   DEC GSYMTH   ; carry bit clear - decrease high pointer
.CONTG   STA GSYMTL
   INC NGSYM   ; Update Symbol count - overflow on 256 symbols
   BEQ OVFERR   ; Check for table full
   STA MISCL   ; put addres into MISCH,L for saving
   LDA GSYMTH
   STA MISCH
   BNE STORE   ; Always branches - symbol tables cannot be on page zero
.LSYM   LDA LSYMTH   ; Store symbol in local symbol table   
   STA MISCH
   LDA LSYMTL   ; Calculate storage address
   LDX NLSYM
   BEQ .CONTL   ; no symbols to skip
.LOOP   CLC
   ADC #SYMSZ+2   ; skip over existing symbols
   BCC .SKIP
   INC MISCH
.SKIP   DEX
   BNE .LOOP
.CONTL   STA MISCL   ; Reqd address is now in MISCL,H
   INC NLSYM   ; Update Symbol count
   LDA NLSYM
   CMP #MAXSYM   ; Check for table full
   BPL OVFERR
STORE   LDY #0      ; First store the symbol string
   STY MISC2H
      LDX #SYMSZ
.MV     LDA (MISC2L),Y    ; move bytes
        STA (MISCL),Y
        INY
        DEX
        BNE .MV
        LDA LVALL   ; Now store the value WORD
   STA (MISCL),Y
   INY
        LDA LVALH
   STA (MISCL),Y
   RTS      ; No error   
   
   
; ****************************************

CONVRT          ; convert an ASCII string at ARGS,X
         ; of the form $nnnn (1 to 4 digits)
         ; return the result in LVALL,H, and preserves X and Y
         ; uses COMM area for scratch space
   CMP #HEX   ; syntax for hex constant
   BNE SBAD   ; syntax error
   STY COMM+1
   JSR NBYTS
   CPX #FAIL
   BEQ SBAD
   STA COMM
   LDY #$00
   STY LVALH
.BACK   DEX
   DEX
   LDA ARGS,X
   CMP #HEX
   BEQ .1DIG
   JSR BYT2HX
   SEC
   BCS .SKIP
.1DIG   JSR AHARGS1   ; one digit
.SKIP   STA LVALL,Y
   INY
   CPY COMM
   BNE .BACK
.RET   LDY COMM+1
   RTS
      
; ****************************************

SYMSCH         ; X = 0 for globals
         ; X = 3 for locals
   LDA GSYMTL,X   ; get global symbol value
   STA TBLL
   LDA GSYMTH,X
   STA TBLH
   LDA NGSYM,X   ; Number of global symbols
   STA RECNM
   JSR SEARCH
   CPX #FAIL   ; Z set if search failed
   RTS      ; caller to check

; ****************************************

FMT2AM         ; calculate the addressing given
         ; the format of the arguments;
         ; return format in X, and
         ; location to CHKEXT from in A
         ; $FF      invalid
         ; #ZPG      $nn
         ; #ZPX      $nn,X
         ; #ZPY      $nn,Y
         ; #ABS      $nnnn
         ; #ABX      $nnnn,X
         ; #ABY      $nnnn,Y
         ; #IND      ($nnnn)
         ; #IDX      ($nn,X)
         ; #IDY      ($nn),Y
         ; #INZ      ($nn)
         ; #IAX      ($nnnn,X)
;      
;   Addressing modes are organised as follows:
;
;   IMP (0)   ZPG (4) INZ (-) ABS (9) IND (C)
;   ACC (1) ZPX (5) INX (7) ABX (A) IAX (D)
;   IMM (2) ZPY (6) INY (8) ABY (B) ---
;   REL (3) ---    ---   ---   ---
;
;   so algorithm below starts with 4, adds 3 if indirect
;   and adds 6 if absolute (i.e. 2 byte address), then adds 1 or 2
;   if ,X or ,Y format
;
   LDX #$00
   LDA #$04   ; start with mode index of 4
   LDY ARGS,X
   CPY #OPEN
   BNE .SKIP
   CLC      ; add 3 for indirect modes
   ADC #$03
   INX
.SKIP   PHA   
   JSR NBYTS   ; count bytes (1 or 2 only)
   TAY      ; byte count in Y
   DEX
   LDA CURMNE
   CMP #$21   ; is it JSR?
   BEQ .JSR
   CMP #$23   ; is it JMP?
   BNE .NOJMP
.JSR   ;LDY #$2      ; force 2 bytes for these two situations
   INY      ; following code treats Y = 3 the same as Y = 2
.NOJMP   PLA      ; mode base back in A
   INX      ; check for NBYTS failure
   BEQ FERR
   DEY
   BEQ .1BYT
.2BYT   CLC
   ADC #$06   ; add 6 to base index for 2 byte modes
.1BYT   TAY      ; mode index now in Y
.CHECK   LDA ARGS,X
   BEQ .DONE
   CMP #SP
   BNE .CONT
.DONE   LDA ARGS
   CMP #OPEN   ; brackets must match
   BEQ FERR
.RET   CPY #$0F
   BPL FERR   ; no indirect absolute Y mode
   CPY #$07
   BEQ FERR   ; no indirect zero page mode
   BMI .1      ; 6502 has no INZ mode, so reduce
   DEY      ; so reduce by ifgreater than 7
.1   TYA
   TAX
   RTS
.CONT   CMP #CLOSE
   BNE .MORE
   LDA #SP
   STA ARGS   ; erase brackets now they have
   INX
   LDA ARGS,X
   CMP #COMMA
   BNE .CHECK
.MORE   LDA ARGS,X
   CMP #COMMA
   BNE FERR
   INX
   LDA ARGS,X
   CMP #'X'
   BEQ .ISX
.ISY   CMP #'Y'
   BNE FERR
   LDA ARGS
   CMP #OPEN
   BEQ FERR
   STA ARGS-2,X   ; to avoid ,X check below
   INY
.ISX   INY
   LDA ARGS-2,X
   CMP #CLOSE
   BEQ FERR
   INX
   BNE .CHECK   ; always
FERR   LDX #FAIL   ; error message generated upstream
FRET   RTS
NBYTS   LDY #$00   ; count bytes using Y
.LOOP   INX
   INY
   JSR AHARGS
   CMP #FAIL
   BNE .LOOP
.NEXT   TYA
   LSR      ; divide number by 2
   BEQ FERR   ; zero is an error
   CMP #$03   ; 3 or more is an error
   BCS FERR
.RET   RTS      
   
; ****************************************
; *          Utility Routines            *
; ****************************************
   
SEARCH         ; TBLL,H has the address of the table to search
         ; and address of record on successful return
         ; STRL,H has the address of the search string
         ; Search through RECNM records
         ; Each of size RECSZ with RECSIG significant chars
   LDA RECNM
   BEQ FERR   ; empty table
   LDX #$00   ; Record number
.CHK1   LDY #$FF   ; Index into entry
.CHMTCH   INY
   CPY RECSIG   ; Have we checked all significant chars?
   BEQ FRET   ; Yes
   LDA (TBLL),Y   ; Load the bytes to compare
   CMP (STRL),Y
   BEQ .CHMTCH   ; Check next if these match
   INX      ; Else move to next record
   CPX RECNM
   BEQ FERR
   LDA TBLL   ; Update address
   CLC
   ADC RECSZ
   STA TBLL
   BCC .CHK1
   INC TBLH   ; Including high byte if necessary
   BCS .CHK1   ; will always branch
;.FAIL   LDX #FAIL   ; X = $FF indicates failure
;.MATCH   RTS      ; got it - index is in X, address is in A and TBLL,H

; ****************************************

BYT2HX         ; convert the ASCII byte (1 or 2 chars) at offset X in
         ; the args field to Hex
         ; result in A ($FF for fail)
   
   JSR AHARGS   
   CMP #FAIL   ; indicates conversion error      
   BEQ FERR
   PHA   
   JSR AHARGS1
   DEX
   CMP #FAIL
   BNE .CONT
   PLA      ; just ignore 2nd character
   RTS
.CONT   STA SCRTCH
   PLA
   ASL      ; shift
   ASL
   ASL
   ASL
   ADC SCRTCH
   RTS
   
; ****************************************

AHARGS1   INX      ; caller needs to DEX
AHARGS   LDA ARGS,X
ASC2HX         ; convert ASCII code in A to a HEX digit
       EOR #$30 
   CMP #$0A 
   BCC .VALID 
   ADC #$88        ; $89 - CLC 
   CMP #$FA 
   BCC .ERR 
   AND #$0F   
.VALID   RTS
.ERR   LDA #FAIL   ; this value can never be from a single digit,
   RTS      ; so ok to indicate error
   
; ****************************************

HX2ASC         ; convert a byte in A into two ASCII characters
         ; store in ARGS,Y and ARGS+1,Y
   PHA       ; 1st byte.
   JSR LSR4   ; slower, but saves a byte and not too crucial
   JSR DO1DIG
   PLA
DO1DIG   AND #$0F   ; Print 1 hex digit
   ORA #$30
   CMP #$3A
   BCC .DONE
   ADC #$06
.DONE   STA ARGS,Y
   INY
   RTS
   
; ****************************************
   
EXPMNE         ; copy the 2 chars at R/LMNETB,X
         ; into LMNE and RMNE, and expand
         ; into 3 chars at MNE to MNE+2
   LDA LMNETB,X
   STA LMNE
   LDA RMNETB,X
   STA RMNE
   LDX #$00
.NEXT   LDA #$00
   LDY #$05
.LOOP   ASL RMNE
   ROL LMNE
   ROL
   DEY
   BNE .LOOP
   ADC #'A'-1
   STA MNE,X
   LDY PRFLAG
   BEQ .SKIP
   JSR OUTCH   ; print the mnemonic as well
.SKIP   INX
   CPX #$03
   BNE .NEXT
   RTS   

; ****************************************
;            DISASSEMBLER
; Adapted from code in a Dr Dobbs article
; by Steve Wozniak and Allen Baum (Sep '76)
; ****************************************
   
DISASM   
   JSR ADDARG
   ;BEQ .DODIS
   BEQ DSMBL
.COPY   JSR LVTOPC
;.DODIS   JMP DSMBL
; fall through

; ****************************************

DSMBL   
   LDA #$13   ; Count for 20 instruction dsmbly
   STA COUNT
.DSMBL2   JSR INSTDSP   ; Disassemble and display instr.
   JSR PCADJ
   STA PCL      ; Update PCL,H to next instr.
   STY PCH
   DEC COUNT   ; Done first 19 instrs
   BNE .DSMBL2   ; * Yes, loop.  Else DSMBL 20th
INSTDSP   JSR PRPC   ; Print PCL,H
   LDA (PCL,X)   ; Get op code
   TAY   
   LSR         ; * Even/odd test
   BCC .IEVEN
   ROR        ; * Test B1
   BCS .ERR   ; XXXXXX11 instr invalid
   CMP #$A2   
   BEQ .ERR   ; 10001001 instr invalid
   AND #$87   ; Mask 3 bits for address mode
   ;ORA #$80   ; * add indexing offset
.IEVEN   LSR         ; * LSB into carry for
   TAX         ; Left/right test below
   LDA MODE,X   ; Index into address mode table
   BCC .RTMODE   ; If carry set use LSD for
   JSR LSR4
   ;LSR         ; * print format index
   ;LSR         
   ;LSR         ; If carry clear use MSD
   ;LSR   
.RTMODE   AND #$0F   ; Mask for 4-bit index
   BNE .GETFMT   ; $0 for invalid opcodes
.ERR   LDY #$80   ; Substitute $80 for invalid op,
   LDA #$00   ; set print format index to 0
.GETFMT   TAX   
   LDA MODE2,X   ; Index into print format table
   STA FORMAT   ; Save for address field format
   AND #$03   ; Mask 2-bit length.  0=1-byte
   STA LENGTH   ; *  1=2-byte, 2=3 byte
   TYA         ; * op code
   JSR GETMNE
   LDY #$00
   PHA         ; Save mnemonic table index
.PROP   LDA (PCL),Y
   JSR OUTHEX
   LDX #$01
.PROPBL   JSR PRBL2
   CPY LENGTH   ; Print instr (1 to 3 bytes)
   INY         ; *  in a 12-character field
   BCC .PROP
   LDX #$03   ; char count for mnemonic print
   STX PRFLAG   ; So EXPMNE prints the mnemonic
   CPY #$04
   BCC .PROPBL
   PLA         ; Recover mnemonic index
   TAX
   JSR EXPMNE
   JSR PRBLNK   ; Output 3 blanks
   LDY LENGTH
   LDX #$06   ; Count for 6 print format bits
.PPADR1   CPX #$03
   BEQ .PPADR5   ; If X=3 then print address val
.PPADR2   ASL FORMAT   ; Test next print format bit
   BCC .PPADR3   ; If 0 don't print
   LDA CHAR1-1,X   ; *  corresponding chars
   JSR OUTCH   ; Output 1 or 2 chars
   LDA CHAR2-1,X   ; *  (If char from char2 is 0,
   BEQ .PPADR3   ; *   don't output it)
   JSR OUTCH
.PPADR3   DEX   
   BNE .PPADR1
   STX PRFLAG   ; reset flag to 0
   RTS        ; Return if done 6 format bits
.PPADR4   DEY
   BMI .PPADR2
   JSR OUTHEX   ; Output 1- or 2-byte address
.PPADR5   LDA FORMAT
   CMP #$E8   ; Handle rel addressing mode
   LDA (PCL),Y   ; Special print target adr
   BCC .PPADR4   ; *  (not displacement)
.RELADR   JSR PCADJ3   ; PCL,H + DISPL + 1 to A,Y
   TAX   
   INX   
   BNE PRNTYX   ; *     +1 to X,Y
   INY   
PRNTYX   TYA   
PRNTAX   JSR OUTHEX   ; Print target adr of branch
PRNTX   TXA         ; *  and return
   JMP OUTHEX
PRPC   JSR CRLF   ; Output carriage return
   LDA PCH
   LDX PCL
   JSR PRNTAX   ; Output PCL and PCH
PRBLNK   LDX #$03   ; Blank count
PRBL2   JSR OUTSP   ; Output a blank
   DEX   
   BNE PRBL2   ; Loop until count = 0
   RTS   
PCADJ   SEC
PCADJ2   LDA LENGTH   ; 0=1-byte, 1=2-byte, 2=3-byte
PCADJ3   LDY PCH   
   TAX         ; * test displ sign (for rel
   BPL .PCADJ4   ; *  branch).  Extend neg
   DEY         ; *  by decrementing PCH
.PCADJ4   ADC PCL
   BCC .RTS      ; PCL+LENGTH (or displ) + 1 to A
   INY         ; *  carry into Y (PCH)
.RTS   RTS
   
GETMNE         ; get mnemonic index for opcode in A
         ; on completion, A holds the index
         ; into the mnemonic table
   STA TEMP1   ; will need it later
   AND #$8F
   CMP #$8A
   BEQ CAT3
   ASL
   CMP #$10
   BEQ CAT2
   LDA TEMP1   ; ? ABCD EFGH - thanks bogax, www.6502.org/forum
   ASL      ; A BCDE FGH0
   ADC #$80   ; B ?CDE FGHA
   ROL      ; ? CDEF GHAB
   ASL      ; C DEFG HAB0
   AND #$1F   ; C 000G HAB0
   ADC #$20   ; 0 001G HABC
   PHA
   LDA TEMP1   ; get the opcode back
   AND #$9F
   BEQ CAT1
   ASL
   CMP #$20
   BEQ CAT4
   AND #$06
   BNE CAT67
CAT5         ; remaining nnnX XX00 codes
   PLA
   AND #$07   ; just low 3 bits
   CMP #$03
   BPL .3
   ADC #$02   ; correction for 21 and 22
.3   ADC #$1F   ; and add 20
   RTS
CAT4         ; Branch instructions - nnn1 0000
   PLA
   AND #$07   ; just low 3 bits
   ADC #$18   ; and add 19 (carry is set)
   RTS
CAT1         ; 0nn0 0000 - BRK, JSR, RTI, RTS
   PLA
   TAX
   LDA MNEDAT-$20,X
   RTS
MNEDAT   .byte $16, $21, $17, $18
CAT2         ; nnnn 1000 - lots of no-arg mnemonics
   LDA TEMP1
LSR4   LSR      ; need high 4 bits
   LSR
   LSR
   LSR
   RTS
CAT3         ; 1nnn 1010 - TXA,TXS,TAX,TSX,DEX,-,NOP,-
   JSR CAT2   ; need high 4 bits
   CMP #$0E
   BNE .2
   ADC #$FD
.2   ADC #$08   ; then add 8
   RTS
CAT67         ; gets the index for categories 6 and 7
   PLA      ; i.e. nnnX XX01 and nnnX XX10 ($28-$2F, $30-$37)
   RTS      ; it's already done
      
; Data and related constants

MODES         ; Addressing mode constants
IMP = $00
ACC = $01
IMM = $02      ; #$nn or #'<char>' or #LABEL
REL = $03      ; *+nn or LABEL
ZPG = $04      ; $nn or LABEL
ZPX = $05      ; $nn,X or LABEL,X
ZPY = $06      ; $nn,Y or LABEL,Y
IDX = $07      ; ($nn,X) or (LABEL,X)
IDY = $08      ; ($nn),Y or (LABEL),Y
ABS = $09      ; $nnnn or LABEL
ABX = $0A      ; $nnnn,X or LABEL,X
ABY = $0B      ; $nnnn or LABEL
IND = $0C      ; ($nnnn) or (LABEL)

NUMMN    =$38      ; number of mnemonics

; Tables

LMNETB

   .byte $82   ; PHP
   .byte $1B   ; CLC
   .byte $83   ; PLP
   .byte $99   ; SEC
   .byte $82   ; PHA
   .byte $1B   ; CLI
   .byte $83   ; PLA
   .byte $99   ; SEI
   .byte $21   ; DEY
   .byte $A6   ; TYA
   .byte $A0   ; TAY
   .byte $1B   ; CLV
   .byte $4B   ; INY
   .byte $1B   ; CLD
   .byte $4B   ; INX
   .byte $99   ; SED
   .byte $A6   ; TXA
   .byte $A6   ; TXS
   .byte $A0   ; TAX
   .byte $A4   ; TSX
   .byte $21   ; DEX
   .byte $73   ; NOP
   .byte $14   ; BRK
   .byte $95   ; RTI
   .byte $95   ; RTS
   .byte $14   ; BPL
   .byte $13   ; BMI
   .byte $15   ; BVC
   .byte $15   ; BVS
   .byte $10   ; BCC
   .byte $10   ; BCS
   .byte $13   ; BNE
   .byte $11   ; BEQ
   .byte $54   ; JSR
   .byte $12   ; BIT
   .byte $53   ; JMP
   .byte $9D   ; STY
   .byte $61   ; LDY
   .byte $1C   ; CPY
   .byte $1C   ; CPX
   .byte $7C   ; ORA
   .byte $0B   ; AND
   .byte $2B   ; EOR
   .byte $09   ; ADC
   .byte $9D   ; STA
   .byte $61   ; LDA
   .byte $1B   ; CMP
   .byte $98   ; SBC
   .byte $0C   ; ASL
   .byte $93   ; ROL
   .byte $64   ; LSR
   .byte $93   ; ROR
   .byte $9D   ; STX
   .byte $61   ; LDX
   .byte $21   ; DEC
   .byte $4B   ; INC


RMNETB
   .byte $20   ; PHP
   .byte $06   ; CLC
   .byte $20   ; PLP
   .byte $46   ; SEC
   .byte $02   ; PHA
   .byte $12   ; CLI
   .byte $02   ; PLA
   .byte $52   ; SEI
   .byte $72   ; DEY
   .byte $42   ; TYA
   .byte $72   ; TAY
   .byte $2C   ; CLV
   .byte $B2   ; INY
   .byte $08   ; CLD
   .byte $B0   ; INX
   .byte $48   ; SED
   .byte $02   ; TXA
   .byte $26   ; TXS
   .byte $70   ; TAX
   .byte $F0   ; TSX
   .byte $70   ; DEX
   .byte $E0   ; NOP
   .byte $96   ; BRK
   .byte $12   ; RTI
   .byte $26   ; RTS
   .byte $18   ; BPL
   .byte $52   ; BMI
   .byte $86   ; BVC
   .byte $A6   ; BVS
   .byte $C6   ; BCC
   .byte $E6   ; BCS
   .byte $8A   ; BNE
   .byte $62   ; BEQ
   .byte $E4   ; JSR
   .byte $68   ; BIT
   .byte $60   ; JMP
   .byte $32   ; STY
   .byte $32   ; LDY
   .byte $32   ; CPY
   .byte $30   ; CPX
   .byte $82   ; ORA
   .byte $88   ; AND
   .byte $E4   ; EOR
   .byte $06   ; ADC
   .byte $02   ; STA
   .byte $02   ; LDA
   .byte $60   ; CMP
   .byte $86   ; SBC
   .byte $D8   ; ASL
   .byte $D8   ; ROL
   .byte $E4   ; LSR
   .byte $E4   ; ROR
   .byte $30   ; STX
   .byte $30   ; LDX
   .byte $46   ; DEC
   .byte $86   ; INC
   
MIN         ; Minimum legal value for MNE for each mode.
   .byte $00, $30, $25, $19, $24
   .byte $28, $34, $28, $28, $21, $28
   .byte $28, $23
MAX         ; Maximum +1 legal value of MNE for each mode.
   .byte $18+1, $33+1, $2F+1, $20+1, $37+1
   .byte $33+1, $35+1, $2F+1, $2F+1, $37+1, $33+1
   .byte $2F+1, $23+1
BASE         ; Base value for each opcode
   .byte $08, $18, $28, $38
   .byte $48, $58, $68, $78
   .byte $88, $98, $A8, $B8
   .byte $C8, $D8, $E8, $F8
   .byte $8A, $9A, $AA, $BA
   .byte $CA, $EA, $00, $40
   .byte $60, $10, $30, $50
   .byte $70, $90, $B0, $D0
   .byte $F0, $14, $20, $40
   .byte $80, $A0, $C0, $E0
   .byte $01, $21, $41, $61
   .byte $81, $A1, $C1, $E1
   .byte $02, $22, $42, $62
   .byte $82, $A2, $C2, $E2
OFFSET         ; Default offset values for each mode,
         ; added to BASE to get Opcode
   .byte $00, $08, $00, $00, $04
   .byte $14, $14, $00, $10, $0C, $1C
   .byte $18, $2C
   
; offset adjustments for the mnemonic exceptions
ADJABY  =$04      ;
ADJIMM  =$08      ;

; disassembler data

; XXXXXXZ0 instrs
; * Z=0, left half-byte
; * Z=1, right half-byte
MODE   .byte $04, $20, $54, $30, $0D
   .byte $80, $04, $90, $03, $22
   .byte $54, $33, $0D, $80, $04
   .byte $90, $04, $20, $54, $33
   .byte $0D, $80, $04, $90, $04
   .byte $20, $54, $3B, $0D, $80
   .byte $04, $90, $00, $22, $44
   .byte $33, $0D, $C8, $44, $00
   .byte $11, $22, $44, $33, $0D
   .byte $C8, $44, $A9, $01, $22
   .byte $44, $33, $0D, $80, $04
   .byte $90, $01, $22, $44, $33
   .byte $0D, $80, $04, $90
; YYXXXZ01 instrs
   .byte $26, $31, $87, $9A
   
MODE2   .byte $00   ; ERR
   .byte $21   ; IMM
   .byte $81   ; Z-PAG
   .byte $82   ; ABS
   .byte $00   ; IMPL
   .byte $00   ; ACC
   .byte $59   ; (Z-PAG,X)
   .byte $4D   ; (Z-PAG),Y
   .byte $91   ; Z-PAG,X
   .byte $92   ; ABS,X
   .byte $86   ; ABS,Y
   .byte $4A   ; (ABS)
   .byte $85   ; Z-PAG,Y
   .byte $9D   ; REL
CHAR1   .byte ','
   .byte ')'
   .byte ','
   .byte '#'
   .byte '('
   .byte '$'
CHAR2   .byte 'Y'
   .byte $00   
   .byte 'X'
   .byte '$'
   .byte '$'
   .byte $00

; Special case mnemonics   
SPCNT   = $06      ; duplicate some checks so I can use the same loop above
; Opcodes
SPINC1   .byte $22, $24, $25, $35, $36, $37
; 1st address mode to check
SPINC2   .byte $04, $05, $05, $02, $05, $05
; 2nd address mode to check
SPINC3   .byte $04, $05, $0A, $0B, $0A, $0A
   
; commands

NUMCMD   =$0C
CMDS   .ASCII "NLXEMRDI$AVP"

N1 = NEW-1
L1 = LIST-1
D1 = DELETE-1
E1 = EDIT-1
M1 = MEM-1
R1 = RUN-1
DIS1 = DISASM-1
I1 = INSERT-1
MON1 = MONTOR-1
A1 = ASSEM-1
V1 = VALUE-1
P1 = PANIC-1

CMDH   .byte   >N1
   .byte   >L1
   .byte   >D1
   .byte   >E1
   .byte   >M1
   .byte   >R1
   .byte   >DIS1
   .byte   >I1
   .byte   >MON1
   .byte   >A1
   .byte   >V1
   .byte   >P1

CMDL   .byte   <N1
   .byte   <L1
   .byte   <D1
   .byte   <E1
   .byte   <M1
   .byte   <R1
   .byte   <DIS1
   .byte   <I1
   .byte   <MON1
   .byte   <A1
   .byte   <V1
   .byte   <P1

; Assembler directives - all entered with a leading '.'

BYTE    ='B'      ; bytes
WORD   ='W'      ; word
STR   ='S'      ; string
EQU   ='='      ; equate
MOD   ='M'      ; start address for subsequent module

NUMDIR   =$05
DIRS   .ascii "BWS=M"

; Errors

UNKERR   =$00
INVMNE   =$01      ; Invalid mnemonic
ILLADM   =$02      ; Illegal addressing mode
SYNTAX   =$03      ; Syntax error
OVRFLW   =$04      ; Symbol table overflow
UNKSYM   =$05      ; Unknown or duplicate symbol error
MAXERR   =$06

EMSGSZ   =$03      ; The size of the error message strings
ERPRSZ   =$05      ; The size of the error prefix string
ERRPRE   .ascii " :RRE"
ERRMSG
   .if UNK_ERR_CHECK
   .ascii "UNK"
   .endif
   .ascii "MNE"
   .ascii "ADD"
   .ascii "SYN"
   .ascii "OVF"
   .ascii "SYM"
   
MSGSZ = $1B
MSG   .ascii "NESSEW NEK YB 2.1 REDASURK",CR

   .if MINIMONITOR
; ****************************************
;            MINIMONITOR
; A simple monitor to allow viewing and
; altering of registers, and changing the PC
; ****************************************
   
NREGS   =$5
DBGCMD   .ascii "PSYXALH"
NDBGCS   =NREGS+2
FLAGS   .ascii "CZIDB"
   .byte $00   ; A non-printing character - this flag always on
   .ascii "VN"

GETCMD   JSR CRLF
   JSR PRDASH
   JSR GETCH1
   LDY #NDBGCS
.LOOP   CMP DBGCMD-1,Y
   BEQ DOCMD   ; if we've found a PC or register change command, then run it
   DEY
   BNE .LOOP
   CMP #'R'   ; resume?
   BNE .NOTR
   JSR RESTORE
   ;CLI      ; enable interrupts again
   JMP (PCL)   ; Simulate the return so we can more easily manipulate the stack
.NOTR
   .if DOTRACE
   CMP #'T'   ; trace?
   BNE NOTT   
TRACE   LDX #$08
XQINIT  LDA INITBL-1,X ;INIT XEQ AREA
        STA XQT,X
        DEX
        BNE XQINIT
        LDA (PCL,X)    ;USER OPCODE BYTE
        BEQ XBRK       ;SPECIAL IF BREAK
        LDY LENGTH     ;LEN FROM DISASSEMBLY
        CMP #$20
        BEQ XJSR       ;HANDLE JSR, RTS, JMP,
        CMP #$60       ;  JMP (), RTI SPECIAL
        BEQ XRTS
        CMP #$4C
        BEQ XJMP
        CMP #$6C
        BEQ XJMPAT
        CMP #$40
        BEQ XRTI
        AND #$1F
        EOR #$14
        CMP #$04       ;COPY USER INST TO XEQ AREA
        BEQ .XQ2       ;  WITH TRAILING NOPS
.XQ1    LDA (PCL),Y    ;CHANGE REL BRANCH
.XQ2    STA XQT,Y      ;  DISP TO 4 FOR
        DEY            ;  JMP TO BRANCH OR
        BPL .XQ1       ;  NBRANCH FROM XEQ.
        JSR RESTORE    ;RESTORE USER REG CONTENTS.
        JMP XQT        ;XEQ USER OP FROM RAM
NOTT
        .endif
   CMP #'$'   ; monitor?
   BNE GETCMD
   JMP MONTOR
DOCMD   LDX #$FE
.LOOP   JSR GETCH1
   STA ARGS+2,X
   INX
   BNE .LOOP
   JSR BYT2HX
   STA REGS-1,Y
   LDX SAVS
   TXS
.1   JMP XBRK
   
DEBUG   PLP
        JSR SAVE       ;SAVE REG'S ON BREAK
        PLA              ;  INCLUDING PC
        STA PCL
        PLA
        STA PCH
XBRK   TSX
        STX SAVS
   JSR SHOW
   JSR INSTDSP    ;PRINT USER PC.
   JMP GETCMD
   .if DOTRACE
XRTI    CLC
        PLA              ;SIMULATE RTI BY EXPECTING
        STA SAVP     ;  STATUS FROM STACK, THEN RTS
XRTS    PLA              ;RTS SIMULATION
        STA PCL        ;  EXTRACT PC FROM STACK
        PLA              ;  AND UPDATE PC BY 1 (LEN=0)
PCINC2  STA PCH
PCINC3  JSR PCADJ2   ;UPDATE PC BY LEN
        STY PCH
        CLC
        BCC NEWPCL
XJSR    CLC
        JSR PCADJ2     ;UPDATE PC AND PUSH
        TAX              ;  ONTO STACK FOR
        TYA              ;  JSR SIMULATE
        PHA
        TXA
        PHA
        LDY #$02
XJMP    CLC
XJMPAT  LDA (PCL),Y
        TAX              ;LOAD PC FOR JMP,
        DEY              ;  (JMP) SIMULATE.
        LDA (PCL),Y
        STX PCH
NEWPCL  STA PCL
        BCS XJMP
   JMP XBRK
        .endif
SHOW     JSR CRLF
   LDX #NREGS
.LOOP   LDA DBGCMD-1,X
   JSR OUTCH
   JSR PRDASH
   LDA REGS-1,X
   JSR OUTHEX
   JSR OUTSP
   DEX
   BNE .LOOP
   LDA SAVP   ; show the flags explicitly as well
   LDX #$08
.NEXT   ASL
   BCC .SKIP
   PHA
   LDA FLAGS-1,X
   JSR OUTCH
   PLA
.SKIP   DEX
   BNE .NEXT
   RTS
   .if DOTRACE
BRANCH  CLC              ;BRANCH TAKEN,
        LDY #$01       ;  ADD LEN+2 TO PC
        LDA (PCL),Y
        JSR PCADJ3
        STA PCL
        TYA
   SEC
        BCS PCINC2
NBRNCH  JSR SAVE       ;NORMAL RETURN AFTER
        SEC              ;  XEQ USER OF
        BCS PCINC3     ;GO UPDATE PC
INITBL  NOP
        NOP              ;DUMMY FILL FOR
        JMP NBRNCH     ;  XEQ AREA
        JMP BRANCH
        .endif
RESTORE LDA SAVP     ;RESTORE 6502 REG CONTENTS
        PHA              ;  USED BY DEBUG SOFTWARE
        LDA SAVA
   LDX SAVX
        LDY SAVY
        PLP
        RTS
SAVE    STA SAVA        ;SAVE 6502 REG CONTENTS
   STX SAVX
        STY SAVY
        PHP
        PLA
        STA SAVP
        TSX
        STX SAVS
        CLD
        RTS
        .endif

; ****************************************
; I/O routines
; ****************************************

PRDASH   
   LDA #MINUS
   JMP OUTCH
   
; ****************************************
   
   .if MINIMONITOR
GETCH1   JSR GETCH
   JMP OUTCH
   .endif
   
; ****************************************

SHWMOD         ; Show name of module being assembled
   JSR CRLF
   LDX #$00
.LOOP2   LDA LABEL,X
   JSR OUTCH
   INX
   CPX #LBLSZ
   BNE .LOOP2
   JSR OUTSP
;   JMP PRLNNM   ; falls through
   
; ****************************************   

PRLNNM
   LDA LINEH
   JSR PRHEX
   LDA LINEL
   JSR OUTHEX
   ;JMP OUTSP
; falls through

OUTSP   
   LDA #SP
   JMP OUTCH
   
CRLF         ; Go to a new line.
   LDA #CR      ; "CR"
   JMP OUTCH

GETCH         ; Get a character from the keyboard.
   LDA ACIA_SR      ;See if we got an incoming char
   AND #$08      ;Test bit 3
   BEQ GETCH      ;Wait for character
   LDA ACIA_DAT      ;Load char
   CMP #$60      ;*Is it Lower case
   BMI   CONVERT      ;*Nope, just convert it
   AND #$5F      ;*If lower case, convert to Upper case
CONVERT
   
   RTS
   
OUTHEX   PHA         ;Save A for LSD.
   LSR
   LSR
   LSR         ;MSD to LSD position.
   LSR
   JSR PRHEX      ;Output hex digit.
   PLA         ;Restore A.
PRHEX   AND #$0F      ;Mask LSD for hex print.
   ORA #$30      ;Add "0".
   CMP #$3A      ;Digit?
   BCC OUTCH      ;Yes, output it.
   ADC #$06      ;Add offset for letter.
OUTCH   PHA         ;*Save A
   STA ACIA_DAT      ;*Send it.
.WAIT   LDA ACIA_SR      ;*Load status register for ACIA
   AND #$10      ;*Mask bit 4.
   BEQ .WAIT      ;*ACIA not done yet, wait.
   PLA         ;*Restore A
   RTS         ;*Done, over and out...
   
User avatar
fsafstrom
 
Posts: 154
Joined: Dec Tue 26, 2006 3:57 pm
Location: San Antonio, Texas

Thanks, this helps!

Postby hanso » Oct Wed 03, 2007 2:07 am

Thanks, this helps!

Hans
hanso
 
Posts: 71
Joined: Sep Sat 22, 2007 1:35 pm
Location: Weesp The Netherlands


Return to Software

Who is online

Users browsing this forum: No registered users and 3 guests

cron