Thanks for your detailed response! I'll try to respond to each point. Some I think you've probably already self-determined, based on your follow-up informational links.
Maël wrote: 08 Nov 2020 00:43
From what I can tell, it works without troubles in HxD

Great!
Well, that's a good start!
Maël wrote: 08 Nov 2020 00:43- Numbers are sometimes shown in decimal with no prefix, sometimes in hexadecimal with a $ prefix, sometimes with a #$ prefix (e.g., for 6800: SUBA #$FF).
I assume the last notation is for immediate values. But what is the logic behind using decimal vs. hexadecimal (e.g., BHI 33)? If it is because of signed numbers: at least in x86, you can also have signed hexadecimals. Edit: One of the PDFs below (page 8 ) has an example "LDA –$21c0,PCR" that shows signed hexadecimals are used for 6809 assembly, too.
Yes, as you've noted, the
# prefix is used in Motorola 6800 Assembly to indicate
Immediate mode addressing.
ie. the following value is the
literal value that is being operated on.
Currently, the decimal vs hexadecimal rendering of the argument value is specified (per opcode definition), in the .CSV defintion file. This is the
ArgumentHexDec column.
So, you can choose your own preference of H|D in your own .CSV file.
The logic I used (for the 6800 defnition file) was to use decimal notation for the relative addressing instructions (Branch instructions), where you'd typically be counting in your head to get to the target address.
So, for
you would "Branch if HIgher" to the address of the next instruction plus 33 (decimal).
For all other instructions I just specified the default Hexadecimal rendering. You can set your .CSV file to whichever you prefer.
Rendering signed Hexadecimal values is a good point, which I hadn't implemented (yet). Currently, for Hexadecimal rendering I just render the raw Hex byte value (I guess old-school me just automatically sees -1 when I see $FF).
The
ArgumentSignedUnsigned value is (currently) utilised in determining if an argument value needs to be sign-extended into a normalised 1, 2, 4, or 8 byte value.
nb. This sign-extend requirement is not actually needed for 6800, as it only utilises byte-aligned 8-bit or 16-bit arguments. However, the 6809 is an example where there are also 5-bit signed arguments, which must therefore be sign-extended into a full byte for ease of rendering.
Maël wrote: 08 Nov 2020 00:43
I thought that maybe in future, you would be able to choose in HxD if you want to have decimal or hexadecimal numbers displayed within assembly, with the checkbox that already exists under the datainspector grid.
Yes, that would indeed be a nicer solution. If the hexadecimal checkbox property could be made available to the Datainspector Plugin, I could then use the checkbox selection to determine Hex or Dec treatment.
I note you'd also want to tweak the checkbox label to be more appropriately descriptive (assuming single checkbox). Currently it specifically refers to: "Show Integers...".
Maël wrote: 08 Nov 2020 00:43- Every mnemonic is in upper case. I see this is common for 6800/6900 assembly (and was so also for x86 assembly for a long time). Personally, I think lowercase is easier on the eyes, though, and it would fit better with the other datatype converters.
Understood. This is determined literally, from the .CSV definition file DasmString. You could easily just convert the .CSV file to lowercase and you'd be good to go.

My choice in the supplied 6800 definition file was to use Uppercase, based on retro 6800 Assembly code traditionally being viewed / published using Uppercase.
In addition, an uppercase/lowercase preference would also ideally be desired for the rendered Hexadecimal values. I note HxD has an option to specify "Hexadecimal numbers capitalization". Therefore, to consistently support this, the Datainspector Plugin would need to also have visibility of this global format setting.
Maël wrote: 08 Nov 2020 00:43- DefinitionLogPath=C:\Temp
While that path may sometimes exist, usually the temp path is a per-user path under Windows. I think the environment variable %TEMP% points to it. Would require parsing for environment variables, and replace them with what the WinAPI GetEnvironmentVariable returns. Or you could just hardcode to use the user's temp directory always: WinAPI GetTempPath
Probably better to do this explicitly, than to rely on Windows to redirect writes aimed at C:\Temp for non-admin users.
Yes, I understand
GetEnvironmentVariable etc. However, my thinking was that the user would want to point the log path to where they wanted the logs to go. This is also on the basis that logging is intended only for temporary .CSV file debugging use (as it also adds, not insignificant, loading overhead).
I just happened to use C:\Temp, so I'd left that in as an example, noting that Logging itself is disabled by default in the supplied .INI (
DefinitionLogEnable=0). Therefore, you would need to edit the .INI if you wanted to turn on the logging output (at which time you'd configure where you wanted it to go).
I don't think it would be appropriate to hard-wire log creation to the system %TEMP% path. Perhaps also not really necessary to support using environment variables embedded in the INI value?
Maël wrote: 08 Nov 2020 00:43- OperandArgumentMask in .csv file - I think this column could use some documentation. I figured it out by switching back and forth between the 6800 link below and your list, seeing that essentially, the mask is always set to exactly cover the operand bytes. The opcode seems to be a single byte always as well, no mixing of bits in the opcode and operand bytes, like for x86 machine code.
In other words: what effect does the mask have, besides ignoring some of the bits of the operand bytes given by OperandBytes? Are they just ignored or used somewhere else?
I agree that for the simple 6800 case, the
OperandArgumentMask use is not that obvious, given that the full Operand is
always the full Argument (in the simple 6800 instruction set).
I guess I'd also fallen into the trap of just assuming everyone knows what a binary bit Mask is. I'll blame that on my old-school background!
Understanding a mask also requires understanding binary logic, specifically the effect of bitwise AND.
So, wherever a Mask bit is set to 1 it preserves the AND'd Operand's bit value, and where a Mask bit is set to 0, the Operand's bit value is purged (masked), to always returned a 0.
For example, if you have the Byte $65 and you apply a Mask of $1F, you will end up with $05.
In binary: %01100101 ($65) & %00011111 ($1F) -> %00000101 ($05)
(nb. % is Motorola convention for binary number notation)
The
OperandArgumentMask value is actually used both for extracting the Argument, and also identifying the rest of the Operand that makes up the balance of the full instruction (ie. as an extension to / in combination with, the Opcode).
So, with the above example, the $1F mask can also be inverted, giving %11100000 ($E0), and used as the Mask to extract the remaining Opcode portion of the Operand bytes (ie. $60) that is required to fully match the Instruction byte sequence.
In binary: %01100101 ($65) & %11100000 ($E0) -> %01100000 ($60)
Perhaps the best real-world example is one of the 6809 Indexed Addressing mode instructions, which provides for a smaller 5-bit signed offset argument.
eg. This definition:
This is a 3 byte instruction, with a fixed 2 byte Opcode (10AE), followed by a single Operand byte which in binary form is represented as: 0RRnnnnn.
In this case the most significant bit (0) is zero, the next 2 bits (RR) specify the source addressing Register, in this case 11 for the 'S' Stack register, then the 5 remaining bits (nnnnn) specify the signed 5-bit offset argument.
So using the above example of $65 as the Operand, we would have a HxD Byte sequence: 10AE65
The inverted
OperandArgumentMask ($1F -> $E0) would allow us to match the 3 byte Instruction definition of "10AE,60" (Opcode + Operand), and the defined
OperandArgumentMask ($1F) would allow us to extract the 5-bit Argument as $05.
So we would have Assembly string:
Note also, as a Signed Argument, this would be sign-extended to a full single Byte (for rendering the value), which in this case gives us +5.
If however the byte stream was: 10AE7F, then $7F (%01111111) would similarly match the Masked "10AE,60" Opcode + Operand, with the extracted 5-bit Argument being $1F.
As a Signed value this would be sign-extended to a full byte as $FF, or in Decimal -1.
So in this case we would have Assembly string:
Or (based on your earlier signed Hexadecimal observation), this should probably be rendered as:
Hopefully all the above helped clarify:
a. The
OperandArgumentMask usage.
b. That the
OpcodeBytes +
OperandBytes define the length of the instruction.
c. The
OperandBytes value just needs to contain the required bits to Identify the full instruction.
d. The bits of the
OperandBytes that represent the actual Argument are irrelevant / can just be left as 0's (as the value of the Instruction Argument can obviously vary).
Maël wrote: 08 Nov 2020 00:43- OpcodeBytes,OperandBytes are apparently used to identify an instruction, and the OperandArgumentMask, which is why you set OperandBytes to 00 for those that have operands, but for which they do not help in identificating the instruction, just such that OperandArgumentMask can work?
Not entirely sure here.
Yes. In the simple 6800 full 8-bit argument, the 00 as
OperandBytes simply fulfil the purpose of identifying the full instruction length.
I think the full intention is best described by my above example and observation that the specified
OpcodeBytes +
OperandBytes define the length of that particular instruction.
The other option would have been to add another CSV field to specifically state each individual Instruction's length, however as this can be implied by the
OpcodeBytes +
OperandBytes fields, this added field would either be redundant, or, would require the dangerous assumption that a larger Instruction length (than what the specified
OpcodeBytes +
OperandBytes indicated) would require zero padding.
Maël wrote: 08 Nov 2020 00:43- 10AE,84,00,,,"LDY ,X" I suppose some entries are not complete, since there is no ? wildcard here.
No, this entry is complete.
This particular instruction has no Argument, hence there is no
OperandArgumentMask needed (so the Mask is just set to 00). Technically, the
OperandArgumentMask field could have also been empty (ie. not specified).
eg.
would also work.
This 6809 instruction is effectively to Load the Y index register from the X register, with no offset! (+0)
The Assembly for which is simply:
Hopefully all the above has help clarify my intentions. You are correct that I do somehow need to roll this into some expanded documentation. Perhaps as above... that's if all the above actually made any sense?
Thanks also for the various links, which I shall be sure to read through. Most of that 6800 / 6809 information I do already have in the form of all my original Motorola Data books, Application books, Reference cards, and Data sheets!
In summary, I think we arrived at the following to-do's / wish list items:
- I should implement -ve rendering of Signed Hexadecimal values, instead of my current old-school assumption that everyone knows $FF is -1
- A future HxD datainspector plugin enhancement to allow 3rd party code visibility of the Hexadecimal / Decimal format checkbox would then allow me to automate (and make dynamic) the current function of the fixed ArgumentHexDec .CSV field.
- A future HxD datainspector plugin enhancement to allow 3rd party code visibility of the "Hexadecimal numbers capitalization" format option, would allow me to follow the HxD global setting for Hexadecimal rendering Uppercase/lowercase preference.