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:
.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:
.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:
.byte $ABCD ; one byte
.word $ABCD ; two bytes, native order
.revword $ABCD ; two bytes, reverse native order
produces
Code:
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:
.cpu T_32_L16
.assume BIT16=10, BIT32=1032
.byte $ABCD
.word $ABCD
.revword $ABCD
produces:
Code:
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:
.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:
.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:
.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!