6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 23, 2024 7:04 am

All times are UTC




Post new topic Reply to topic  [ 35 posts ]  Go to page Previous  1, 2, 3  Next
Author Message
PostPosted: Wed Nov 21, 2018 5:11 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
On the 65C02, $00 maps to $0000, no matter whether it's encoded as a Zero Page or Absolute address. This stops being true on the 65816 as soon as you start using the DBR and DPR, so $00 can simultaneously map to three completely different addresses, depending only on whether Direct Page, Absolute or Absolute Long mode is chosen by the assembler. Worse, the syntax is not standardised for working around this problem, which is practically unavoidable since you effectively have one "true" address space and two "virtual" ones mapped onto it.

I'll quote from Bruce Clark's tutorial, since he illustrates it well:
Quote:
5.23 A NOTE ON OPERAND ADDRESSES
On the 65C02 and NMOS 6502, LDA $12 (direct addressing) and LDA $0012 (absolute addressing) load data from the same address. On the 65C816, this is not always the case. For example, if the DBR is $12, the D register is $3400, and the m flag is 1, then

LDA $56 (direct addressing) loads data from $003456
LDA $0056 (absolute addressing) loads data from $120056
LDA $000056 (long addressing) loads data from $000056
When encountering an operand address whose high byte is $00, almost all 65C02 and NMOS 6502 assemblers will use zero page addressing rather than absolute addressing as an optimization, since this usually saves a byte and a cycle. It is rarely necessary to override this optimization (i.e. to tell the assembler to use absolute addressing).

However, on the 65C816, it is necessary to pay much closer attention to the addressing mode being assembled, as the example above illustrates. An assembler that assembles code for the 65C816, as well as one (or both) of its 8-bit predecessors may perform the aforementioned optimization even for the 65C816, which may be not what you wanted or intended. It may be worthwhile to review the documentation of your assembler to see how to explicitly specify whether direct, absolute, or long addressing will be used.


On the subject of mnemonics, how do you feel about MVN and MVP? Without carefully reading the documentation, I'd assume they operated in the opposite manner than they actually do. Hence the new mnemonics I've chosen are careful to describe their operation unambiguously, even though they are the same length.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 21, 2018 8:22 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8544
Location: Southern California
Chromatix wrote:
On the subject of mnemonics, how do you feel about MVN and MVP? Without carefully reading the documentation, I'd assume they operated in the opposite manner than they actually do. Hence the new mnemonics I've chosen are careful to describe their operation unambiguously, even though they are the same length.

I think they're quite clear and make total sense in WDC's programming manual (which no 65xx enthusiast should be without), but I still forget and have to refer back to it to make sure I'm using the right one.

_________________
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?


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 21, 2018 8:42 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
Chromatix wrote:
I'll quote from Bruce Clark's tutorial, since he illustrates it well:
Quote:
LDA $56 (direct addressing) loads data from $003456
LDA $0056 (absolute addressing) loads data from $120056
LDA $000056 (long addressing) loads data from $000056


I haven't done enough '816 programing to comment, but how much of a real issue is this?

Because I think you may be framing it incorrectly.

The direct page issue is not that "LDA $56" can load from "$3456", it's simply that it loads from the Direct Page. In the '02 mode, the Direct Page is always $00, in '816 mode, it can be anything. The '816 doesn't HAVE "Zero Page Addressing" any more, rather it has Direct Page addressing, which may or may not be $00 at a particular time.

Similarly with the Absolute addressing.

Perhaps you shouldn't be thinking of the '816 in '02 terms but the other way around.

The complexities you're trying to mitigate are based on the context of when the code is run, what mode the CPU is in, what values the assorted registers are. Issues the 6502 does not have. And these are all things that the Assembler can do little to nothing about, simply because they're runtime attributes, not Assembly time attributes. Assembling the proper instruction to match the intent of the programmer, that's an assembly time issue -- managed by the pseudo ops, or even your suggested syntax changes. And it's certainly useful to try and make sure that the assumptions of the developer are consistent with the configuration of the assembler at the time of assembly.

I'm just not certain than an entire new assembly syntax is the way to reinforce that relationship.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 21, 2018 9:03 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Quote:
Perhaps you shouldn't be thinking of the '816 in '02 terms but the other way around.

But that's exactly the problem I'm trying to solve here. The standard '816 syntax merely extends the standard 'C02 syntax, effectively viewing the former in terms of the latter, and forcing the programmer to do the same. Here I'm setting out specifically with the '816 in mind, and proposing a syntax tailored for its quirks, which doesn't need non-standard workarounds just to ensure the correct addressing mode is selected in edge cases.

And here's why it matters: imagine you have a device handler which copies data from a UART to a fixed buffer in high memory. The buffer happens to be at the beginning of a 64K bank, so you point the DBR at it (eliminating the need for long-mode or indirect addressing, which are both slower than absolute-indexed), and you've also pointed the DPR at the UART (so you can access it in Direct Page mode which is also very fast).

Assuming you use a 28L92, you then need to read from $01 and $03 in Direct-Page mode, which is no problem, but write to $0000,X in Absolute Indexed mode, which naive assemblers might attempt to simplify to Direct-Page Indexed mode, especially if the addresses are sourced from named constants instead of literals. But if they *do* simplify it, they'll make your routine scribble all over the UART's registers!

In the new syntax, there is no such ambiguity, since you read from {$01} and {$03}, then write to ($0000+X). The type of brackets used in each case specifies clearly which addressing mode is intended.

Then there's the register-width modality fiasco, which I'm also trying to address. The opportunity to rationalise the mnemonics really just falls out of these main improvements.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 21, 2018 9:33 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
GARTHWILSON wrote:
Chromatix wrote:
On the subject of mnemonics, how do you feel about MVN and MVP? Without carefully reading the documentation, I'd assume they operated in the opposite manner than they actually do. Hence the new mnemonics I've chosen are careful to describe their operation unambiguously, even though they are the same length.

I think they're quite clear and make total sense in WDC's programming manual (which no 65xx enthusiast should be without), but I still forget and have to refer back to it to make sure I'm using the right one.

This really supports my conclusion that the standard mnemonics are confusing. They appear to be based on the relative locations of data blocks to prevent corruption, but this is only relevant when they overlap, which is probably not the common case for most people (how often is memmove() used versus memcpy()?)

My mnemonics are instead based on the direction of indexing, which is always relevant when using these instructions. Any experienced programmer will be able to interpret that to discover which instruction is needed for overlapping blocks.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 21, 2018 11:35 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8507
Location: Midwestern USA
Chromatix wrote:
On the 65C02, $00 maps to $0000...

You are manufacturing a controversy. Changing DP in itself has no effect on direct page addressing. All one is doing when loading DP with something other than $0000 is changing the MPU's notion of where direct page lies. It only affects a load/store instruction assembled with an eight bit address. In other words, direct page addressing is still direct page addressing. I fail to see any problem here, other than someone perhaps not fully understanding how the '816 works.

Quote:
On the subject of mnemonics, how do you feel about MVN and MVP? Without carefully reading the documentation, I'd assume they operated in the opposite manner than they actually do. Hence the new mnemonics I've chosen are careful to describe their operation unambiguously, even though they are the same length.

These two mnemonics, like MOV in some other assembly languages, are poorly chosen. Nothing gets "moved," only copied. That said, they don't confuse me.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 21, 2018 11:53 pm 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
Quote:
It only affects a load/store instruction assembled with an eight bit address.

Okay, but I'll highlight the central point which you seem to have missed: How does the assembler know, unambiguously, whether Direct Page or Absolute or Long addressing is intended, given an address which could belong in any of the three, and which would refer to different physical addresses in each mode? See earlier posts for concrete examples.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 22, 2018 1:53 am 
Offline

Joined: Thu Mar 10, 2016 4:33 am
Posts: 181
Chromatix wrote:
Okay, but I'll highlight the central point which you seem to have missed: How does the assembler know, unambiguously, whether Direct Page or Absolute or Long addressing is intended, given an address which could belong in any of the three, and which would refer to different physical addresses in each mode? See earlier posts for concrete examples.


There was an earlier example that attempts to disambiguate the address by taking account of the length of the operand:

Quote:
LDA $56 (direct addressing) loads data from $003456
LDA $0056 (absolute addressing) loads data from $120056
LDA $000056 (long addressing) loads data from $000056


The trouble with this method is when we use symbols:

Code:
LDA addr


We don't know the addressing mode. The 65C816 datasheet has some information on the recommended assembler format, but as far as I can tell it is incomplete. It does state that the default addressing mode is two bytes if there is no other information, and that you can use the prefix characters <, |, > to force a subset of the operand value. It appears to be the case that LDA <$1234 would force direct page addressing mode. The datasheet doesn't appear to describe how you would specify the absolute long addressing mode for LDA.

Eyes and Lichty don't resolve this issue either for the rare case where it may be important. If the operand is larger than $FFFF then absolute long would be used. If it is less than $FFFF then absolute would be used and the DBR used to select the bank, which conceivably might not be what you want.

Code like this:
Code:
addr = $00A000
LDA addr

I believe would select absolute addressing. If the programmer wanted this to be absolute long I'm not sure how that could be specified.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 22, 2018 2:18 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8507
Location: Midwestern USA
jds wrote:
Code like this:
Code:
addr = $00A000
LDA addr

I believe would select absolute addressing. If the programmer wanted this to be absolute long I'm not sure how that could be specified.

Page 47 of the '816 data sheet lists the operand format to be used when "promoting" a 16 bit address to 24 bits.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 22, 2018 2:33 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8507
Location: Midwestern USA
Quote:
LDA $56 (direct addressing) loads data from $003456
LDA $0056 (absolute addressing) loads data from $120056
LDA $000056 (long addressing) loads data from $000056

Who cares that LDA $56 loads from $003456? The programmer implicitly knows this because he or she loaded $3400 into DP. From the assembler's point of view, it's just another instruction using direct page addressing.

I also fail to see a problem with LDA $0056. That is the way the '816 works in native mode: it concatenates the operand to whatever is in DB to produce the effective address. This is a generally convenient behavior and may lead to more succinct and faster-acting code. Again, DB has the value in it that was put there by the programmer (or by an MVN or MVP instruction). If you are expecting 65C02 behavior perhaps you should use the 65C02. Or use something outside of the 65xx family. I understand AMD makes a lot of x86-64 units. :D

As for LDA $000056, it's a way to load from physical zero page when DP is pointing elsewhere. Rather slow, but that's the price to be paid for processing a 24 bit address.

At the risk of sounding like a stuck record, I fail to see where there is a problem.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 22, 2018 2:36 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
BDD, you keep describing what the CPU does. We're concerned here with what the assembler does.

Looking at the datasheet, it does indeed provide a (verbose, cryptic, small-print) table of how to specify each addressing mode from each size of memory operand. Bizarrely however, the same modifier is used to extract bits 8-15 (or 8-23) of the operand for use in an immediate operand, and to specify that a memory operand should use Long mode. That makes it difficult to remember and, later, to read the code.

I can use the same modifiers to extract parts of a value, without them being confused with the addressing mode syntax.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 22, 2018 4:38 am 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
Chromatix's point is based on simple assemblers.

My assembler (which is NOT an '816 assembler) will do as he suggests. If the value of the operand is <= $FF, the instruction (if possible) will trend toward a Zero Page addressing mode. For my purposes, this has not been an issue.

If you do:
Code:
LABEL = $0000
LDA LABEL

My assembler just sees zero, and makes it Zero Page.

Mind, my assembler is about a week totals work.

BDDs point is (apparently) that the size of the value of an expression is implicit in how the expression is represented in the assembler.
Code:
$00 = 8 bit
$0000 = 16 bit
$000000 = 24 bit

Much like:
Code:
int i = 100L;

in C will give a warning (because 100L is a long constant), in a "proper" assembler, the argument size should be conveyed based on the constant used.

Thus:
Code:
LABEL1 = $00
LDA LABEL1
LABEL2 = $0000
LDA LABEL2
LABEL3 = $000000
LDA LABEL3

should all "do the right thing".

Chromatix's point, also, is that when you see:
Code:
LDA XXX

You don't know what it will assemble to unless you know the value of XXX. I don't necessarily think that's a bad thing.

I think much of the problems can be mitigated with some type checking and warnings at assembly time, as well as typed expressions. If you add a value to an 8-bit expression, and it overflows, it should, perhaps, cause a warning and truncate rather than promote the value to 16-bits. Base the value of an expression on the type of the first element in the expression.


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 22, 2018 5:34 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8544
Location: Southern California
I like what I think BDD is saying, that the Kowalski assembler he uses assembles the right op code and number of operand bytes from $56 v. $0056 v. $000056—although there will be situations where even if an EQUate referenced by name was defined with $000056 for example and the assembler knew that, you could have other EQUates that were calculated by the assembler and not done by hand.

I use the C32 assembler, but although I've used it for the 65802, I've never used it for an actual '816 with multiple banks available. Also, it has been many years since I needed to refer to an address of less than $100 as absolute (rather than ZP or DP), and at the moment I can't even remember how it's done, and a quick look in the manual isn't revealing it. I might have gotten the info from a fax from Peter Aske (sp?) right after I bought it and asked about some things I couldn't figure out from the manual.

_________________
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?


Top
 Profile  
Reply with quote  
PostPosted: Thu Nov 22, 2018 9:36 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
When you generate code for the 65C816, whether by hand or in a compiler back end you have to track the state of the CPU and if your output is assembly code, rather than direct to binary object code, then you will have to generate commands to the assembler so it knows what state the CPU will execute the code in.

The 'standard' for the 65C816 is to use a combination of directives (longa, longi and dpage) and prefixes on the operand, like this:
Code:
                                             .longa  off             ; The assumed CPU state
                                             .longi  on
                                             
00:4000  A912              :                 lda     #$12            ; State is 8-bits
00:4002  A21200            :                 ldx     #$12            ; State is 16-bits
                                             
00:4005  AD49DF            :                 lda     UIER            ; Assembler picks mode based on value
                                             
                                             .dpage  $df00           ; Change the assumed state ..
                                             
00:4008  A549              :                 lda     UIER            ; .. And the mode changes
                                             
                                             .dpage  $0000           ; Back to the normal value
                                             
00:400A  A549              :                 lda     <UIER           ; Force direct page
00:400C  AD49DF            :                 lda     !UIER           ; Force absolute
00:400F  AF49DF00          :                 lda     >UIER           ; Force long                                   

I find that 65C816 code normally executes predominantly in one state, either 8-bit A + 16-bit X/Y or 16-bit A/X/Y in a given application. Routines that change the state will usually only do it temporarily and then return to the standard state. A C or Pascal runtime for example I would expect to be largely in all 16-bit mode only changing to 8-bit A when handling strings as the main language data types are integers and pointers.

I added a new feature to my assembler yesterday to allow the state of a register size to be 'undefined' (.longa ?) to help catch issues with immediate instructions which change size with CPU state.

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Tue Nov 27, 2018 6:09 am 
Offline

Joined: Mon May 21, 2018 8:09 pm
Posts: 1462
I've started on a prototype assembler that can understand this syntax and do the sort of checking I suggested. This may take a while, as I'm not used to writing syntax parsers, and Boost::Spirit isn't *quite* analogous to EBNF because it always does greedy matching. I should be able to adapt my existing emulator to produce a corresponding disassembly, if only for the 65C02 code it can already execute.

I think I can also add Decimal mode checking as well, using ABCD and SBCD as Decimal-specific mnemonics, and making A and S specific to Binary mode. Only ADC and SBC are affected by the D flag, and I think it's unlikely that the D flag would intentionally be left on outside those rare routines that specifically require Decimal arithmetic.

Thinking carefully about the RMW instructions, I could theoretically append W or B to the I, D, SL, SR, RL, RR mnemonics to make them wide- or narrow-specific. For the moment however, I'll leave them plain and non-specific.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 35 posts ]  Go to page Previous  1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 33 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: