Jump to content
IGNORED

Understanding how cartridges load and run


Recommended Posts

I've made some progress with my Ghidra loaders for TI-99/4A. I now have ones in progress for FIAD (V9T9), TIFILES (XMODEM), .BIN (raw files without external header), and .RPK (MAME cartridge format).

 

So RPK files are zip archives with one XML file that's used, one or more .bin files, and usually some unused files.

 

The .bin files all end with a letter to provide some information about them:

xxxxxC.BIN - loads as CPU cartridge ROM at >6000

xxxxxD.BIN - loads as banked CPU cartridge ROM at >6000, second bank (such as Extended BASIC or AtariSoft carts)

xxxxxG.BIN - loads as GROM cartridge at >6000 in GROM space

xxxxx3.BIN - Classic99 extension, loads as a 379/Jon Guidry style cartridge ROM at >6000

 

Often each .BIN file has an internal 'standard header', but not always. In the case of Burgertime there are two bin files: phm3233c.bin and phm3233g.bin, so the first is a CPU cartridge ROM and the second is a GROM cartridge. Since they both load at >6000 I have to ask how the address space works. Is "GROM space" its own separate address space? Or is there a paging mechanism?

 

The layout.xml file looks like this:

<romset listname="burgertm" version="1.0">

  <resources>

    <rom file="phm3233g.bin" id="gromimage"/>

    <rom file="phm3233c.bin" id="romimage"/>

  </resources>

  <configuration>

    <pcb type="standard">

      <socket id="grom_socket" uses="gromimage"/>

      <socket id="rom_socket" uses="romimage"/>

    </pcb>

  </configuration>

</romset>

 

So you can see that all it does is say which .bin file goes in which socket (rom vs grom). Nothing about address etc.

 

I'm not proficient at MAME's built-in debugger, but I can see that the "CPU cartridge" is in memory at >6000. I'm not sure yet how to find if or where the GROM is loaded. Does anyone know?

 

The GROM .bin file does have a standard header but the CPU .bin file does not. It starts with >FF but is not a GRAM Kracker format. After the >FF it has one byte each from >01 to >0F and then at >6010 it appears to have an address: >6012. At >6012 it has >C80B but as the TMS9900 extension for Ghidra is currently broken I can't check if that's valid TMS9900 machine code.

 

Does anybody know where execution begins in a cartridge file that doesn't have one of the usual formats? Or did I just fail to identify which format this is? Or is it standard that there's an execution address at >6012?

Link to comment
Share on other sites

Of course GROM has a separate address space! Putting all the bits of info together in my brain sadly takes more than one reading. I found the GROM at address >0000 of what MAME calls the ":gromport:single:cartridge:grom_contents" region.

Screenshot2024-09-12at7_22_43PM.thumb.png.207ea11621eeae9f02055edcee71088a.png

This doesn't match the info that says it would be at >6000 so I'm still missing something.

 

Also, for a cartridge that has a GROM and a CPU ROM, which will be executed first? It seems that the original cartridges were GROM cartridges so that would make me think the GROM calls into the CPU ROM at some point, but of course I am probably still missing quite a lot.

  • Like 1
Link to comment
Share on other sites

Required reading:  https://www.unige.ch/medecine/nouspikel/ti99/architec.htm 

GROM is a separate address space. The built in console GROM files are 24K and take up >0000 to >5FFF and the user/cart GROMs start at >6000 and can be 40K in size up to >FFFF (actually, you can utilize more than one GROM base... but that's probably not of great interest to the basic understanding here).

 

The TI99 built-in 8K Console ROM will boot up figure out what's "out there". If there is something to run at GROM >6000 or if it should look to the Cart/User ROM space... etc.

Link to comment
Share on other sites

28 minutes ago, hippietrail said:

Of course GROM has a separate address space! Putting all the bits of info together in my brain sadly takes more than one reading. I found the GROM at address >0000 of what MAME calls the ":gromport:single:cartridge:grom_contents" region.

Screenshot2024-09-12at7_22_43PM.thumb.png.207ea11621eeae9f02055edcee71088a.png

This doesn't match the info that says it would be at >6000 so I'm still missing something.

 

Also, for a cartridge that has a GROM and a CPU ROM, which will be executed first? It seems that the original cartridges were GROM cartridges so that would make me think the GROM calls into the CPU ROM at some point, but of course I am probably still missing quite a lot.

GROMs also generally only contain GPL assembly not TMS9900 assembly, so until you have a Ghidra loader that understands the GPL opcodes no point worrying about it yet, as it will not disassemble via 9900.

 

On the TI99 the first 8k console ROM at >0000 contains a virtual cpu interpreter that decodes the GPL.

 

The TI99 is complex beast in that it basically has two cpus each with its own 64k of address space, one real the 9900 and one virtual the GPL which is custom language that TI designed which simulates a stack based 8 bit type opcode assembly with custom commands to make using the VDP which has its own 16k of ram easier.

  • Like 4
Link to comment
Share on other sites

1 hour ago, Gary from OPA said:

GROMs also generally only contain GPL assembly not TMS9900 assembly, so until you have a Ghidra loader that understands the GPL opcodes no point worrying about it yet, as it will not disassemble via 9900.

Yes this much I did already understand. I have a page or two of the GPL opcodes handy. Writing a Ghidra extension for a new processor looks a lot harder than writing a loader, but it should be possible as I believe other virtual machines are supported by Ghidra already. In the meantime I can do things like put the mnemonics in comments. But at this stage it's often just helpful to look up an opcode or two to check that I'm interpreting things correctly.

Link to comment
Share on other sites

5 hours ago, hippietrail said:

xxxxx3.BIN - Classic99 extension, loads as a 379/Jon Guidry style cartridge ROM at >6000

 

Though @Tursi’s Classic99 still honors it, the ‘3’ terminator is deprecated in favor of ‘9’ for the 379 inverted-bank implementation and ‘8’ for the 378 non-inverted-bank implementation.

 

...lee

  • Like 2
Link to comment
Share on other sites

15 minutes ago, Asmusr said:

@hippietrail can you say a bit more about what we would be able to use Ghidra for when you're done?

Ghidra is open source reverse engineering tool mainly designed to disassemble computer languages, amazing enough it does support tms9900 except it needs to be updated, the part that loads the binary code in so you can view it.

 

https://en.m.wikipedia.org/wiki/Ghidra

 

It is nice piece of software designed by NSA and is free compared to the commercial IDA Pro which is similar type of tool.

 

 

  • Like 3
Link to comment
Share on other sites

57 minutes ago, Gary from OPA said:

Ghidra is open source reverse engineering tool mainly designed to disassemble computer languages, amazing enough it does support tms9900 except it needs to be updated, the part that loads the binary code in so you can view it.

 

https://en.m.wikipedia.org/wiki/Ghidra

 

It is nice piece of software designed by NSA and is free compared to the commercial IDA Pro which is similar type of tool.

Thanks, I have also Googled it, but how would it compare to something like SkoolKit for the ZX Spectrum?

  • Like 1
Link to comment
Share on other sites

1 hour ago, Asmusr said:

Thanks, I have also Googled it, but how would it compare to something like SkoolKit for the ZX Spectrum?

Not the same class at all, -- The best we have currently for live debugging and simulating TI99 code would be Classic99 - All tho for it, would be nice if it did more in the way of displaying GPL opcode disassembly as well.

Link to comment
Share on other sites

Ghidra is basically an advanced interactive disassembler and decompiler.

So first it takes in binary executable code such as machine code for a CPU or byte code for a virtual machine such as WASM, Java bytecode, Android Dalvik bytecode, C# CIL, etc.

As long as the processor is supported either with built-in support with Ghidra, or with a 3rd party extension.

Then it also decompiles the executable code into C-like source code. (It doesn't have to have been originally in C and it doesn't decompile to other languages.)

 

It's less popular than IDA, but it's free and open source, whereas IDA is expensive.

 

Its main focus is on modern platforms but due to being open source we're free to add retro platforms. People have already added support for some of the most popular retro platforms and for most of the console gaming platforms which are newer than what I'm interested in.

 

For many platforms there are already 'better' disassemblers. So if you're only interested in only in platform it might not interest you. But, like MAME, it supports many platforms in the same way and anybody that can code can add new support. So if you've started to feel comfortable using Ghidra on one platform it's easy to start using it on another platform even if you don't know much about its architecture.

 

Somebody made a TMS9900 CPU extension but Ghidra has been updated a couple of times while the TMS9900 extension hasn't been updated since 2022. Nobody has made any Loader or FileSystem extensions for TI-99/4A that I know of.

 

I'm working on Loaders and FileSystems. Loaders parse file formats of single programs to find the parameters such as which CPU and the machine code sections so that Ghidra can then disassemble and decompile it. FileSystems parse file formats that contain multiple programs, such as disk images, tape images, archive and compression file formats.

 

Ghidra is written in Java, which is not my favourite programming language. Its extension-development tools are for Eclipse, which is my least favourite IDE. Apparently some people have got it working in other IDEs and maybe working with Kotlin, but I haven't gone down that rabbit hole yet.

 

I only know a tiny fraction of Ghidra, both how to use it and how to program extensions for it. I'm not an expert. But as an old Z80 and 680x0 machine code and assembly programmer who is also interested in the other systems from the late '70s until the PC era, the fun of exploring is enough to keep me going so far.

 

If anyone is keen, you're welcome to have a look at RetroGhidra on Github: https://github.com/hippietrail/RetroGhidra but I haven't done a release yet and though TI-99/4A files (not disk images yet) can be loaded, they can't yet be disassembled. You can add feature requests for other systems and file formats not on my TODO list etc.

 

Also the TI stuff is not in GitHub yet but I can put in in a branch if anyone is interested. https://github.com/gnulnulf/Ghidra-TMS9900 I will have to look at the broken TMS9900 support later, but that looks much more complicated to work on than Loaders and FileSystems. I should at least look at it more deeply and file a bug report. (If I'm wrong and it's easier than I think then one day somebody could probably add GPL support.)

  • Like 1
Link to comment
Share on other sites

12 hours ago, Asmusr said:

Thanks, I have also Googled it, but how would it compare to something like SkoolKit for the ZX Spectrum?

It's probably not as good as many of the dedicated tools that target only one platform. But also most of those tools probably disassemble but don't decompile.

 

Decompiling can be fun because you can view pseudocode of a function whether its decompiled from an assembly language you know well or one that's totally alien to you.

 

When I first got interested in Ghidra for old computers at the start of the pandemic I thought it would be fun to see if the ports of Manic Miner from the ZX Spectrum to other systems of the day used the same logic and algorithms. (Which I never ended up getting to.)

 

I made several disassemblers when I was around 12 to 15 in BASIC on my ZX Spectrum and a decade later made one in C for my Amiga 2000/030. I've been interested in disassemblers ever since.

  • Like 1
Link to comment
Share on other sites

11 hours ago, Gary from OPA said:

Not the same class at all, -- The best we have currently for live debugging and simulating TI99 code would be Classic99 - All tho for it, would be nice if it did more in the way of displaying GPL opcode disassembly as well.

Ghidra actually has debugging support but I've never tried to use it. I'm assuming it would work for any platform that has the loader support and cpu support. I think it's relatively new. I don't know if anyone has tried to use it with any retro platform. I would definitely watch any YouTube videos anyone made on that topic!

 

For the Speccy I usually use RetroVirtualMachine, which is a very slick Speccy emulator with a built-in debugger. I mainly used this to make sure I was parsing the .SNA file format properly for my Speccy .SNA loader for Ghidra.

But then there's MAME, which is maybe like a lowest common denominator. Like most things in MAME, its debugger is probably unintuitive and probably has quite a learning curve, but once you get to grips with it on one platform, it will work the same on every platform MAME supports.

  • Like 1
Link to comment
Share on other sites

49 minutes ago, Torrax said:

From your description you are going to need a "GPL extension" for Ghidra to handle the GROM files.

There is a GPL interpreter built into the TI-99/4A system ROMs that handles the GROM code.

My goals for now are Loaders and FileSystems and I have a hunch that while I could probably write a GPL disassembler with enough effort, I'm not sure I could write a GPL extension for Ghidra. From what I've seen of processor support they look quite arcane.

 

But it would surely be a fun and rewarding project for the right person! There is also a chance that it might be a bit higher level than the other bytecodes Ghidra already supports which might potentially cause problems.

 

In the meantime I can use xdg99.py to see that I've identified the right parts of a file and the right load addresses and get a vague idea what some of the code might do.

  • Like 1
Link to comment
Share on other sites

In case anyone's interested, I've filed a bug report against the TMS9900 extension for Ghidra: https://github.com/gnulnulf/Ghidra-TMS9900/issues/1

 

Perhaps people who have written TI-99/4A emulators could manage to understand some of it, but it's beyond my skill and knowledge levels.

 

Hopefully the person who developed the extension will notice in the near future.

  • Like 1
Link to comment
Share on other sites

Good news!

The author of the TMS9900 extension for Ghidra has posted a fix that works for me. I can now disassemble the machine code parts of .rpk cartridge emulator files. (Not the GPL parts of course unfortunately.)

 

If anyone can point me towards some files that have only TMS9900 machine code and no GPL bytecode I can make sure my TIFILES, FIAD, and .bin loaders work. So far it seems most of the files I've collected are BASIC, GROMs, or game cartridge files, which I believe always have a GROM whether or not they also have some machine code.

 

Also, are there any other formats? Note that I'm not ready to support disk image formats or cassette tape .wav files yet.

  • Like 1
Link to comment
Share on other sites

35 minutes ago, HOME AUTOMATION said:

Thanks! The parsing of the .bin / standard header is working and disassembling is working. Sadly, decompiling into C/pseudocode is not working. That's up to the TMS9900 module, which the author tells me is very much still a work-in-progress.

 

Standard header:

image.thumb.png.dec6e84821b4ea99796654f16bfb626d.png

Beginning of code as pointed to by Standard header:

image.thumb.png.6e517c13f6260a79320217552cef5514.png

 

Edited by hippietrail
better first image without comments cropped out
  • Like 1
Link to comment
Share on other sites

2 hours ago, hippietrail said:

Good news!

The author of the TMS9900 extension for Ghidra has posted a fix that works for me. I can now disassemble the machine code parts of .rpk cartridge emulator files. (Not the GPL parts of course unfortunately.)

 

If anyone can point me towards some files that have only TMS9900 machine code and no GPL bytecode I can make sure my TIFILES, FIAD, and .bin loaders work. So far it seems most of the files I've collected are BASIC, GROMs, or game cartridge files, which I believe always have a GROM whether or not they also have some machine code.

 

Also, are there any other formats? Note that I'm not ready to support disk image formats or cassette tape .wav files yet.

 

Two things:

  1. @ralphb’s suite of TI-99/4A cross-development tools written in Python, which include a GPL cross-assembler and a GPL disassembler, might be useful in your endeavors.
  2. My fbForth 3.0 cartridge BIN (four 8KiB banks) is all TMS9900 machine code, which you are welcome to use:

...lee

  • Like 1
Link to comment
Share on other sites

9 minutes ago, Lee Stewart said:

 

Two things:

  1. @ralphb’s suite of TI-99/4A cross-development tools written in Python, which include a GPL cross-assembler and a GPL disassembler, might be useful in your endeavors.
  2. My fbForth 3.0 cartridge BIN (four 8KiB banks) is all TMS9900 machine code, which you are welcome to use:

...lee

Thanks that could be perfect! I've already been looking at ralphb's tools, especially the GPL disassembler. I'm going to see how Ghidra goes with your Forth binary right now.

 

I pushed all my TI-99/4A loader work to GitHub a few hours ago by the way.

  • Like 2
Link to comment
Share on other sites

On 9/12/2024 at 5:57 AM, hippietrail said:

The GROM .bin file does have a standard header but the CPU .bin file does not. It starts with >FF but is not a GRAM Kracker format. After the >FF it has one byte each from >01 to >0F and then at >6010 it appears to have an address: >6012. At >6012 it has >C80B but as the TMS9900 extension for Ghidra is currently broken I can't check if that's valid TMS9900 machine code.

 

Does anybody know where execution begins in a cartridge file that doesn't have one of the usual formats? Or did I just fail to identify which format this is? Or is it standard that there's an execution address at >6012?

On 9/12/2024 at 6:27 AM, hippietrail said:

Also, for a cartridge that has a GROM and a CPU ROM, which will be executed first? It seems that the original cartridges were GROM cartridges so that would make me think the GROM calls into the CPU ROM at some point, but of course I am probably still missing quite a lot.

Normally, carts have a single HEADER. If a GROM is used, that's where the HEADER, would be. A ROM would only have a HEADER, if no GROM is included.

The GROM HEADER(program list), can only point execution to an address within GROM address space, where GPL code, exists. Similarly a ROM's HEADER, can only start execution within CPU address space, and MACHINE CODE, exists.

 

GPL uses single BYTE instructions. When GPL code, is running, and needs to branch to MACHINE CODE(which can only execute from CPU space), a GPL, XML(eXecute Machine Language, >0F)instruction is used. This is followed by a single BYTE, that indicates where to start execution within CPU space. That byte is divided into two nybbles. The first nybble, indicates what TABLE(CPU, base address), is desired...

 

Table    Address    Memory
>0    >0D1A    Console ROM
>1    >12A0    "
>2    >2000    Low memory expansion
>3    >3FC0    "
>4    >3FE0    "
>5    >4010    Peripheral card ROM (or RAM)
>6    >4030    "
>7    >6010    Cartridge ROM/ Rambo bank (RAM)
>8    >6030    "
>9    >7000    Cartridge bank / Rambo bank
>A    >8000    Decoded as >8300 on most machines
>B    >A000    High memory expansion
>C    >B000    "
>D    >C000    "
>E    >D000    "
>F    >8300    Scratch-pad memory

 

(ABOVE, taken from: https://www.unige.ch/medecine/nouspikel/ti99/gpl2.htm)

 

The second NYBBLE, indicates what PROCEDURE(branch address), to execute...

The PROCEDUREs, are single WORD entries, that indicate the final address to branch to.

Thus... XML >70, will point execution to the CPU address, specified in >6010. XML >71, should point to >6012, et cetera.

 

That all being said, it is possible to use both GROM, and ROM, HEADERS, to some advantage, in a single cart ...or at least I have.
This is undocumented(a trick), and there probably is a better way to handle this. But can be less practical if one is reusing/modifying existing code.

 

I sometimes use two HEADERS, in order to rewrite/replace the RAM bank, in MINI MEMORY. This allows to start execution in the RAM bank(without the need to modify the GPL code to include an XML), while retaining the ability of the GROM HEADER, to specify the POINTER TO SUBPROGRAM LIST, needed, for example, to add "CALL LINK" to BASIC.

 

I used this, here, to get SNAKE SNAKE(BASIC/MINI MEMORY), to run as a cartridge.

:sleep:

Edited by HOME AUTOMATION
left out a ...), and ..., also removed some anomalous occurrences of the current time/date.
  • Like 3
Link to comment
Share on other sites

On 9/14/2024 at 11:04 AM, Lee Stewart said:

 

Two things:

  1. @ralphb’s suite of TI-99/4A cross-development tools written in Python, which include a GPL cross-assembler and a GPL disassembler, might be useful in your endeavors.
  2. My fbForth 3.0 cartridge BIN (four 8KiB banks) is all TMS9900 machine code, which you are welcome to use:

...lee

 

I think we should mention that there is a lot of 9900 code but also a significant amount of address threaded data with "dictionary" headers interleaved.

It's a really good test for a diss-assembler. :)

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...