It was time to download and fire up Ghidra, and run it on PVTEST_ to get to know what the code is like. I ran it in 68000 mode.
There were some oddities with the disassembly. And a crucial piece of information was missing: I didn't know at what memory location the code was loaded, the origin of the assembly file (I had a pretty good guess of where the file header ended and where the code began--there was a JMP instruction that looked like a start). Looking at the disassembly, I had an idea. The code accessed various data addresses via instructions like
movea.l #0x9aa84c,A0and
pea (0x9a5939).lI noticed that often these addresses were pretty much in order. Which makes sense, in that in earlier pieces of code you tend to access earlier data. There was a good chance that these referred to data in the program itself. I had a clever (I think) idea that I would look at sequences of human-readable null-delimited ASCII strings, of which there were many, and look for code in the disassembly that accessed memory locations whose spacing equalled the size of these strings. With the help of dumping what looked like the right instructions from the Ghidra disassembly I eventually found some instructions and corresponding strings that seemed to match. This would let me know what memory address the strings were loaded at, and hence I could calculate the address the whole code got loaded at.
Except it didn't quite work.
Moreover, there were some weird things. Occasionally text strings were interrupted by a short piece of junk. And occasionally disassembly would break down weirdly.
I had also been looking at the way the oscilloscope saved data. I noticed that it saved some of the data in 256 byte chunks (which happens to be the LIF block size), each starting with 0x00 0xFE. I guessed that these two bytes indicated the length of the data to come (254 bytes). And then I guessed that maybe the executable files were similarly divided into 256 byte chunks, and what I thought was junk was a chunk header. It sure looked that way.
The chunking setup also allowed the system to have files whose length wasn't a multiple of block size, even though the LIF directory only listed file sizes in block size multiples. For the last header might be a number smaller than 0x00 0xFE.
I wrote a quick and dirty unchunker and ran it the code. Suddenly everything started fitting into place. Looking at the spacing of memory accesses and lengths of strings, I was able to figure out that the code is loaded at 0x00984500. Yay!
Eventually, I incorporated the unchunking and chunking into my lifutils.py code. Indeed, once I managed to extract the ROM code (a future story), I learned that the ROM disk code automatically chunks files being written and unchunks them on read, so we should really think of the chunking headers as a special feature of the LIF file system as found on the HP 165x units.
Alexander R Pruss
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.