Background
I'm currently embroiled in a project to understand the inner workings of some 68HC16 based embedded system. If you feel like asking 'y tho?' right now the answer is: because its there and because I want to, and because I can. I've also been interested in the Ghidra project since I heard about it a few years ago.
Source materials
Most of the documentation around the processor is still available from NXP, who after mergers and sales and other corporate shenanigans, came to own Motorola's IP. Most of my source materials for this part of the project is available here and here for the specific processor I'm interested in.
HC16 support: (╯°□°)╯︵ ┻━┻
Seems like Ghidra already supports a few other variants of the 68xx series (6809, 68HC12) and of course supports a whole ton of the 68K, but there doesn't seem to be a high level of overlap between the instruction sets and that of the 68HC16. I've already randomly tied to disassemble the binary using whatever seemed to fit and after reviewing the instruction sets, they don't seem very close.
DIY time
After a bit of googling and some reading it seems like getting Ghidra to do most of the heavy lifting here is not an impossible task. The nicest introduction I could find to doing this was over at spinsel.dev. The examples in that series use brainfuck, which is a language that I haven't looked at in way more than 10 years, but its simplicity lends itself nicely to the examples. I'd suggest picking through the first 2 posts there to get a feel for things.
Failed attempts at leveraging 68HC12
So I initially thought that the 68HC12 instruction set might be a good starting point for this. Turns out that they're rather different. I know after spending some time with the datasheets that there's many, many more differences than what I'm about to layout below, but I stopped here.
y not?
To see why this wasn't a workable path, let's look at the same instruction between the 2 sets. This data is taken from the pdfs linked above. The HC12 instruction came from p106 in this doc. And the HC16 one came from p338 in this doc.
Note: I've taken some liberties with the layout of the instructions below to try and make them more similar. Hopefully I didn't fuck anything up too badly, but I'll revise this later if I did.
HC12 ADCA instruction
Add with carry to A; (A)+(M)+C⇒A or (A)+imm+C⇒A
instruction + args | mode | opcode and operand |
---|---|---|
ADCA #opr8i | IMM | 89 ii |
ADCA opr8a | DIR | 99 dd |
ADCA opr16a | EXT | B9 hh ll |
ADCA oprx0_xysppc | IDX | A9 xb |
ADCA oprx9,xysppc | IDX1 | A9 xb ff |
ADCA oprx16,xysppc | IDX2 | A9 xb ee ff |
ADCA [D,xysppc] | [D,IDX] | A9 xb |
ADCA [oprx16,xysppc] | [IDX2] | A9 xb ee ff |
HC16 ADCA instruction
ADCA Add with Carry to A (A) + (M) + C ⇒ A
instruction + args | mode | opcode and operand |
---|---|---|
ADCA opr8a | IND8, X | 43 ff |
ADCA opr8a | IND8, Y | 53 ff |
ADCA opr8a | IND8, Z | 63 ff |
ADCA #opr8i | IMM8 | 73 ii |
ADCA opr16a | IND16, X | 1743 gggg |
ADCA opr16a | IND16, Y | 1753 gggg |
ADCA opr16a | IND16, Z | 1763 gggg |
ADCA #opr16i | EXT | 1773 hh ll |
ADCA [E,X] | [E, X] | 2743 - |
ADCA [E,Y] | [E, Y] | 2753 - |
ADCA [E,Z] | [E, Z] | 2763 - |
it's more than just the opcodes :(
The most painful difference here, and the one that kills any hope of using the Ghidra definition from HC12 as a quick path to victory for HC16 is that the index information in xb
is used to figure out what index mode and how much more data comes after this opcode. If you read the HC12 doc, you'll see the tables for how to decode xb
. The HC16 has much more regular opcodes for this instruction and most of the others I looked closely at. It seems like the instructions staring with [1,3]7
all will have 16 bits of data following them, whether it's immediate data or an offset to an index register.