65Org16 Assembler (16-bit bytes, 32-bit address space)

Programming the 6502 microprocessor and its relatives in assembly and other languages.
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Post by BitWise »

Found the bug in a routine that determines if a unsigned value will fit in a byte by testing if the high byte is all ones or all zeroes. Addresses are unsigned so this returns the wrong result for $ffff0000-$ffffffff.

The fixed assembler outputs:

Code: Select all

FFFFF000  00BD8000FFFF      :                 LDA $FFFF8000,X
FFFFF003  00BD8000FFFF      :                 LDA !$FFFF8000,X
FFFFF006  00BD8000FFFF      :                 LDA |$FFFF8000,X
I've updated the 65Org16 assembler zip at
http://www.obelisk.demon.co.uk/files/65016.zip
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
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Post by ElEctric_EyE »

Awesome, I'll be able to put the new update to use in a couple of days...
teamtempest
Posts: 443
Joined: 08 Nov 2009
Location: Minnesota
Contact:

Post by teamtempest »

Quote:
(I couldn't get strings to come out quite right in HXA, so I'm currently working around it with .byte directives and hex values. It's likely that I haven't got the .assume/.cpu directives quite right.)
I'm going to try to expand a little on the HXA 0.180 documention under the assumption that what's there isn't clear enough yet. Maybe writing it out in a longer fashion will even help me understand it better :)

To begin with, HXA deals 32-bit signed and unsigned integers. If we consider those as consisting of four 8-bit octets, I think of them as being laid out this way, from most to least significant:

3 - 2 - 1 - 0

It takes a right shift to move bits to a less significant position, so I visualize the most significant bits as being on the left, regardless of what the actual internal arrangement might be.

When the time comes to produce output, an array of these 32-bit values is a primary source of raw material. However we usually do not want all four octets, and even if we do, we might not want them in that 3-2-1-0 order. So HXA provides options to specify exactly what we do want.

For example, 6502 processors normally want their octets in least significant first order. An 8-bit quantity is just 0, 16-bits is 01, 24-bits is 012, and 32-bits should come out 0123. The 6502 has a 16-bit address bus, and the way to describe all this to HXA is:

Code: Select all

.cpu T_16_L
"T" originally meant "Test", but "16" means "16-bit address bus" and "L" means "Least significant byte first" (as an aside, I've decided this is a useful enough notation that the native 65xx version of HXA, HXA65, actually uses it behind the scenes).

Anyway, what do we want for the 65Org16? This is an "LSB" processor with a 32-bit address space and a 16-bit "byte". The straightforward way to describe that is:

Code: Select all

.cpu T_32_L16
where "L16" means "least significant byte first, 16-bit bytes" (if no number is present after the "L", eight-bit bytes are defaulted).

So what does this get us? Well, the pseudo ops "BYTE" and "WORD" become aliases for "BIT16" and "BIT32" (instead of "BIT08" and "BIT16", respectively) and the "LONG" pseudo op isn't available. This is the trick that lets the same macro instruction set work for both a normal 6502 and the 65Org16, as all the macros are defined in terms of these alias families.

Now

Code: Select all

.byte $ABCD    ; one byte
.word $ABCD    ; two bytes, native order
.revword $ABCD ; two bytes, reverse native order
produces

Code: Select all

DC    ; wrong - should be CD
DC BA ; wrong - should be CD AB
AB CD ; correct
What's happened is that the "L" in "T_32_L16" causes HXA to by default extract 16-bit values in the octet order 01, 32-bits in the order 0123 and reversed 32-bits in the order 3210.

To deal with this HXA extends its "ASSUME" pseudo op to describe custom octet extraction orders. To make the sequence correct for the 65Org16:

Code: Select all

.cpu T_32_L16
.assume BIT16=10, BIT32=1032

.byte $ABCD
.word $ABCD
.revword $ABCD
produces:

Code: Select all

CD
CD AB
AB CD
which is what we want.

Because custom extraction orders are possible the 65Org16 can also be described as a most-significant-byte first processor. In this case the default octet extraction orders run 16-bits 10, 32-bits 3210 and reversed 32-bits 0123. The 16-bit ("byte") order is naturally what we want, but the other two must be accounted for:

Code: Select all

.cpu T_32_M16
.assume BIT32=1032, BIT32R=3210
Given that either way works fine for "byte" and "word" values, is there any reason to prefer one to the other? It turns out there is, and that is because of "string" values.

Character values in HXA range from zero to 255, eight bits or one octet, regardless of the "byte" size. This means that when a "byte" is larger than one octet, characters in strings must be padded to fit. Because the numeric value of a character is always smaller than 256, HXA pads in such a way that the "character octet" is always in the least significant position:

Code: Select all

.cpu T_16_L08
.str "123" ; -> 31 32 33

.cpu T_16_M08
.str "123" ; -> 31 32 33

.cpu T_32_L16
.str "123" ; -> 31 00 32 00 33 00

.cpu T_32_M16
.str "123" ; -> 00 31 00 32 00 33

.cpu T_32_L32
.str "123" ; -> 31 00 00 00 32 00 00 00 33 00 00 00

.cpu T_32_M32
.str "123" ; -> 00 00 00 31 00 00 00 32 00 00 00 33
Um, this is just for illustration, as HXA does not actually permit cpu re-definition during a single assembly.

It is an arguable point that because "character" values are always "bytes", any custom extraction order that is applied to "BIT16" for 16-bit "bytes" (or "BIT32" for 32-bit "bytes") should also apply to character "bytes". For the time being HXA does not do that, however.

Because the 65Org16 wants to see character octets in "00 char" rather than "char 00" order, the better definition to use is after all:

Code: Select all

.cpu T_32_M16
.assume BIT32=1032, BIT32R=3210
I should note that this works only for the HXA_T variant at present, although eventually, once either an instruction set is finalized or I happen to feel like it, something very much like this will happen "behind the scenes" when HXA65 is extended to support the 65Org16.

Hope this helps anyone who's confused about this!
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Post by ElEctric_EyE »

Hi Bitwise,
I think I may have have witnessed another bug involving DEC/INC $xxxxxxxx (opcodes $CE/$EE respectively). It is being translated to DEC/INC $xxxx (opcode $C6/$E6).
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Post by BitWise »

ElEctric_EyE wrote:
Hi Bitwise,
I think I may have have witnessed another bug involving DEC/INC $xxxxxxxx (opcodes $CE/$EE respectively). It is being translated to DEC/INC $xxxx (opcode $C6/$E6).
Found and fixed over the weekend. I'll build an updated ZIP tonight.
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
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Post by BitWise »

BitWise wrote:
ElEctric_EyE wrote:
Hi Bitwise,
I think I may have have witnessed another bug involving DEC/INC $xxxxxxxx (opcodes $CE/$EE respectively). It is being translated to DEC/INC $xxxx (opcode $C6/$E6).
Found and fixed over the weekend. I'll build an updated ZIP tonight.
Ok. Now generates this

Code: Select all

FFFFF000  00BD8000FFFF      :                 LDA $FFFF8000,X
FFFFF003  00BD8000FFFF      :                 LDA !$FFFF8000,X
FFFFF006  00BD8000FFFF      :                 LDA |$FFFF8000,X
                              
FFFFF009  00B58000          :                 LDA $00008000,X
FFFFF00B  00BD80000000      :                 LDA !$00008000,X
FFFFF00E  00BD80000000      :                 LDA |$00008000,X
                              
FFFFF011  00EE8000FFFF      :                 INC $FFFF8000
FFFFF014  00EE8000FFFF      :                 INC !$FFFF8000
FFFFF017  00EE8000FFFF      :                 INC |$FFFF8000
                                                              
FFFFF01A  00E68000          :                 INC $00008000
FFFFF01C  00EE80000000      :                 INC !$00008000
FFFFF01F  00EE80000000      :                 INC |$00008000
New ZIP at http://www.obelisk.demon.co.uk/files/65016.zip
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
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Post by ElEctric_EyE »

Thanks again Bitwise!
What is actually involved in making these 'minor' adjustments to your JAVA creation? Could a layman like myself do them?
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Post by BitWise »

If you can program in Java then the code is quite easy to fix. For example here a link to the patch for the last bug fix

http://dev65.svn.sourceforge.net/viewvc ... pathrev=16

You'd need a Subversion client, a copy of the Eclipse IDE with the 'Subclipse' plug in installed, a sourceforge account and access permission to commit changes back to repository -- All these are free downloads and registrations + me granting you repository access.
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
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Post by ElEctric_EyE »

Not so easy, heh...

Are you sure that's the update? I'm getting all zero page opcodes again, even LDA$xxxxxxxx which was fixed before... I'll try the ! expression.
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Post by BitWise »

ElEctric_EyE wrote:
Not so easy, heh...

Are you sure that's the update? I'm getting all zero page opcodes again, even LDA$xxxxxxxx which was fixed before... I'll try the ! expression.
Curious. I get

Code: Select all

FFFFF000  00BD8000FFFF      :                 LDA $FFFF8000,X
FFFFF003  00BD8000FFFF      :                 LDA !$FFFF8000,X
FFFFF006  00BD8000FFFF      :                 LDA |$FFFF8000,X
                              
FFFFF009  00B58000          :                 LDA $00008000,X
FFFFF00B  00BD80000000      :                 LDA !$00008000,X
FFFFF00E  00BD80000000      :                 LDA |$00008000,X
                              
FFFFF011  00EE8000FFFF      :                 INC $FFFF8000
FFFFF014  00EE8000FFFF      :                 INC !$FFFF8000
FFFFF017  00EE8000FFFF      :                 INC |$FFFF8000
                                                              
FFFFF01A  00E68000          :                 INC $00008000
FFFFF01C  00EE80000000      :                 INC !$00008000
FFFFF01F  00EE80000000      :                 INC |$00008000
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
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Post by ElEctric_EyE »

It works. I forgot it optimizes $00000001 to $0001...

Some more observations as I am testing more opcodes on my .b core:

1) STA $xxxx,Y ($0091) is observed as STA $xxxxxxxx,Y ($0099). In fact, all odd opcodes in column 1 have this problem, i.e. ($0011,$0031,$0051,$0071... observed as $0019,$0039,$0059,$0079, etc.)

Thanks for your continued support!
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Post by BitWise »

ElEctric_EyE wrote:
It works. I forgot it optimizes $00000001 to $0001...

Some more observations as I am testing more opcodes on my .b core:

1) STA $xxxx,Y ($0091) is observed as STA $xxxxxxxx,Y ($0099). In fact, all odd opcodes in column 1 have this problem, i.e. ($0011,$0031,$0051,$0071... observed as $0019,$0039,$0059,$0079, etc.)

Thanks for your continued support!
In the WDC datasheet $91 is STA (zp),Y. Only LDX and STX have a zp,Y addressing mode so the assembler uses the abs,Y instruction where zp,Y isn't available.

Code: Select all

FFFFF02B  009980000000      :                 STA $00008000,Y
FFFFF02E  009980000000      :                 STA !$00008000,Y
FFFFF031  009980000000      :                 STA |$00008000,Y
FFFFF034  00910001          :                 STA ($0001),Y
FFFFF036  00110001          :                 ORA ($0001),Y
FFFFF038  00B61234          :                 LDX $1234,Y
FFFFF03A  00961234          :                 STX $1234,Y
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
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Post by ElEctric_EyE »

DOH, I knew that. Indirect Indexed. :oops:
Still it is an interesting feature of your assembler. Thanks, I think As65 is bug free now!
ElEctric_EyE
Posts: 3260
Joined: 02 Mar 2009
Location: OH, USA

Re: 65Org16 Assembler (16-bit bytes, 32-bit address space)

Post by ElEctric_EyE »

In As65, I am using simple macro's like for instance:

Code: Select all

LDBi              .MACRO          ;LDB #$xxxx
                  .BYTE $01A9
                  .ENDM
And so when I write the assembly I have to do this:

Code: Select all

LDBi
.BYTE $00FF
What is the syntax of the macro have to look like to have the assembly abit more agreeable to the eyes?

Code: Select all

LDBi, $00FF
or

Code: Select all

LDBi $00FF
or something along these lines.

Ideally, it would look like

Code: Select all

LDBi #$00FF
Is this possible?
User avatar
GARTHWILSON
Forum Moderator
Posts: 8773
Joined: 30 Aug 2002
Location: Southern California
Contact:

Re: 65Org16 Assembler (16-bit bytes, 32-bit address space)

Post by GARTHWILSON »

In that case, with the three commercial assemblers I've worked with, you would put the name of a macro variable in the macro definition line:

Code: Select all

LDBi:  .MACRO  param
       .BYTE   $1A9, param
       .ENDM
 ;---------------------
Something I liked about the 2500AD assembler is that you could have any number of parameters, and have, in essence, "If there is a fourth parameter, do this; if there is a fifth one, do that," etc..

For different address modes, you would probably have to use another parameter to tell it which addressing mode you want, or put it in the mnemonic, which is what I did in my super-simple Forth assembler, so it takes for example, LDA# or LDA_ZP or LDA_ZP,X etc.. Not being familiar with As65 though, I suspect the range of characters it lets you put in a label (as for macro names) is more limited.
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?
Post Reply