Jump to content

Open Club  ·  60 members

DASM
IGNORED

Macro Magic


Thomas Jentzsch

Recommended Posts

For some years I have been using a macro which checks if code or data crosses a page boundary. It worked very well, but sometimes too well. Then it failed in an early assembler pass, where it would have succeeded in the final one.

 

Today Andrew came up with a brilliant idea: Define a label inside the macro in case of success only. And use that label later on. The assembler will return with an error if he cannot resolve the label in the final pass.

 

For convenience I added the success check into my macro too. Here is the updated macro:

_ERR SET 0

  MAC CHECKPAGE ; {address}
    LIST OFF              ; keep the list file clean
    IF (>(.-1)) != >{1}
      ECHO ""
      ECHO "ERROR: different pages! (", {1}, ",", .-1, ")"
      ECHO ""
;      ERR                ; previously this aborted the assembly
_ERR SET _ERR + 1         ; count number of errors (useful for extra output)
    ELSE
CHECKPAGE_{1}             ; define in case of success
    ENDIF
$CHECK SET CHECKPAGE_{1}  ; check success
    LIST ON
  ENDM

Usage:

Table
  .byte 1, 2, 3, 4,...
  CHECKPAGE Table

If Table crosses a page boundary the assembler will error: 

CHECKPAGE_Table ????(r )

 

  • Like 1
Link to comment
Share on other sites

If I use the version that's in github master, it seems to work for me. (I uncommented your commented ERR statement) Here's my output if I use an ORG of $10ff...

 

/usr/local/bin/dasm scratch.asm -f3 -sscratch.symbol.txt -lscratch.listing.txt  -I. -I../includes -oscratch.bin
 
 ERROR: different pages! ( $10ff , $1102 )
 

scratch.asm (27): error: ERR pseudo-op encountered.
 

and my output if I use an ORG of $1000...

 

/usr/local/bin/dasm scratch.asm -f3 -sscratch.symbol.txt -lscratch.listing.txt  -I. -I../includes -oscratch.bin

Complete.

 

That seems to be what you intended.

Link to comment
Share on other sites

  • 1 month later...

What does $CHECK do?

 

I changed that line to:

	IFNCONST CHECKPAGE_{1}
	  ECHO "ERROR: page crossing (",{1},",",.-1,")"
	  ERR
	ENDIF

(and removed the ECHOs from the other IF block) which seems to work, but I’m not certain it solves the original problem with using ERR directly, and I’m also not certain it works with a developmental dasm. I’m using 2.20.13, which I believe is the latest release.

Link to comment
Share on other sites

I found that (.-1) is useful when I’m confirming some block is on a single page, but when I’m confirming 2 different blocks are on the same page, I just want (.). So I split it into two separate macros. Here’s what I have now (I changed some names in my preference):

 

        mac samehighimpl ; {addr1,addr2}
        list localoff
        if >{1} == >{2}
SAMEHIGH_{1}_{2}_EXISTS ; defined if high bytes are equal
        endif
        ifnconst SAMEHIGH_{1}_{2}_EXISTS
          echo "ERROR: high byte difference (",{1},",",{2},")"
          err
        endif
        endm

        mac prevsamehighas ; {addr}
SAMEHIGHBASE set .-1 ; evaluate here so SAMEHIGH_{1}_{2}_EXISTS will work
        samehighimpl SAMEHIGHBASE,{1}
        endm

        mac nextsamehighas ; {addr}
SAMEHIGHBASE set . ; evaluate here so SAMEHIGH_{1}_{2}_EXISTS will work
        samehighimpl SAMEHIGHBASE,{1}
        endm

 

Edited by bizarrostormy
  • Like 1
Link to comment
Share on other sites

Now, how to get it to work for local labels?

 

EDIT: also, the label doesn’t substitute how I want it to. I want it to contain the addresses. Instead {1} expands to SAMEHIGHBASE, and {2} expands to the label (not the address) of the original argument. The implication is it does not support multiple calls for the same label. In some sense, that’s not necessary: of all the addresses that are supposed to be on the same page, the only ones that really matter are the first and the last. But this macro exists to ensure that future revisions don’t break old assumptions, so I would prefer to be able to put the macro everywhere in case one of those future revisions moves things.

Edited by bizarrostormy
Link to comment
Share on other sites

On 7/22/2020 at 1:51 AM, Thomas Jentzsch said:

Not sure why, but as of now, macros do not accept local labels. 

 

I didn’t realize this at the time, but macros apparently have their own namespace, as implied by this line from the documentation:

Quote

You should always use LOCAL labels (.name) inside macros which you use more than once.

which also implies the rationale.

 

The fact that macro calls do not implicitly evaluate their arguments is a major limitation. Tcl technically does the same thing but provides several ways to substitute.

Link to comment
Share on other sites

Just following that suggestion improves the code:

 

        mac samehigh8impl ; {addr1,addr2}
        list localoff
        if >{1} == >{2}
.SAMEHIGH8_EXISTS ; defined if high bytes are equal
        endif
        ifnconst .SAMEHIGH8_EXISTS
          echo "ERROR: high byte difference (",{1},",",{2},")"
          err
        endif
        endm

        mac prevsamehigh8as ; {addr}
SAMEHIGH8BASE set .-1 ; prevent error in samehigh8impl
        samehigh8impl SAMEHIGH8BASE,{1}
        endm

        mac nextsamehigh8as ; {addr}
SAMEHIGH8BASE set . ; prevent error in samehigh8impl
        samehigh8impl SAMEHIGH8BASE,{1}
        endm

 

Still doesn’t work for local labels but does now allow multiple calls with the same label.

 

EDIT: one reason I changed the name from “checkpage” to “samehigh” is because I also have places that need two addresses to have the same low byte. With “samehigh” it is very clear what to call the low-byte equivalent.

 

Edited by bizarrostormy
Link to comment
Share on other sites

  • 3 weeks later...

It’s best to bracket all parameter references used as subexpressions, in case someone passes an argument containing a low-precedence operator:

 

EDIT: I posted code that doesn’t work. Will try again later.

 

EDIT: the gist was to enclose {1} and {2} in brackets, like:

        if >[{1}] == >[{2}]

But that doesn’t work: dasm rejects >[.] and >[.-1], both directly and when passed as a macro argument and then accessed via symbol.

 

EDIT: This seems to work, even when passing . or .-1:

        mac samehigh8impl ; {addr1,addr2}
        list localoff
        if >{1} == >{2} ; dasm currently rejects [.] in some cases
.SAMEHIGH8_EXISTS ; defined if high bytes are equal
        endif
        ifnconst .SAMEHIGH8_EXISTS
          echo "ERROR: high byte difference (",{1},",",{2},")"
          err
        endif
        endm

        mac prevsamehigh8as ; {addr}
SAMEHIGH8BASE set .-1 ; prevent error in samehigh8impl
        samehigh8impl SAMEHIGH8BASE,[{1}]
        endm

        mac nextsamehigh8as ; {addr}
SAMEHIGH8BASE set . ; prevent error in samehigh8impl
        samehigh8impl SAMEHIGH8BASE,[{1}]
        endm

 

Edited by bizarrostormy
Link to comment
Share on other sites

  • 1 month later...

I often want to check the top nybble, and there might be uses (bankswitching?) to check other ranges.

 

This version can check any number of bits on either the high side or the low side.

 

This also uses no global symbols. The trick to getting rid of them was to assign a local label from the parameter in the leaf macro.

 

        mac samebits ; {numbits, addr1, addr2, mask, side}
        list localoff
.numbits = {1}
.addr1 = {2}
.addr2 = {3}
.mask = {4}
.side = {5} ; current dasm doesn't have setstr

.addr1masked = .addr1 & .mask
.addr2masked = .addr2 & .mask
        if .addr1masked == .addr2masked
.SAMEBITS_EXISTS ; defined if non-masked bits are equal
        endif
        ifnconst .SAMEBITS_EXISTS
          echo "ERROR: ", .side, " ", .numbits, "bits difference (", .addr1, ",", .addr2, ")"
          err
        endif
        endm

        mac samelow ; {numbits, addr1, addr2}
        samebits {1}, {2}, {3}, [1<<[{1}]]-1 & $FFFF, "low"
        endm

        mac samehigh ; {numbits, addr1, addr2}
        samebits {1}, {2}, {3}, ~[[1<<[16-[{1}]]]-1] & $FFFF, "high"
        endm

        mac prevsamelowas ; {numbits, addr}
        samelow [{1}], .-1, [{2}]
        endm

        mac nextsamelowas ; {numbits, addr}
        samelow [{1}], ., [{2}]
        endm

        mac prevsamehighas ; {numbits, addr}
        samehigh [{1}], .-1, [{2}]
        endm

        mac nextsamehighas ; {numbits, addr}
        samehigh [{1}], ., [{2}]
        endm

        mac prevsamehigh8as ; {addr} ; deprecated: use prevsamehighas instead
        prevsamehighas 8, [{1}]
        endm

        mac nextsamehigh8as ; {addr} ; deprecated: use nextsamehighas instead
        nextsamehighas 8, [{1}]
        endm

 

Link to comment
Share on other sites

6 hours ago, Thomas Jentzsch said:

Very nice.

 

But AFAIK the latest DASM supports 'setstr'.

 

Ah. I was not aware of the 2.20.14 release. 2.20.13 does not support 'setstr'. TBH I’m not clear on the difference between 'set' and 'setstr'. The = seems to work fine in this case.

Link to comment
Share on other sites

On 10/5/2020 at 12:54 AM, bizarrostormy said:

TBH I’m not clear on the difference between 'set' and 'setstr'. The = seems to work fine in this case.

SETSTR makes a string literally from a symbol name. SET evaluates the value of the stuff on the right side of the SET command, and assigns that value to the symbol. Using = is the same as SET, except it's a constant symbol assignment, where you can repeatedly use SET to assign different values to the same symbol. (This is particularly useful when you want to generate look-up-table data instead of using constants, but by no means the only use for SET)

 

This code...

   processor 6502
   org $1000

 MAC testset

myset1 = {1}
myset2 SET {1}
mysetstr SETSTR {1}

 echo "myset1 is",myset1
 echo "myset2 is",myset2
 echo "mysetstr is",mysetstr

 ENDM

mylabel

 testset mylabel

...will result in this output during the assembly...

DASM 2.20.14-SNAPSHOT
/usr/local/bin/dasm scratch.asm -f3 -sscratch.symbol.txt -lscratch.listing.txt  -I. -I../includes -oscratch.bin
 myset1 is $1000
 myset2 is $1000
 mysetstr is mylabel

Complete. (0)

This is the main use case for SETSTR - so you can have a macro report which symbol it was called with.

  • Thanks 1
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...