Closed sigurasg closed 3 months ago
Hey there! I'm interested in this as well: I'm trying to reverse engineer an 80s pinball machine running on a MC6803 (which is just a MC6801 with only mode 2 and 3 available since it has no functional internal ROM). Your plugin gets me most of the way there already (nice!), but it bails out when it encounters some of the new instructions that were added with the MC6801.
I'm happy to assist any way I can (either by helping adding the missing instructions or simply testing things once they are added) - though I should note I'm very much a beginner when it comes to Ghidra so I may need some hand-holding to get started 😅
I'm happy to assist any way I can (either by helping adding the missing instructions or simply testing things once they are added) - though I should note I'm very much a beginner when it comes to Ghidra so I may need some hand-holding to get started 😅
My best effort at MC6801 support is already on the main branch, but I haven't cut a release with it yet. Let me do that right now, but then I'd be very interested to hear how the language spec works for you.
My best effort at MC6801 support is already on the main branch, but I haven't cut a release with it yet. Let me do that right now, but then I'd be very interested to hear how the language spec works for you.
There you go: https://github.com/sigurasg/GhidraTek2465/releases/tag/v0.4-rc1
That works surprisingly well so far! No errors anymore, at least 🥳 Thanks so much; I'm going to dig into the ROMs I'm analysing some more with this and will let you know any feedback I have after. 👍
That works surprisingly well so far! No errors anymore, at least 🥳
Awesome, glad it's working for you. LMK how it goes, good, bad or indifferent? I'm thinking I should probably break the language specs out to a separate extension, as the Tek-specific plugin is no use to anyone but a couple of nerds (tops).
I understand the 6803 has some built-in peripherals. Would be reasonable to add their addresses to the language spec?
Sample size one here of course (just me is hardly representative of all potential users); but that was indeed the very first thing I did after opening up the ROM I was analyzing: label all the addresses that the hardware has assigned special meaning to. So, yes, I think that would not only be reasonable but a very welcome addition.
Here's a snippet from the MC6801 datasheet:
That entire first 0x20
bytes is always assigned to these functions - though 0x04-0x07
and 0x0F
may not be available depending on the mode the chip is in (they should be unused in those cases, so labeling them as such anyway should be harmless).
Another snippet: You already have the reset vector (not on this table) and some of the other vectors listed on this table, but the rest is missing (are they perhaps not present on the MC6800 that this was based on? I don't know 🙃). Those would make sense to add as well, I think.
That entire first
0x20
bytes is always assigned to these functions - though0x04-0x07
and0x0F
may not be available depending on the mode the chip is in (they should be unused in those cases, so labeling them as such anyway should be harmless).
Nice, thanks. Tagging the interrupt vectors is easy, but does there exist a set of mnemonics used to name the registers?
Probably... but I couldn't find that information on the datasheet and more documentation for this old thing is quite hard to find. 🙃
Probably... but I couldn't find that information on the datasheet and more documentation for this old thing is quite hard to find. 🙃
Looks like the Reference Manual might have at least some registers named?
Oooh, useful!
I was able to find the following:
P1DDR
(0x00
)
P2DDR
(0x01
)
P1DATA
(0x02
)
P2DATA
(0x03
)
P3DDR
(0x04
)
P4DDR
(0x05
)
P3DATA
(0x06
)
P4DATA
(0x07
)
TCSR
(0x08
)
TIMER
(0x09-0x0A
)
OUTCMP
(0x0B-0x0C
)
IMPCAP
(0x0D-0x0E
)
P3SCR
(0x0F
)
RMCR
(0x10
)
TRCS
(0x11
)
RX
(0x12
)
TX
(0x13
)
... which leaves only "RAM Control Register" as unknown. I'd personally use RAMCR
, but I can't find an "official" mnemonic for it.
... which leaves only "RAM Control Register" as unknown. I'd personally use
RAMCR
, but I can't find an "official" mnemonic for it.
Sweet, thanks!
How does this look to you? Maybe I can add you as a collaborator and send you review requests?
I don't suppose you can point me to a ROM image I can load to test against?
This is the ROM I'm currently trying to decompile: https://transfer.ddvtech.com/6unN26Jh1f/cpu_u2.128 https://transfer.ddvtech.com/2acqdXsq2c/cpu_u3.128 These are two 16K EEPROMs; U2 is supposed to be loaded at 0x8000 and U3 at 0xC000. This particular ROM also expects 2K of (external) volatile RAM at 0x1000, but you should be able to load it without configuring that. The machine this is used in also has two PIAs, connected at addresses 0x20 and 0x40 (each 4 bytes long), so don't be surprised if you see reads/writes there too.
I'll take a look at the new PR later tonight 👀
This is the ROM I'm currently trying to decompile:
...
Thanks! I loaded them up and I see the new vectors and register names populate. Auto analysis doesn't start until I typed and manually disassembled the vectors in the vector table. Still, I think the PR works as intended?
Oh, also very cool to see e.g. PSHX/PULX in action, I was ... unimpressed ... with the MC6800 in some respects: https://sigurasg.github.io/reversing-the-2465/2024/06/18/mc6800-limitations.html. The 6801 fixes these problems and more with only a handful of extra instructions.
Yeah the PR looks good - interestingly, it did automatically start analyzing the vector addresses for me. 🤔
https://github.com/sigurasg/GhidraTek2465/pull/14 implements most/all MC6801/6803 instructions, vectors and internal registers.
I apologize for the lack of communication. I have been incredibly busy lately and havent had time to do anything fun.
I merely added all extra instruction support to my code, I only have a single interrupt vector (besides reset, and I dont have either added in any way), and there are also no peripherals on the processor I am working with because it is all redundant. It has to be able to run the car without the processor :)
I also understand why X wasnt used the way it was on the 6801 on the 6800. It seems like a minor oversight but the push/pull functionality is there through swi, right? lol. In my case X is only used for constants and table base addresses, so sans cpx this code doesnt benefit from being able to manually push x.
Also on your limitations list I dont understand why you think X isnt preserved through interrupts? According to the processor manual it is?
Page 18, "Saving MPU Status"
Am I misunderstanding what you mean?
I apologize for the lack of communication. I have been incredibly busy lately and havent had time to do anything fun.
No worries. If at some point you have time, the latest release of the plugin should cover the MC6801 and I'd love to know if it works for you.
Also on your limitations list I dont understand why you think X isnt preserved through interrupts? According to the processor manual it is?
It's preserved through interrupts, so that's all fine. The problem is that regular code has no good way to save it on stack nor restore it, which makes it pretty much impossible to use it reentrantly.
I'd understand if the example were a routine that called itself but I don't understand why it seems to imply that x would be lost due to an interrupt. something must be going over my head here. I can't think of a situation where x would be lost, save for if an interrupt occurred at the branch and called that same routine again at which point i don't see how it's related to x and instead just a race condition irrespective to the ability for x to be pushed/pulled. I don't see the alternative if X could be pushed unless you're going to push it to the stack and then manipulate it on there? (pshx tsx addb stab bcc inc txs pulx?)
not trying to nitpick or anything im just trying to understand. you'll have to realize they only ever used about three bytes of stack on my getup, and that's a stretch at that :)
I will give it a shot at some point. I'm fairly unfamiliar with ghidra, are the peripherals optional? ram is 0-ff for me with io and whatnot spread around at 400 800 c00 1000 3000 e000 and f000
On Fri, Aug 16, 2024, 15:00 Sigurður Ásgeirsson @.***> wrote:
I apologize for the lack of communication. I have been incredibly busy lately and havent had time to do anything fun.
No worries. If at some point you have time, the latest release of the plugin should cover the MC6801 and I'd love to know if it works for you.
Also on your limitations list I dont understand why you think X isnt preserved through interrupts? According to the processor manual it is?
It's preserved through interrupts, so that's all fine. The problem is that regular code has no good way to save it on stack nor restore it, which makes it pretty much impossible to use it reentrantly.
— Reply to this email directly, view it on GitHub https://github.com/sigurasg/GhidraTek2465/issues/10#issuecomment-2294008708, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABF2HAN33KBX3LS3GNLCJATZRZD3TAVCNFSM6AAAAABKPJLPS2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOJUGAYDQNZQHA . You are receiving this because you were mentioned.Message ID: @.***>
I'd understand if the example were a routine that called itself but I don't understand why it seems to imply that x would be lost due to an interrupt. something must be going over my head here. I can't think of a situation where x would be lost, save for if an interrupt occurred at the branch and called that same routine again at which point i don't see how it's related to x and instead just a race condition irrespective to the ability for x to be pushed/pulled.
The problem is that it's impossible to write reentrant code that uses X. Consider this function from the 2465 ROMs:
word ADD_X_B(word x, byte b)
word X:2 <RETURN>
word X:2 x
byte B:1 b
ADD_X_B
TPA ; Save SR in A
SEI ; Disable interrupts
STX TMP_X ; Store X in a temporary
ADDB TMP_X+1 ; Add B to LSB of temporary.
STAB TMP_X+1 ; Store LSB sum to the temporary.
BCC NO_CARRY
INC TMP_X ; Increment MSB of temporary
; on carry.
NO_CARRY
LDX TMP_X ; Load sum.
TAP ; Restore SR (possibly
; re-enabling interrupts)
RTS
Because there's no way to store X to stack, this uses a global to store and manipulate the sum. It then has to disable interrupts to protect the global from reentrant use by an interrupt, but even then it can't be protected from NMI. The MC6801 solves this by (aside from providing ABX as an instruction) with e.g. PSHX/PULX, allowing the use of stack instead of forcing the use of globals.
I don't see the alternative if X could be pushed unless you're going to push it to the stack and then manipulate it on there? (pshx tsx addb stab bcc inc txs pulx?) not trying to nitpick or anything im just trying to understand.
Yup, that'd be reentrant code that doesn't risk the temporary global getting stomped on reentrancy.
you'll have to realize they only ever used about three bytes of stack on my getup, and that's a stretch at that :) I will give it a shot at some point. I'm fairly unfamiliar with ghidra, are the peripherals optional? ram is 0-ff for me with io and whatnot spread around at 400 800 c00 1000 3000 e000 and f000
The pheripherals, as-is, are not optional, but they simply add a set of labels and a block to the memory map. My understanding of the 6801 is that 0x0000-0x0020 is always used by these pheripherals, irrespective which mode the chip runs in. Are you working with another variant of the chip?
Ok makes sense then. At first glance I had taken it as the interrupt being the problem instead of the global(or at least static local) use.
Yes this is some unknown variant that GM had specifically made. They supposedly funded the 6801 added instructions in exchange for getting the first however many loads of them for however many years (I think they had them two years early?).
No onboard peripherals, always non multiplexed bus, processor always master, no internal ram, no internal rom, single phase clock, one interrupt, hardware division unit (kidding), etc. The car is completely able to run without the processor :)
On Sat, Aug 17, 2024, 07:40 Sigurður Ásgeirsson @.***> wrote:
I'd understand if the example were a routine that called itself but I don't understand why it seems to imply that x would be lost due to an interrupt. something must be going over my head here. I can't think of a situation where x would be lost, save for if an interrupt occurred at the branch and called that same routine again at which point i don't see how it's related to x and instead just a race condition irrespective to the ability for x to be pushed/pulled.
The problem is that it's impossible to write reentrant code that uses X. Consider this function from the 2465 ROMs:
word ADD_X_B(word x, byte b) word X:2 <RETURN> word X:2 x byte B:1 b ADD_X_B TPA ; Save SR in A SEI ; Disable interrupts STX TMP_X ; Store X in a temporary ADDB TMP_X+1 ; Add B to LSB of temporary. STAB TMP_X+1 ; Store LSB sum to the temporary. BCC NO_CARRY INC TMP_X ; Increment MSB of temporary ; on carry. NO_CARRY LDX TMP_X ; Load sum. TAP ; Restore SR (possibly ; re-enabling interrupts) RTS
Because there's no way to store X to stack, this uses a global to store and manipulate the sum. It then has to disable interrupts to protect the global from reentrant use by an interrupt, but even then it can't be protected from NMI. The MC6801 solves this by (aside from providing ABX as an instruction) with e.g. PSHX/PULX, allowing the use of stack instead of forcing the use of globals.
I don't see the alternative if X could be pushed unless you're going to push it to the stack and then manipulate it on there? (pshx tsx addb stab bcc inc txs pulx?) not trying to nitpick or anything im just trying to understand.
Yup, that'd be reentrant code that doesn't risk the temporary global getting stomped on reentrancy.
you'll have to realize they only ever used about three bytes of stack on my getup, and that's a stretch at that :) I will give it a shot at some point. I'm fairly unfamiliar with ghidra, are the peripherals optional? ram is 0-ff for me with io and whatnot spread around at 400 800 c00 1000 3000 e000 and f000
The pheripherals, as-is, are not optional, but they simply add a set of labels and a block to the memory map. My understanding of the 6801 is that 0x0000-0x0020 is always used by these pheripherals, irrespective which mode the chip runs in. Are you working with another variant of the chip?
— Reply to this email directly, view it on GitHub https://github.com/sigurasg/GhidraTek2465/issues/10#issuecomment-2294834774, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABF2HALBE3DBCZGZLSFMPGTZR4ZBPAVCNFSM6AAAAABKPJLPS2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOJUHAZTINZXGQ . You are receiving this because you were mentioned.Message ID: @.***>
Yes this is some unknown variant that GM had specifically made. They supposedly funded the 6801 added instructions in exchange for getting the first however many loads of them for however many years (I think they had them two years early?).
Wow, that's pretty cool. Given a part number, it would be trivial to add another pspec file for it... I dunnot that this is warranted, though I'd gladly take the PR ;).
Yes this is some unknown variant that GM had specifically made.
There's a quick mention of this in the Wikipedia article.
Is SC44125 the part number you're working with?
nada, sorry. meant to respond but got tied up. no part numbers on these chips, they're privately labeled Delco parts
On Mon, Aug 19, 2024, 12:53 Sigurður Ásgeirsson @.***> wrote:
Yes this is some unknown variant that GM had specifically made.
There's a quick mention of this in the Wikipedia article https://en.wikipedia.org/wiki/Motorola_6800#:~:text=It%20was%20initially%20designed%20for%20automotive%20use%2C%20with%20General%20Motors%20as%20the%20lead%20customer .
Is SC44125 https://www.cpu-world.com/forum/viewtopic.php?t=34397 the part number you're working with?
— Reply to this email directly, view it on GitHub https://github.com/sigurasg/GhidraTek2465/issues/10#issuecomment-2297015022, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABF2HAN2GXQB7WUDPXG2WGLZSIPI3AVCNFSM6AAAAABKPJLPS2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEOJXGAYTKMBSGI . You are receiving this because you were mentioned.Message ID: @.***>
Sorry I dont have a better picture on hand and dont really wanna go out to my car currently haha. This is it in my board I made for my car.
Just to reiterate. No internal rom, no internal ram, no dual phase clock, no bus configuration, always non multiplexed, no ports, no timers, no nothing. It literally just executes bytes with zero other functionality.
On the actual board for it, there are privately labeled custom peripherals, such as a timer unit that has more (and more configurable?) channels than any consumer released standard part, as well as having a few io/flag pins. Both capture and output modes, single shot, repeating, etc. Im sure some sort of edge detection goes into the configuration bits for it but I never probed it further than making it turn a couple leds on and off. Theres also two chips that seem to each contain 4k of rom, 128 bytes of ram(which is NV because of having idle power pins), and 4/4 in/out ports, and then lastly theres a 4k 2732 style eprom (used for individual vehicle configuration features/tuning)
edit*
Just saw there was a page 2 on that forum you linked. I see that at the end they claim that it "is" the part, but I would beg to differ.
"It contained a 128-byte RAM, 2-Kbyte ROM, sophisticated 16-bit timer (a la automotive), 4-MHz on-chip clock oscillator, programmable digital I/O, serial port and, of course, the CPU."
This just simply isnt true for this part. I dont know the first year that this computer was made, but the internet seems to say this "style" of the computer started around 81
It seems straightforward to add MC6801 support. The main question is how to structure the code. Perhaps pulling the bulk of the MC6800 into an include file with an ifdef for CPX, include it into both .slaspecs is the best way to go?
There's also the question of how to treat the embedded pheripherals, and/or other members of the MPU family.
@jombo23 how did you structure this in your code? Do you have anything you're comfortable sharing?