Mike Kohn's naken_asm

Programming the 6502 microprocessor and its relatives in assembly and other languages.
joe7
Posts: 78
Joined: 23 Feb 2014

Re: Mike Kohn's naken_asm

Post 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?).
teamtempest
Posts: 443
Joined: 08 Nov 2009
Location: Minnesota
Contact:

Re: Mike Kohn's naken_asm

Post 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.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Mike Kohn's naken_asm

Post 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
Klaus2m5
Posts: 442
Joined: 28 Jul 2012
Location: Wiesbaden, Germany

Re: Mike Kohn's naken_asm

Post 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
6502 sources on GitHub: https://github.com/Klaus2m5
User avatar
BigDumbDinosaur
Posts: 9428
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: Mike Kohn's naken_asm

Post 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.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
User avatar
GARTHWILSON
Forum Moderator
Posts: 8775
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Mike Kohn's naken_asm

Post 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.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
Tor
Posts: 597
Joined: 10 Apr 2011
Location: Norway/Japan

Re: Mike Kohn's naken_asm

Post 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
joe7
Posts: 78
Joined: 23 Feb 2014

Re: Mike Kohn's naken_asm

Post 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.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Mike Kohn's naken_asm

Post 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
teamtempest
Posts: 443
Joined: 08 Nov 2009
Location: Minnesota
Contact:

Re: Mike Kohn's naken_asm

Post 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!
User avatar
BigDumbDinosaur
Posts: 9428
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: Mike Kohn's naken_asm

Post 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.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
joe7
Posts: 78
Joined: 23 Feb 2014

Re: Mike Kohn's naken_asm

Post 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
User avatar
GARTHWILSON
Forum Moderator
Posts: 8775
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: Mike Kohn's naken_asm

Post 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.
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?
teamtempest
Posts: 443
Joined: 08 Nov 2009
Location: Minnesota
Contact:

Re: Mike Kohn's naken_asm

Post 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)".
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: Mike Kohn's naken_asm

Post 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
Post Reply