LWASM – Tricks and cool features

I thought I’d share some of the cool features I’ve discovered over the years using LWASM that I don’t think are widely known or maybe I just live under a rock. 🙂

One of the best things are the need for less labels when writing your code. You can use the less than (<) and greater than (>) as labels that direct the code to the exclamation mark (!) in your code. For example:

Cool program #1 with labels:

    LDX    #$1000
LOOP1:
    INC    ,X+
    CMPX   #$2000
    BNE    LOOP1
    LDD    ,Y
    BNE    Done
    LDD    #$BBBB
Done:
    RTS

Cool program #1 with <, > and ! – Look ma, no labels:

    LDX    #$1000
!
    INC    ,X+
    CMPX   #$2000
    BNE    <
    LDD    ,Y
    BNE    >
    LDD    #$BBBB
!
    RTS

Another cool label shortcut/feature is the use of @ at the end of your labels. You can re-use labels in the same source code as long as you leave a blank line between code sections and use an @ at the end. I haven’t used this too much myself but I have seen it used in a few 6809 source code files I’ve come across. It works like this

Cool program #2 with all different labels:

    LDX    #$1000
Loop1
    INC    ,X+
    CMPX   #$2000
    BNE    Loop1
    CMPD   #$AAAA
    BNE    Skip1
    LDD    #$BBBB
Skip1:
    BRA    NextCode
    RTS
NextCode:
    LDX    #$5000
Loop2
    INC    ,X+
    CMPX   #$6000
    BNE    Loop2
    RTS

If you leave a blank line after the RTS and put @ at the end of your label names you can reuse the same labels in the next section (see the 1@):

    LDX    #$1000
1@
    INC    ,X+
    CMPX   #$2000
    BNE    1@
    CMPD   #$AAAA
    BNE    2@
    LDD    #$BBBB
2@
    BRA    NextCode
    RTS

NextCode:
    LDX    #$5000
1@
    INC    ,X+
    CMPX   #$6000
    BNE    1@
    RTS

Another cool thing LWASM can do is tell you the CPU cycle counts of your code. You can insert the following anywhere in your code that you’d like to count the cycles. Leave a few spaces on a line then type

opt c  * enable cycle counts
opt cd * enable detailed cycle counts breaking down addressing modes
opt ct * show a running subtotal of cycles
opt cc * clear the running subtotal

As the comments show the c shows the cycle counts, the ct tells the assembler to add the counts and the cc clears the current count. You can use any of these individually or together as I have.

    opt     c,ct,cc       * show cycle count, add the counts, clear the current count

When you look at the output listing LWASM writes when it assembles your program you will see the cycles

Mem  Code     Cycles               Assembly Code (Mnemonics)
4000 8E2000   [3]                  LDX     #$2000
4003 A684     [4+0]                LDA     ,X
4005 A61F     [4+1]                LDA     -1,X
4009 A610     [4+1]                LDA     -16,X
400B A688EF   [4+1]                LDA     -17,X
400E A68880   [4+1]                LDA     -128,X
4011 A689FF7F [4+4]                LDA     -129,X
4015 A601     [4+1]                LDA     1,X
4017 A60F     [4+1]                LDA     15,X
4019 A68810   [4+1]                LDA     16,X
401C A6887F   [4+1]                LDA     127,X
401F A6890080 [4+4]                LDA     128,X

Another cool feature is Conditional Assembly. Conditional assembly basically uses IF, ELSE and END in your code and depending on the setting that you define then LWASM will assemble the code one way or another. There are many different conditions show in the LWASM documentation here. Just remember to use some spaces on the lines that you have your IF, ELSE, END or whatever other DEFINE you are using.

One last thing I sometimes use are Pragmas. You use them again with some spaces on the line then the word pragma a few spaces then the pragma itself. For example if I don’t want to see all the output in the assembly listing I use these pragmas:

   pragma nolist    * The code below will not be shown in the listing
INCLUDE ./includes/CoCo3_Start.asm
INCLUDE ./includes/Def_CoCo3_Memory_Description_and_Defines.asm
   pragma list      * The code below will be shown in the listing

In the example above, everything still gets assembled as normal but the output of sections will be hidden in the listing. Useful if you have tons of code you don’t need to look through. Here’s the list of pragmas available.

There’s much more the LWASM program can do like macros and more. Of course the documentation is available here.

Have fun,

Glen

This entry was posted in Uncategorized. Bookmark the permalink.

7 Responses to LWASM – Tricks and cool features

  1. Daniel says:

    I started reading this thinking I could follow along? Mistake! In a couple of your descriptions of the interesting usage you mentioned some “why” where you could re-use labels. OK I can see that where you might have some fairly simple and repetitive routines which are fast and not quite worth making into a subroutine. But the other examples just left me with “huh?” Maybe I need to be more awake and re-read. 🙂

  2. -=chf=- says:

    HI Glen,
    first, thank you for sharing the tips for 6809 assembly, I just read the “Optimizing 6809 Assembly Code”, four parts in a row!

    For me, I did learn a lot on 6809 code optimizing by reading the ASSIST09 source code, and use it on a personal project about 30 years ago… More learning by dissambling the P/L9 compiled code analyzing, then rewriting (most of the LDA #0 could be an CLRA, while no CCR register needed).

    Today I’m trying a new 6809 project, using an HD6309, and will re-assemble the ASSIST09 monitor using the Hitachi 6309 instructions.
    There the problems starting with LWASM!
    Even using the latest version, LWASM stop assembling the ASSIST09 source code in the definition of the WORKPG definition: the label VECTAB defined as ” * – NUMVTR*2 ” stop the assembly, while it can be defined on the first pass!
    LWASM seems to be a great piece of soft, but with the lack of trying more than one pass to define the labels, it’s not that useful, at least for ASSIST09 (relocatable monitor).
    This isn’t an issue on the asm6809, that product 6309 code too.
    asm6809 is there: https://www.6809.org.uk/asm6809/

    Have a nice code assembling day!
    -=chf=-

    • nowhereman999 says:

      Hi chf,

      I’m glad you found my blog useful, it always makes me happy to know others find it useful. You definitely can learn a lot of neat tricks by disassembling other peoples source code. As for your LWASM problem, make sure there are no spaces in you equation, otherwise LWASM will think that part of it is a comment. If you post the part of the ASSIST09 source could that has the problem I could take a look at it and see if I can offer any help.

      Cheers,
      Glen

  3. -=chf=- says:

    Hi Glen,

    thank for your fast reply, on this Sunday! ;o)

    So, after your suggestion, I double check anythings…
    First, I did run the 4.17 version of lwasm, move to the 4.18 version but same issues
    Re-read the manual, I think that the ‘ * ‘ was not seen as the ‘ PC ‘ during assembly, but it seems to be OK.

    I make the source smaller, if you want to test it. I can upload to my “website” the full source, that assemble great with asm6809, but had issues with the assist09. I would prefer that lwasm as the only tool I would use, but after trying, I give up, coz I could assemble it on an other way.

    At the moment, I’m on the hardware design, and playing with KiCad…

    Here the source I work on (part of it):

    ;TTL ASSIST09 – MC6809 MONITOR
    ;OPT ABS,LLE=85,S,CRE
    ;OPT PAG ;opt cd – enable detailed cycle counts breaking down addressing modes: [5+3]

    *pragma 6309conv,m80ext ;index0tonone autobranchlength

    ; *************************************
    ; * COPYRIGHT (C) MOTOROLA, INC. 1979 *
    ; *************************************

    ; *********************************************
    ; * GLOBAL MODULE EQUATES
    ; *********************************************

    I_O_SEL EQU $EF ;base I/O selected on uP card
    I_O_PAG EQU I_O_SEL*$100 ;base I/O adresses
    I_O_SIZ EQU 256 ;lenght of I/O page

    ROMBEG EQU I_O_PAG+I_O_SIZ ; ROM START ASSEMBLY ADDRESS $F000
    RAMOFS EQU -I_O_SIZ-$200 ; ROM OFFSET TO RAM WORK PAGE -$300
    ROMSIZ EQU $10000-ROMBEG ; ROM SIZE $1000
    ROM2OF EQU ROMBEG+$0800 ; START OF EXTENSION ROM $F800
    ACIA EQU I_O_PAG+$00 ; DEFAULT ACIA ADDRESS $EF00
    PTM EQU I_O_PAG+$08 ; DEFAULT PTM ADDRESS $EF08
    DFTCHP EQU 0 ; DEFAULT CHARACTER PAD COUNT
    DFTNLP EQU 5 ; DEFAULT NEW LINE PAD COUNT
    PROMPT EQU ‘>’ ; PROMPT CHARACTER
    NUMBKP EQU 8 ; NUMBER OF BREAKPOINTS
    ; *********************************************

    ; *********************************************
    ; * MISCELLANEOUS EQUATES
    ; *********************************************
    EOT EQU $04 ; END OF TRANSMISSION
    BELL EQU $07 ; BELL CHARACTER
    LF EQU $0A ; LINE FEED
    CR EQU $0D ; CARRIAGE RETURN
    DLE EQU $10 ; DATA LINE ESCAPE
    CAN EQU $18 ; CANCEL (CTRL-X)
    ; * PTM ACCESS DEFINITIONS
    PTMSTA EQU PTM+1 ; READ STATUS REGISTER
    PTMC13 EQU PTM ; CONTROL REGISTER 1 AND 3
    PTMC2 EQU PTM+1 ; CONTROL REGISTER 2
    PTMTM1 EQU PTM+2 ; LATCH 1
    PTMTM2 EQU PTM+4 ; LATCH 2
    PTMTM3 EQU PTM+6 ; LATCH 3
    ; * ACIA ACCESS DEFINITIONS
    ACIACR EQU ACIA+0 ;command register offset
    ACIASR EQU ACIA+0 ;status register offset
    ACIATD EQU ACIA+1 ;transmit data register offset
    ACIADR EQU ACIA+1 ;receive data register offset

    SKIP2 EQU $8C ; “CMPX #” OPCODE – SKIPS TWO BYTES

    ; **************************************************
    ; * ASSIST09 MONITOR SWI FUNCTIONS
    ; * THE FOLLOWING EQUATES DEFINE FUNCTIONS PROVIDED
    ; * BY THE ASSIST09 MONITOR VIA THE SWI INSTRUCTION.
    ; **************************************************
    INCHNP EQU 0 ; INPUT CHAR IN A REG – NO PARITY
    OUTCH EQU 1 ; OUTPUT CHAR FROM A REG
    PDATA1 EQU 2 ; OUTPUT STRING
    PDATA EQU 3 ; OUTPUT CR/LF THEN STRING
    OUT2HS EQU 4 ; OUTPUT TWO HEX AND SPACE
    OUT4HS EQU 5 ; OUTPUT FOUR HEX AND SPACE
    PCRLF EQU 6 ; OUTPUT CR/LF
    SPACE EQU 7 ; OUTPUT A SPACE
    MONITR EQU 8 ; ENTER ASSIST09 MONITOR
    VCTRSW EQU 9 ; VECTOR EXAMINE/SWITCH
    BRKPT EQU 10 ; USER PROGRAM BREAKPOINT
    PAUSE EQU 11 ; TASK PAUSE FUNCTION
    NUMFUN EQU 11 ; NUMBER OF AVAILABLE FUNCTIONS
    ; * NEXT SUB-CODES FOR ACCESSING THE VECTOR TABLE.
    ; * THEY ARE EQUIVALENT TO OFFSETS IN THE TABLE.
    ; * RELATIVE POSITIONING MUST ME MAINTAINED.
    _AVTBL EQU 0 ; ADDRESS OF VECTOR TABLE
    _CMDL1 EQU 2 ; FIRST COMMAND LIST
    _RSVD EQU 4 ; RESERVED HARDWARE VECTOR
    _SWI3 EQU 6 ; SWI3 ROUTINE
    _SWI2 EQU 8 ; SWI2 ROUTINE
    _FIRQ EQU 10 ; FIRQ ROUTINE
    _IRQ EQU 12 ; IRQ ROUTINE
    _SWI EQU 14 ; SWI ROUTINE
    _NMI EQU 16 ; NMI ROUTINE
    _RESET EQU 18 ; RESET ROUTINE
    _CION EQU 20 ; CONSOLE ON
    _CIDTA EQU 22 ; CONSOLE INPUT DATA
    _CIOFF EQU 24 ; CONSOLE INPUT OFF
    _COON EQU 26 ; CONSOLE OUTPUT ON
    _CODTA EQU 28 ; CONSOLE OUTPUT DATA
    _COOFF EQU 30 ; CONSOLE OUTPUT OFF
    _HSDTA EQU 32 ; HIGH SPEED PRINTDATA
    _BSON EQU 34 ; PUNCH/LOAD ON
    _BSDAT EQU 36 ; PUNCH/LOAD DATA
    _BSOFF EQU 38 ; PUNCH/LOAD OFF
    _PAUSE EQU 40 ; TASK PAUSE ROUTINE
    _EXPAN EQU 42 ; EXPRESSION ANALYZER
    _CMDL2 EQU 44 ; SECOND COMMAND LIST
    _ACIA EQU 46 ; ACIA ADDRESS
    _PAD EQU 48 ; CHARACTER PAD AND NEW LINE PAD
    _ECHO EQU 50 ; ECHO/LOAD AND NULL BKPT FLAG
    _PTM EQU 52 ; PTM ADDRESS
    NUMVTR EQU 52/2+1 ; NUMBER OF VECTORS
    HIVTR EQU 52 ; HIGHEST VECTOR OFFSET

    ; **************************************************
    ; * WORK AREA
    ; * THIS WORK AREA IS ASSIGNED TO THE PAGE ADDRESSED BY
    ; * -$1800,PCR FROM THE BASE ADDRESS OF THE ASSIST09
    ; * ROM. THE DIRECT PAGE REGISTER DURING MOST ROUTINE
    ; * OPERATIONS WILL POINT TO THIS WORK AREA. THE STACK
    ; * INITIALLY STARTS UNDER THE RESERVED WORK AREAS AS
    ; * DEFINED HEREIN.
    ; **************************************************
    WORKPG EQU ROMBEG+RAMOFS ; SETUP DIRECT PAGE ADDRESS $ED00
    SETDP WORKPG/$100 ; NOTIFY ASSEMBLER $ED
    ORG WORKPG+256 ; READY PAGE DEFINITIONS $EE00
    ; * THE FOLLOWING THRU BKPTOP MUST RESIDE IN THIS ORDER
    ; * FOR PROPER INITIALIZATION
    ORG *-4
    PAUSER EQU * ; PAUSE ROUTINE
    ORG *-1
    SWIBFL EQU * ; BYPASS SWI AS BREAKPOINT FLAG
    ORG *-1
    BKPTCT EQU * ; BREAKPOINT COUNT
    ORG *-2
    SLEVEL EQU * ; STACK TRACE LEVEL
    ORG *-NUMVTR*2
    VECTAB EQU * ; VECTOR TABLE
    ORG *-2*NUMBKP
    BKPTBL EQU * ; BREAKPOINT TABLE
    ORG *-2*NUMBKP
    BKPTOP EQU * ; BREAKPOINT OPCODE TABLE
    ORG *-2
    WINDOW EQU * ; WINDOW
    ORG *-2
    ADDR EQU * ; ADDRESS POINTER VALUE
    ORG *-1
    BASEPG EQU * ; BASE PAGE VALUE
    ORG *-2
    NUMBER EQU * ; BINARY BUILD AREA
    ORG *-2
    LASTOP EQU * ; LAST OPCODE TRACED
    ORG *-2
    RSTACK EQU * ; RESET STACK POINTER
    ORG *-2
    PSTACK EQU * ; COMMAND RECOVERY STACK
    ORG *-2
    PCNTER EQU * ; LAST PROGRAM COUNTER
    ORG *-2
    TRACEC EQU * ; TRACE COUNT
    ORG *-1
    SWICNT EQU * ; TRACE “SWI” NEST LEVEL COUNT
    ORG *-1 ; (MISFLG MUST FOLLOW SWICNT)
    MISFLG EQU * ; LOAD CMD/THRU BREAKPOINT FLAG
    ORG *-1
    DELIM EQU * ; EXPRESSION DELIMITER/WORK BYTE
    ORG *-40
    ROM2WK EQU * ; EXTENSION ROM RESERVED AREA
    ORG *-21 ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<< for 6309 add two more byte: -23
    TSTACK EQU * ; TEMPORARY STACK HOLD
    STACK EQU * ; START OF INITIAL STACK

    ; *****************************************************
    ; * DEFAULT THE ROM BEGINNING ADDRESS TO 'ROMBEG'
    ; * ASSIST09 IS POSITION ADDRESS INDEPENDENT HOWEVER
    ; * WE ASSEMBLE ASSUMING CONTROL OF THE HARDWARE VECTORS.
    ; * NOTE THAT THE WORK RAM PAGE MUST BE 'RAMOFS'
    ; * FROM THE ROM BEGINNING ADDRESS.
    ; *****************************************************
    ORG ROMBEG+$800 ; ROM ASSEMBLY/DEFAULT ADDRESS <<<<<VALID STACK RAM
    ; * OUTPUT: U->VECTOR TABLE ADDRESS
    ; * DPR->ASSIST09 WORK AREA PAGE
    ; * THE VECTOR TABLE AND DEFAULTS ARE INITIALIZED
    ; * ALL REGISTERS VOLATILE.
    ; *****************************************************
    BLDVTR LEAX VECTAB,PCR ; ADDRESS VECTOR TABLE
    TFR X,D ; OBTAIN BASE PAGE ADDRESS
    TFR A,DP ; SETUP DPR
    STA BASEPG ; STORE FOR QUICK REFERENCE
    LEAU ,X ; RETURN TABLE TO CALLER
    LEAY <INITVT,PCR ; LOAD FROM ADDR
    STU ,X++ ; INIT VECTOR TABLE ADDRESS
    LDB #NUMVTR-5 ; NUMBER OF RELOCATABLE VECTORS
    PSHS B ; STORE INDEX ON STACK
    BLD2 TFR Y,D ; PREPARE ADDRESS RESOLVE
    ADDD ,Y++ ; TO ABSOLUTE ADDRESS
    STD ,X++ ; INTO VECTOR TABLE
    DEC ,S ; COUNT DOWN
    BNE BLD2 ; BRANCH IF MORE TO INSERT
    LDW #INTVE-INTVS ;<<<< HD6309
    TFM Y+,X+ ;<<<< HD6309
    LEAY ROM2OF,PCR ; TEST POSSIBLE EXTENSION ROM
    LDX #$20FE ; LOAD "BRA *" FLAG PATTERN
    CMPX ,Y++ ; ? EXTENDED ROM HERE
    BNE BLDRTN ; BRANCH NOT OUR ROM TO RETURN
    JSR ,Y ; CALL EXTENDED ROM INITIALIZE
    BLDRTN PULS B,PC ; RETURN TO INITIALIZER

    ; *****************************************************
    ; * RESET ENTRY POINT
    ; * HARDWARE RESET ENTERS HERE IF ASSIST09 IS ENABLED
    ; * TO RECEIVE THE MC6809 HARDWARE VECTORS. WE CALL
    ; * THE BLDVTR SUBROUTINE TO INITIALIZE THE VECTOR
    ; * TABLE, STACK, AND THE FIREUP THE MONITOR VIA SWI
    ; * CALL.
    ; *****************************************************
    RESET LEAS STACK,PCR ; SETUP INITIAL STACK
    BSR BLDVTR ; BUILD VECTOR TABLE
    RESET2 CLRA ; ISSUE STARTUP MESSAGE
    TFR A,DP ; DEFAULT TO PAGE ZERO
    SWI ; PERFORM MONITOR FIREUP
    FCB MONITR ; TO ENTER COMMAND PROCESSION
    BRA RESET2 ; REENTER MONITOR IF 'CONTINUE'

    ; *****************************************************
    ; * INITVT – INITIAL VECTOR TABLE
    ; * THIS TABLE IS RELOCATED TO RAM AND REPRESENTS THE
    ; * INITIAL STATE OF THE VECTOR TABLE. ALL ADDRESSES
    ; * ARE CONVERTED TO ABSOLUTE FORM. THIS TABLE STARTS
    ; * WITH THE SECOND ENTRY, ENDS WITH STATIC CONSTANT
    ; * INITIALIZATION DATA WHICH CARRIES BEYOND THE TABLE.
    ; *****************************************************
    INITVT FDB CMDTBL-* ; DEFAULT FIRST COMMAND TABLE
    FDB RSRVDR-* ; DEFAULT UNDEFINED HARDWARE VECTOR
    FDB SWI3R-* ; DEFAULT SWI3
    FDB SWI2R-* ; DEFAULT SWI2
    FDB FIRQR-* ; DEFAULT FIRQ
    FDB IRQR-* ; DEFAULT IRQ ROUTINE
    FDB SWIR-* ; DEFAULT SWI ROUTINE
    FDB NMIR-* ; DEFAULT NMI ROUTINE
    FDB RESET-* ; RESTART VECTOR
    FDB CION-* ; DEFAULT CION
    FDB CIDAT-* ; DEFAULT CIDAT
    FDB CIOFF-* ; DEFAULT CIOFF
    FDB COON-* ; DEFAULT COON
    FDB CODAT-* ; DEFAULT CODAT
    FDB COOFF-* ; DEFAULT COOFF
    FDB HSDTA-* ; DEFAULT HSDTA
    FDB BSON-* ; DEFAULT BSON
    FDB BSDAT-* ; DEFAULT BSDAT
    FDB BSOFF-* ; DEFAULT BSOFF
    FDB PAUSER-* ; DEFAULT PAUSE ROUTINE
    FDB EXP1-* ; DEFAULT EXPRESSION ANALYZER
    FDB CMDTB2-* ; DEFAULT SECOND COMMAND TABLE
    ; * CONSTANTS
    INTVS FDB ACIA ; DEFAULT ACIA
    FCB DFTCHP,DFTNLP ; DEFAULT NULL PADDS
    FDB 0 ; DEFAULT ECHO
    FDB PTM ; DEFAULT PTM
    FDB 0 ; INITIAL STACK TRACE LEVEL
    FCB 0 ; INITIAL BREAKPOINT COUNT
    FCB 0 ; SWI BREAKPOINT LEVEL
    FCB $39 ; DEFAULT PAUSE ROUTINE (RTS)
    INTVE EQU *

    CMDTBL equ *
    RSRVDR equ *
    SWI3R equ *
    SWI2R equ *
    FIRQR equ *
    IRQR equ *
    SWIR equ *
    NMIR equ *
    CION equ *
    CIDAT equ *
    CIOFF equ *
    COON equ *
    CODAT equ *
    COOFF equ *
    HSDTA equ *
    BSON equ *
    BSDAT equ *
    BSOFF equ *
    EXP1 equ *
    CMDTB2 equ *

    • nowhereman999 says:

      Hi chf,

      I got it to assemble by assigning names instead of the ‘*’ in all the pointers. I don’t know if it’s correct (I think it is), but give it a try and compare the binary with the one that asm09 made.

      ;TTL ASSIST09 – MC6809 MONITOR
      ;OPT ABS,LLE=85,S,CRE
      ;OPT PAG ;opt cd – enable detailed cycle counts breaking down addressing modes: [5+3]

      *pragma 6309conv,m80ext ;index0tonone autobranchlength

      ; *************************************
      ; * COPYRIGHT (C) MOTOROLA, INC. 1979 *
      ; *************************************

      ; *********************************************
      ; * GLOBAL MODULE EQUATES
      ; *********************************************

      I_O_SEL EQU $EF ;base I/O selected on uP card
      I_O_PAG EQU I_O_SEL*$100 ;base I/O adresses
      I_O_SIZ EQU 256 ;lenght of I/O page

      ROMBEG EQU I_O_PAG+I_O_SIZ ; ROM START ASSEMBLY ADDRESS $F000
      RAMOFS EQU -I_O_SIZ-$200 ; ROM OFFSET TO RAM WORK PAGE -$300
      ROMSIZ EQU $10000-ROMBEG ; ROM SIZE $1000
      ROM2OF EQU ROMBEG+$0800 ; START OF EXTENSION ROM $F800
      ACIA EQU I_O_PAG+$00 ; DEFAULT ACIA ADDRESS $EF00
      PTM EQU I_O_PAG+$08 ; DEFAULT PTM ADDRESS $EF08
      DFTCHP EQU 0 ; DEFAULT CHARACTER PAD COUNT
      DFTNLP EQU 5 ; DEFAULT NEW LINE PAD COUNT
      PROMPT EQU ‘>’ ; PROMPT CHARACTER
      NUMBKP EQU 8 ; NUMBER OF BREAKPOINTS
      ; *********************************************

      ; *********************************************
      ; * MISCELLANEOUS EQUATES
      ; *********************************************
      EOT EQU $04 ; END OF TRANSMISSION
      BELL EQU $07 ; BELL CHARACTER
      LF EQU $0A ; LINE FEED
      CR EQU $0D ; CARRIAGE RETURN
      DLE EQU $10 ; DATA LINE ESCAPE
      CAN EQU $18 ; CANCEL (CTRL-X)
      ; * PTM ACCESS DEFINITIONS
      PTMSTA EQU PTM+1 ; READ STATUS REGISTER
      PTMC13 EQU PTM ; CONTROL REGISTER 1 AND 3
      PTMC2 EQU PTM+1 ; CONTROL REGISTER 2
      PTMTM1 EQU PTM+2 ; LATCH 1
      PTMTM2 EQU PTM+4 ; LATCH 2
      PTMTM3 EQU PTM+6 ; LATCH 3
      ; * ACIA ACCESS DEFINITIONS
      ACIACR EQU ACIA+0 ;command register offset
      ACIASR EQU ACIA+0 ;status register offset
      ACIATD EQU ACIA+1 ;transmit data register offset
      ACIADR EQU ACIA+1 ;receive data register offset

      SKIP2 EQU $8C ; “CMPX #” OPCODE – SKIPS TWO BYTES

      ; **************************************************
      ; * ASSIST09 MONITOR SWI FUNCTIONS
      ; * THE FOLLOWING EQUATES DEFINE FUNCTIONS PROVIDED
      ; * BY THE ASSIST09 MONITOR VIA THE SWI INSTRUCTION.
      ; **************************************************
      INCHNP EQU 0 ; INPUT CHAR IN A REG – NO PARITY
      OUTCH EQU 1 ; OUTPUT CHAR FROM A REG
      PDATA1 EQU 2 ; OUTPUT STRING
      PDATA EQU 3 ; OUTPUT CR/LF THEN STRING
      OUT2HS EQU 4 ; OUTPUT TWO HEX AND SPACE
      OUT4HS EQU 5 ; OUTPUT FOUR HEX AND SPACE
      PCRLF EQU 6 ; OUTPUT CR/LF
      SPACE EQU 7 ; OUTPUT A SPACE
      MONITR EQU 8 ; ENTER ASSIST09 MONITOR
      VCTRSW EQU 9 ; VECTOR EXAMINE/SWITCH
      BRKPT EQU 10 ; USER PROGRAM BREAKPOINT
      PAUSE EQU 11 ; TASK PAUSE FUNCTION
      NUMFUN EQU 11 ; NUMBER OF AVAILABLE FUNCTIONS
      ; * NEXT SUB-CODES FOR ACCESSING THE VECTOR TABLE.
      ; * THEY ARE EQUIVALENT TO OFFSETS IN THE TABLE.
      ; * RELATIVE POSITIONING MUST ME MAINTAINED.
      _AVTBL EQU 0 ; ADDRESS OF VECTOR TABLE
      _CMDL1 EQU 2 ; FIRST COMMAND LIST
      _RSVD EQU 4 ; RESERVED HARDWARE VECTOR
      _SWI3 EQU 6 ; SWI3 ROUTINE
      _SWI2 EQU 8 ; SWI2 ROUTINE
      _FIRQ EQU 10 ; FIRQ ROUTINE
      _IRQ EQU 12 ; IRQ ROUTINE
      _SWI EQU 14 ; SWI ROUTINE
      _NMI EQU 16 ; NMI ROUTINE
      _RESET EQU 18 ; RESET ROUTINE
      _CION EQU 20 ; CONSOLE ON
      _CIDTA EQU 22 ; CONSOLE INPUT DATA
      _CIOFF EQU 24 ; CONSOLE INPUT OFF
      _COON EQU 26 ; CONSOLE OUTPUT ON
      _CODTA EQU 28 ; CONSOLE OUTPUT DATA
      _COOFF EQU 30 ; CONSOLE OUTPUT OFF
      _HSDTA EQU 32 ; HIGH SPEED PRINTDATA
      _BSON EQU 34 ; PUNCH/LOAD ON
      _BSDAT EQU 36 ; PUNCH/LOAD DATA
      _BSOFF EQU 38 ; PUNCH/LOAD OFF
      _PAUSE EQU 40 ; TASK PAUSE ROUTINE
      _EXPAN EQU 42 ; EXPRESSION ANALYZER
      _CMDL2 EQU 44 ; SECOND COMMAND LIST
      _ACIA EQU 46 ; ACIA ADDRESS
      _PAD EQU 48 ; CHARACTER PAD AND NEW LINE PAD
      _ECHO EQU 50 ; ECHO/LOAD AND NULL BKPT FLAG
      _PTM EQU 52 ; PTM ADDRESS
      NUMVTR EQU 52/2+1 ; NUMBER OF VECTORS
      HIVTR EQU 52 ; HIGHEST VECTOR OFFSET

      ; **************************************************
      ; * WORK AREA
      ; * THIS WORK AREA IS ASSIGNED TO THE PAGE ADDRESSED BY
      ; * -$1800,PCR FROM THE BASE ADDRESS OF THE ASSIST09
      ; * ROM. THE DIRECT PAGE REGISTER DURING MOST ROUTINE
      ; * OPERATIONS WILL POINT TO THIS WORK AREA. THE STACK
      ; * INITIALLY STARTS UNDER THE RESERVED WORK AREAS AS
      ; * DEFINED HEREIN.
      ; **************************************************
      WORKPG EQU ROMBEG+RAMOFS ; SETUP DIRECT PAGE ADDRESS $ED00
      SETDP WORKPG/$100 ; NOTIFY ASSEMBLER $ED
      ORG WORKPG+256 ; READY PAGE DEFINITIONS $EE00
      ; * THE FOLLOWING THRU BKPTOP MUST RESIDE IN THIS ORDER
      ; * FOR PROPER INITIALIZATION
      HERE *
      ORG HERE-4
      PAUSER EQU * ; PAUSE ROUTINE
      ORG PAUSER-1
      SWIBFL EQU * ; BYPASS SWI AS BREAKPOINT FLAG
      ORG SWIBFL-1
      BKPTCT EQU * ; BREAKPOINT COUNT
      ORG BKPTCT-2
      SLEVEL EQU * ; STACK TRACE LEVEL
      ORG SLEVEL-NUMVTR*2
      VECTAB EQU * ; VECTOR TABLE
      ORG VECTAB-2*NUMBKP
      BKPTBL EQU * ; BREAKPOINT TABLE
      ORG BKPTBL-2*NUMBKP
      BKPTOP EQU * ; BREAKPOINT OPCODE TABLE
      ORG BKPTOP-2
      WINDOW EQU * ; WINDOW
      ORG WINDOW-2
      ADDR EQU * ; ADDRESS POINTER VALUE
      ORG ADDR-1
      BASEPG EQU * ; BASE PAGE VALUE
      ORG BASEPG-2
      NUMBER EQU * ; BINARY BUILD AREA
      ORG NUMBER-2
      LASTOP EQU * ; LAST OPCODE TRACED
      ORG LASTOP-2
      RSTACK EQU * ; RESET STACK POINTER
      ORG RSTACK-2
      PSTACK EQU * ; COMMAND RECOVERY STACK
      ORG PSTACK-2
      PCNTER EQU * ; LAST PROGRAM COUNTER
      ORG PCNTER-2
      TRACEC EQU * ; TRACE COUNT
      ORG TRACEC-1
      SWICNT EQU * ; TRACE “SWI” NEST LEVEL COUNT
      ORG SWICNT-1 ; (MISFLG MUST FOLLOW SWICNT)
      MISFLG EQU * ; LOAD CMD/THRU BREAKPOINT FLAG
      ORG MISFLG-1
      DELIM EQU * ; EXPRESSION DELIMITER/WORK BYTE
      ORG DELIM-40
      ROM2WK EQU * ; EXTENSION ROM RESERVED AREA
      ORG ROM2WK-21 ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<< for 6309 add two more byte: -23
      TSTACK EQU * ; TEMPORARY STACK HOLD
      STACK EQU * ; START OF INITIAL STACK

      ; *****************************************************
      ; * DEFAULT THE ROM BEGINNING ADDRESS TO 'ROMBEG'
      ; * ASSIST09 IS POSITION ADDRESS INDEPENDENT HOWEVER
      ; * WE ASSEMBLE ASSUMING CONTROL OF THE HARDWARE VECTORS.
      ; * NOTE THAT THE WORK RAM PAGE MUST BE 'RAMOFS'
      ; * FROM THE ROM BEGINNING ADDRESS.
      ; *****************************************************
      ORG ROMBEG+$800 ; ROM ASSEMBLY/DEFAULT ADDRESS <<<<VECTOR TABLE ADDRESS
      ; * DPR->ASSIST09 WORK AREA PAGE
      ; * THE VECTOR TABLE AND DEFAULTS ARE INITIALIZED
      ; * ALL REGISTERS VOLATILE.
      ; *****************************************************
      BLDVTR:
      LEAX VECTAB,PCR ; ADDRESS VECTOR TABLE
      TFR X,D ; OBTAIN BASE PAGE ADDRESS
      TFR A,DP ; SETUP DPR
      STA BASEPG ; STORE FOR QUICK REFERENCE
      LEAU ,X ; RETURN TABLE TO CALLER
      LEAY <INITVT,PCR ; LOAD FROM ADDR
      STU ,X++ ; INIT VECTOR TABLE ADDRESS
      LDB #NUMVTR-5 ; NUMBER OF RELOCATABLE VECTORS
      PSHS B ; STORE INDEX ON STACK
      BLD2 TFR Y,D ; PREPARE ADDRESS RESOLVE
      ADDD ,Y++ ; TO ABSOLUTE ADDRESS
      STD ,X++ ; INTO VECTOR TABLE
      DEC ,S ; COUNT DOWN
      BNE BLD2 ; BRANCH IF MORE TO INSERT
      LDW #INTVE-INTVS ;<<<< HD6309
      TFM Y+,X+ ;<<<< HD6309
      LEAY ROM2OF,PCR ; TEST POSSIBLE EXTENSION ROM
      LDX #$20FE ; LOAD "BRA *" FLAG PATTERN
      CMPX ,Y++ ; ? EXTENDED ROM HERE
      BNE BLDRTN ; BRANCH NOT OUR ROM TO RETURN
      JSR ,Y ; CALL EXTENDED ROM INITIALIZE
      BLDRTN PULS B,PC ; RETURN TO INITIALIZER

      ; *****************************************************
      ; * RESET ENTRY POINT
      ; * HARDWARE RESET ENTERS HERE IF ASSIST09 IS ENABLED
      ; * TO RECEIVE THE MC6809 HARDWARE VECTORS. WE CALL
      ; * THE BLDVTR SUBROUTINE TO INITIALIZE THE VECTOR
      ; * TABLE, STACK, AND THE FIREUP THE MONITOR VIA SWI
      ; * CALL.
      ; *****************************************************
      RESET LEAS STACK,PCR ; SETUP INITIAL STACK
      BSR BLDVTR ; BUILD VECTOR TABLE
      RESET2 CLRA ; ISSUE STARTUP MESSAGE
      TFR A,DP ; DEFAULT TO PAGE ZERO
      SWI ; PERFORM MONITOR FIREUP
      FCB MONITR ; TO ENTER COMMAND PROCESSION
      BRA RESET2 ; REENTER MONITOR IF 'CONTINUE'

      ; *****************************************************
      ; * INITVT – INITIAL VECTOR TABLE
      ; * THIS TABLE IS RELOCATED TO RAM AND REPRESENTS THE
      ; * INITIAL STATE OF THE VECTOR TABLE. ALL ADDRESSES
      ; * ARE CONVERTED TO ABSOLUTE FORM. THIS TABLE STARTS
      ; * WITH THE SECOND ENTRY, ENDS WITH STATIC CONSTANT
      ; * INITIALIZATION DATA WHICH CARRIES BEYOND THE TABLE.
      ; *****************************************************
      INITVT FDB CMDTBL-* ; DEFAULT FIRST COMMAND TABLE
      FDB RSRVDR-* ; DEFAULT UNDEFINED HARDWARE VECTOR
      FDB SWI3R-* ; DEFAULT SWI3
      FDB SWI2R-* ; DEFAULT SWI2
      FDB FIRQR-* ; DEFAULT FIRQ
      FDB IRQR-* ; DEFAULT IRQ ROUTINE
      FDB SWIR-* ; DEFAULT SWI ROUTINE
      FDB NMIR-* ; DEFAULT NMI ROUTINE
      FDB RESET-* ; RESTART VECTOR
      FDB CION-* ; DEFAULT CION
      FDB CIDAT-* ; DEFAULT CIDAT
      FDB CIOFF-* ; DEFAULT CIOFF
      FDB COON-* ; DEFAULT COON
      FDB CODAT-* ; DEFAULT CODAT
      FDB COOFF-* ; DEFAULT COOFF
      FDB HSDTA-* ; DEFAULT HSDTA
      FDB BSON-* ; DEFAULT BSON
      FDB BSDAT-* ; DEFAULT BSDAT
      FDB BSOFF-* ; DEFAULT BSOFF
      FDB PAUSER-* ; DEFAULT PAUSE ROUTINE
      FDB EXP1-* ; DEFAULT EXPRESSION ANALYZER
      FDB CMDTB2-* ; DEFAULT SECOND COMMAND TABLE
      ; * CONSTANTS
      INTVS FDB ACIA ; DEFAULT ACIA
      FCB DFTCHP,DFTNLP ; DEFAULT NULL PADDS
      FDB 0 ; DEFAULT ECHO
      FDB PTM ; DEFAULT PTM
      FDB 0 ; INITIAL STACK TRACE LEVEL
      FCB 0 ; INITIAL BREAKPOINT COUNT
      FCB 0 ; SWI BREAKPOINT LEVEL
      FCB $39 ; DEFAULT PAUSE ROUTINE (RTS)
      INTVE EQU *

      CMDTBL equ *
      RSRVDR equ *
      SWI3R equ *
      SWI2R equ *
      FIRQR equ *
      IRQR equ *
      SWIR equ *
      NMIR equ *
      CION equ *
      CIDAT equ *
      CIOFF equ *
      COON equ *
      CODAT equ *
      COOFF equ *
      HSDTA equ *
      BSON equ *
      BSDAT equ *
      BSOFF equ *
      EXP1 equ *
      CMDTB2 equ *
      END

      Hope it helps. If not maybe reach out to William Astle who wrote LWASM his contact info should be on his website. Which I linked to his documentation in the original post.

  4. -=chf=- says:

    Hello Glen,
    thank you for your suggestion: I saw it early this morning, and modify the source code this night;
    It work, both with assem6309 and lwasm, the code seems to be OK.
    So, the “issue” is due to the “*-x” evaluation by the assembler?
    Sadly, it make the code less readable.
    So, I think that I will comment it to the lwasm developers, maybe it’s a bug.

    Again, Glen, thank you for your help and deep analyze of that problem.

    When I “discover” lwasm, even with a well written manual, there is, at least for me, a lack of example of use of this masterpiece.

    Have a nice day.
    Kind regard.
    -=chf=-

    • nowhereman999 says:

      Hi chf,

      I’m glad I could help, and I totally agree that LWASM is awesome but actual examples would take it to another level and allow more people to start using it.

      Have a great day too,
      Glen

Leave a comment