Page 2 of 4

Re: Mike Kohn's naken_asm

Posted: Tue Mar 04, 2014 3:05 pm
by joe7
All good points, the problem is that it doesn't know the difference between 01 and 0001, so this is the safer default route I think.

Before I had addresses below 256 use zp instructions, but that broke trying to index into the stack from zp because of the wrapping. I can probably add a directive of some sort (what would you call it?).

Re: Mike Kohn's naken_asm

Posted: Tue Mar 04, 2014 3:45 pm
by teamtempest
In my HXA assembler I decided to permit address mode forcing by use of an assembler directive called "ASSUME", rather than the usual method of "decorating" the expression with a sort of pseudo-operator. I did this partly because I imagined that HXA might be ported to other processors that had no use for address mode forcing, so I created the "ASSUME" directive as a handy place to put all processor-specific directives.

HXA evaluates all expressions as 32-bit, but in the case of the 65xx family compares the result to the mnemonic and tries to select the most appropriate bits out of that result to emit as code. "ASSUME" essentially tells HXA in advance which bits to select. It only applies to the next expression encountered, ie., for one line. So something like:

Code: Select all

   .assume absolute
   lda $FE,X
assembles as "BD FE 00" instead of "B5 FE".

So that's one way to do it. Plus I find it easier to read than expression decoration.

Re: Mike Kohn's naken_asm

Posted: Tue Mar 04, 2014 4:15 pm
by barrym95838
Hi teamtempest,

I find your method to be acceptable/agreeable. It wasn't a huge effort for you to implement that feature, was it?

Without getting into the gory details, would you mind explaining briefly, in general terms, how someone would go about doing something like this, for the benefit of all of us, including joe7?

Thanks,

Mike

Re: Mike Kohn's naken_asm

Posted: Tue Mar 04, 2014 4:45 pm
by Klaus2m5
You can always use macros to force an addressing mode:

Code: Select all

00fe =                  zp:     equ $fe

                        ldax    macro       ;lda abs,x - forced abs
                                db  $bd     ;opcode
                                dw  \1      ;absolute address
                                endm

0000 : b5fe                     lda zp,x
                                ldax zp
0002 : bd              >        db  $bd     ;opcode
0003 : fe00            >        dw  zp      ;absolute address

Re: Mike Kohn's naken_asm

Posted: Tue Mar 04, 2014 6:15 pm
by BigDumbDinosaur
BitWise wrote:
The WDC assembler (and mine) uses an address prefix character to force a particular mode. So |addr or !addr forces an absolute mode, <addr is always zero page and >addr is the 65816 long absolute. You can add the index suffixes after the address as usual (e.g |addr,X).

Very useful when you want to force a particular mode or if the assember can't work out the mode because the value is imported from a different relocatable module.
The assembler in my POC monitor is similar in that respect. If one codes LDA #$12, it is assembled as A9 12. If one codes LDA !#$12 it is assembled as A9 12 00. I currently don't do this to direct page instructions, so LDA $12 is always assembled as A5 12 and LDA !$12 would be flagged as an error.

Re: Mike Kohn's naken_asm

Posted: Tue Mar 04, 2014 10:18 pm
by GARTHWILSON
joe7 wrote:
All good points, the problem is that it doesn't know the difference between 01 and 0001, so this is the safer default route I think.
It is rare that we would need abs addressing for addresses in ZP. The assemblers I've used offer a way to do it, but I can't even remember what it is now-- perhaps somethine like LDA >$FE,X. The tiny assembler I wrote for my Forth kernel in an evening puts the addressing mode in the mnemonic itself, like AND,X for abs and AND_ZP,X for ZP, which prevented the need for parsing and also for vocabularies (since AND by itself is already a Forth word). Being in Forth, there is automatically full macro support.
Quote:
Before I had addresses below 256 use zp instructions, but that broke trying to index into the stack from zp because of the wrapping. I can probably add a directive of some sort (what would you call it?).
Now it sounds like you're trying to do negative indexing into the stack which is dangerous if you have interrupts, as they will overwrite values you wanted to read.

The default addressing mode for addresses below $100 really needs to be ZP, but there's nothing wrong with having an operator that forces abs for the rare occasions it might be needed.

Re: Mike Kohn's naken_asm

Posted: Wed Mar 05, 2014 1:40 am
by Tor
It's been decades since I was actually paid to write 6502 assembly code, so in my naivety I feel I must ask: Why doesn't the assembler know the difference between 0001 and 01(or, rather, as I prefer: $0001 and $01)? Because back then the 6502 assembler I used did. If it's so that my memory isn't accurate about the 6502 assembler then certainly assemblers for other architectures I programmed back then and not as far back _did_ know the difference between $0001 and $01 and treated one as 16-bit and the other as 8-bit.

-Tor

Re: Mike Kohn's naken_asm

Posted: Wed Mar 05, 2014 2:54 am
by joe7
Quote:
Now it sounds like you're trying to do negative indexing into the stack which is dangerous if you have interrupts, as they will overwrite values you wanted to read.

The default addressing mode for addresses below $100 really needs to be ZP, but there's nothing wrong with having an operator that forces abs for the rare occasions it might be needed.
I hadn't thought about that. Now I can see how the wrapping can actually serve to protect the stack and defaulting to ZP with < 256 addresses is probably the safer route. Thanks for your insights.
Quote:
It's been decades since I was actually paid to write 6502 assembly code, so in my naivety I feel I must ask: Why doesn't the assembler know the difference between 0001 and 01(or, rather, as I prefer: $0001 and $01)? Because back then the 6502 assembler I used did. If it's so that my memory isn't accurate about the 6502 assembler then certainly assemblers for other architectures I programmed back then and not as far back _did_ know the difference between $0001 and $01 and treated one as 16-bit and the other as 8-bit.
I remember them working like that too. But this is part of a collection of assemblers, so my module only receives the actual number, often the result of an expression so there's know way to know the intent.

Re: Mike Kohn's naken_asm

Posted: Wed Mar 05, 2014 3:33 am
by barrym95838
GARTHWILSON wrote:
Now it sounds like you're trying to do negative indexing into the stack which is dangerous if you have interrupts, as they will overwrite values you wanted to read.
Yeah, you're probably asking for trouble unless you really know what you're doing. Woz is still confusing hobbyists 36-years later with some of his awesomely eccentric techniques!

Mike

Re: Mike Kohn's naken_asm

Posted: Wed Mar 05, 2014 5:56 am
by teamtempest
Quote:
Without getting into the gory details, would you mind explaining briefly, in general terms, how someone would go about doing something like this,
Thanks for asking! :)

It's not really all that difficult if you stop to think about it. All "ASSUME [somemode]" really has to do is set a flag. Whenever an instruction mnemonic is processed, the flag is checked at some point to see if address forcing is active. Before the end of processing every mnemonic the flag is always cleared, so the forcing only applies for one line.

The implemention details come down to things like how many checks are made. For some time HXA has done it by first determining that the expression following a mnemonic describes a legal address mode for that mnemonic, then checking that any forcing is also legal.

The earliest versions checked only that the forced mode was legal for the particular mnemonic, which made it possible that an otherwise "illegal" mode (as determined by examining the expression) could be forced to a legal one. That eventually struck me as an undetected error that really ought to be, so I changed it.

BTW, I agree that address wrapping is the proper way to go on the 6502, but I wonder if the same behavior is necessary in systems where direct and stack pages are not necessarily adjacent. The C128 had (has?) hardware that could relocate them to arbitrary pages, for instance. I suppose there some advantage to consistent behavior, though!

Re: Mike Kohn's naken_asm

Posted: Wed Mar 05, 2014 7:18 am
by BigDumbDinosaur
teamtempest wrote:
The C128 had (has?) hardware that could relocate them to arbitrary pages, for instance. I suppose there some advantage to consistent behavior, though!
Actually, what the C-128's MMU did was a swap, not a true relocation. For example, if you told the MMU that the start of the stack was now at $20 (page, not address), stack accesses would indeed be directed to $02000-$020FF. However, any access to page $20, e.g., LDA $2030, would be directed to page $01, effectively resulting in an LDA $00130 operation in this case.

Ditto for a relocated zero page. For example, a write to the page to which ZP had been relocated would end up in the physical ZP.

The C-128 relocation method isn't anything like relocating direct page or the stack with the 65C816, so in my mind it was a feature of limited value. I never did find a good use for it.

Re: Mike Kohn's naken_asm

Posted: Sun Mar 09, 2014 1:33 am
by joe7
Ok, the current state of the project is that addresses 1-255 will use zp instructions again. However address 0 in particular cannot be resolved because on the first pass labels have an address of 0 also. Therefore, if address 0 is used it will default to abs, absx, absy modes and print a warning.

There is one other possible solution, during pass 2 it could change to zp instructions, and pad the instruction with a NOP. (Pass 1 and 2 must line up, or label addresses will be off..)

Fixed a couple of table problems which may have affected the disassembler/simulator. Have used the assembler extensively in recent weeks with no issues, but let me know if there is a problem.

Latest source here:
https://github.com/mikeakohn/naken_asm

Re: Mike Kohn's naken_asm

Posted: Sun Mar 09, 2014 1:46 am
by GARTHWILSON
joe7 wrote:
Ok, the current state of the project is that addresses 1-255 will use zp instructions again. However address 0 in particular cannot be resolved because on the first pass labels have an address of 0 also.
It shouldn't be a problem, because variables should always be declared before they are used anyway, so the assembler will already know whether they're in ZP or not.
Quote:
There is one other possible solution, during pass 2 it could change to zp instructions, and pad the instruction with a NOP. (Pass 1 and 2 must line up, or label addresses will be off..)
That would lose the efficiency advantage, both in code size and execution time.

Re: Mike Kohn's naken_asm

Posted: Sun Mar 09, 2014 5:45 am
by teamtempest
Quote:
However address 0 in particular cannot be resolved because on the first pass labels have an address of 0 also
Huh - why is that? As you point out, that leads to an artificial limitation in what you can do, and something the programmer has to remember won't work. Presumably you already have some way to associate label names with values. If it's something like an array of records (in Pascal) or structures (in C), just add another field as a "valid" flag. Or if you can make the value field something other than a 16-bit unsigned integer, then any value outside that range can be used as a flag meaning "not valid (yet)".

Re: Mike Kohn's naken_asm

Posted: Sun Mar 09, 2014 8:03 am
by barrym95838
... or, if teamtempest's suggestions wind up taking more effort than you're willing to expend right now, how about $ffff for un-initialized labels? That way, un-initialized references in pass 1 would default to absolute, but zero-page would still be completely available, by simply equating before reference in the source. So your $00ff,x example could be implemented with L00FF,x throughout your code, and L00FF = 0xff at the end of your source.

You're laying the op-codes down during the first pass, right?

I'm not a fan of the NOP idea, for the same reasons stated by Garth.

Mike