dasm-assembler / dasm

Macro assembler with support for several 8-bit microprocessors

Home Page:https://dasm-assembler.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Range error in constant

andrew-davie opened this issue · comments

dasm special-cases negative immediates in, for example...

VAL = -1
  lda #VAL. ; assembles OK

Although numbers are stored internally as 32 bits, and by rights this would be equivalent to...

  lda #$FFFFFFFF

... it assembles OK with dasm using the low bye ($FF) of the internal 32-byte number.
All good so far. It's detecting that the two's complement negative can be expressed as a single byte.

However, long ago when I was "fixing" things, and as a result we were required to write ...

VAL = -1
    lda #VAL&$FF. ; nobody liked this

... well the "fix" was reverted/fixed, and we could once again write just ``lda #-1"
The rationale being that dasm would range-check (I am guessing) to detect if the operand was in the correct (signed or unsigned) range. And now to my point...

The valid signed range is of course 8 bits (2's complement). That is from $80 (-128 signed) to $FF (unsigned).
We should be able to use any value in that range without error. But not outside it.

It seems, however, that dasm is restricting the range to -$FF to +$FF, which is incorrect.
The correct range, as noted, is -$80 to +$FF.

As an example, the following assembles - and it should not...

  lda #-130.  ; whoops!  Range should be -128 to 255 inclusive.

When I first implemented the overflow checks, I started out with a range check from -$80 to $FF. I later noticed that in the negative.asm test Peter F had included some checks that crossed below -$80 that he seems to expect to pass. Though I didn't understand the use case, I didn't want to break the existing assembly, so I relaxed the check from -$FF to $FF.

If someone wants to tighten it up again, I have no objection.

More specifically, the range allowed should be based on the 32 bit value, and then the low byte used.
So, -128 decimal to 255 decimal. Not $80 to $FF in hex values, but actually $FFFFFF80 to $000000FF hex.

Here's the original implementation for .byte and .word.

I had a look just now, and the range check for negative operands is handled a bit differently, and should probably be made to match the .byte case. Here's what it currently looks like...

        //FIX: for negative operands...
        if ( (addrmode == AM_IMM8) && (sym->value <0) )
        {
            opsize=1;
            sym->value=(char)(sym->value & 255);
            break;
        }

...after the dust has settled from the big merge, and I'll have a go at fixing it.

Probably all it needs is...

    if ( (addrmode == AM_IMM8) && (sym->value >= -128) && (sym->value < 256))