Jump to content
IGNORED

Help with GROM header


orbitaldecay
 Share

Recommended Posts

Hello All,

 

I've recently become interested in programming on the TI-99/4A. After figuring out how to write and assemble a simple 'Hello, World' programing using the EA cart, I decided I'd give a go at writing a simple cart from scratch. Here is my code so far:

       AORG >6000

       BYTE >AA     * Standard header
       BYTE >01     * Version number
       BYTE >01     * Number of programs (optional)
       BYTE >00     * Reserved
       DATA >0000   * Pointer to power-up list
       DATA PRGLST  * Pointer to program list
       DATA >0000   * Pointer to DSR list
       DATA >0000   * Pointer to subprogram list
       
PRGLST DATA >0000   * Next program list entry
       DATA MAIN    * Program address
       BYTE 5       * Length of name
       TEXT 'HELLO' * Name

MAIN   B *R11

I've gotten the GROM header format from http://www.unige.ch/medecine/nouspikel/ti99/groms.htm#GROM%20header.

 

So far so good... except when I assemble it and try to load it with classic99, it doesn't work! I'd expect to see an entry in the main menu that says "2 FOR HELLO", but it doesn't show up. I'm using Asm994a. Does anyone know what I'm doing wrong?

Link to comment
Share on other sites

Good for you, diving right in! You've got the right idea, just missing a little background information.

 

The first is that it's important to differentiate between "GROM" and "ROM". GROM is actually a completely separate memory space that TI used for a lot of stuff. The memories are auto-incrementing (much like a modern serial EEPROM) and can not run assembly language code. Normally they contain data or "GPL".

 

You're writing assembly, so you will be dealing with ROM. All that said, of course, the header is the same for both (there are some limitations to deal with, but not for just making it show).

 

Your header looks okay, so the next questions are "how are you assembling it?" and "how are you loading it?". If we can see your binary we can check that matches the source, but I suspect it's just how you're loading it. The issue that you are probably running into is a combination of those.

 

I think you either are trying to load the object code instead of a binary cartridge (Asm994A can produce a cartridge, otherwise you need a couple of steps to convert the object file into a binary - this can be done with external tools or Classic99), or it's not loading at the right address. If the final cartridge name ends with "C.BIN" (for CPU memory cartridge) you can use Cartridge->User->Open to load it into Classic99.

 

My last comment is unrelated to your problem -- I don't think B *R11 will return successfully from a cartridge launch... the best way to reset the console in a cartridge is to branch to the reset vector: BLWP @>0000

Edited by Tursi
Link to comment
Share on other sites

Good for you, diving right in! You've got the right idea, just missing a little background information.

 

The first is that it's important to differentiate between "GROM" and "ROM". GROM is actually a completely separate memory space that TI used for a lot of stuff. The memories are auto-incrementing (much like a modern serial EEPROM) and can not run assembly language code. Normally they contain data or "GPL".

 

You're writing assembly, so you will be dealing with ROM. All that said, of course, the header is the same for both (there are some limitations to deal with, but not for just making it show).

 

Your header looks okay, so the next questions are "how are you assembling it?" and "how are you loading it?". If we can see your binary we can check that matches the source, but I suspect it's just how you're loading it. The issue that you are probably running into is a combination of those.

 

I think you either are trying to load the object code instead of a binary cartridge (Asm994A can produce a cartridge, otherwise you need a couple of steps to convert the object file into a binary - this can be done with external tools or Classic99), or it's not loading at the right address. If the final cartridge name ends with "C.BIN" (for CPU memory cartridge) you can use Cartridge->User->Open to load it into Classic99.

 

My last comment is unrelated to your problem -- I don't think B *R11 will return successfully from a cartridge launch... the best way to reset the console in a cartridge is to branch to the reset vector: BLWP @>0000

 

Thanks for your encouraging and informative post! "If the final cartridge name edits with 'C.BIN'" was the magic piece of information I was missing. I named the image 'HELLO.BIN' and I was bashing my head against the wall as to why Cartridge->User->Open wouldn't load it :-D . Now that the file is named "HELLOC.BIN" I can see it in the menu! I have a friend who is able to burn ROMs to carts. Could he burn my HELLOC.BIN file to a rom, pop in the cart, and see that on the menu on his real deal TI-99/4A?

 

Thanks again, I was really pulling my hair out over this one!

Link to comment
Share on other sites

No worries.. the User->Cartridge->Load is just a helper I put in for loading the old V9T9 style carts, but since they are raw binaries, the filename is the only way to know where in the memory map they go! Normally the Classic99.ini is extended to add a permanent cartridge - check the manual for that, there are examples near the end.

 

And yes! If you burned that to an EPROM it should load on a real TI. The only caveat is that if the TI displays "2.2" and a 1983 copyright on the title page, it won't work, because in the 2.2 consoles TI locked out ROM-only cartridges. Those are a bit more uncommon than the 1981 version though. :)

Link to comment
Share on other sites

Hello All,

 

I've recently become interested in programming on the TI-99/4A. After figuring out how to write and assemble a simple 'Hello, World' programing using the EA cart, I decided I'd give a go at writing a simple cart from scratch. Here is my code so far:

       AORG >6000

       BYTE >AA     * Standard header
       BYTE >01     * Version number
       BYTE >01     * Number of programs (optional)
       BYTE >00     * Reserved
       DATA >0000   * Pointer to power-up list
       DATA PRGLST  * Pointer to program list
       DATA >0000   * Pointer to DSR list
       DATA >0000   * Pointer to subprogram list
       
PRGLST DATA >0000   * Next program list entry
       DATA MAIN    * Program address
       BYTE 5       * Length of name
       TEXT 'HELLO' * Name

MAIN   B *R11

I've gotten the GROM header format from http://www.unige.ch/medecine/nouspikel/ti99/groms.htm#GROM%20header.

 

So far so good... except when I assemble it and try to load it with classic99, it doesn't work! I'd expect to see an entry in the main menu that says "2 FOR HELLO", but it doesn't show up. I'm using Asm994a. Does anyone know what I'm doing wrong?

 

Ok if you go to Atari Age tutorials I wrote on GPL and Assembly of a GPL program here is your repaired program.

      GROM >6000 
      AORG >0000

       BYTE >AA     * Standard header
       BYTE >01     * Version number
       BYTE >01     * Number of programs (optional)
       BYTE >00     * Reserved
       DATA >0000   * Pointer to power-up list
       DATA PRGLST  * Pointer to program list
       DATA >0000   * Pointer to DSR list
       DATA >0000   * Pointer to subprogram list
       
PRGLST DATA >0000   * Next program list entry
       DATA MAIN    * Program address
       BYTE 5       * Length of name

MAIN   ALL  32      * Clears screen with space character
       FMT          * Get ready to do a text set up
       COL  14      * COLUMN 14 on screen 32x24
       ROW  12      * ROW 12 on screen 32x24
       TEXT 'HELLO' * Text to display
       FEND
HERE   B    HERE    * Loop to HERE forever


*       TEXT 'HELLO' * Name * must be in a command structure.
* MAIN  B    *R11    * This is a ASSEMBLY COMMAND does not exist in GPL

        END
Link to comment
Share on other sites

 

 

Ok if you go to Atari Age tutorials I wrote on GPL and Assembly of a GPL program here is your repaired program.

 

Thank you for your response. But as Tursi correctly identified, I was attempting to write a ROM in assembly and not a GROM in GPL. I was just conflating ROMs and GROMs because their headers looked the same. I now understand the difference.

Link to comment
Share on other sites

Very nice, I could have used this example when I started on TMS9900 assembler a few years ago.

 

I noticed some of comments in your code:

* Nice tight loop. Too bad we don't have a REP or LOOP
* instruction like x86 

PTLP   MOVB R1, @VDPWD
       DEC  R2
       JNE  PTLP

One small improvement is to load VDPWD into a register:

       LI   R0,VDPWD
PTLP   MOVB R1,*R0
       DEC  R2
       JNE  PTLP

This is faster because the MOVB instruction is now only one word instead of two. Then you can start unrolling the loop, e.g:

       LI   R0,VDPWD
PTLP   MOVB R1,*R0
       MOVB R1,*R0
       DECT R2
       JNE  PTLP

You can go further and unroll the loop up to 8 times. After that the effect becomes negligible. Don't worry about pauses between writes, Tursi has shown you cannot overrun the VDP on writes.

Link to comment
Share on other sites

Very nice, I could have used this example when I started on TMS9900 assembler a few years ago.

 

I noticed some of comments in your code:

* Nice tight loop. Too bad we don't have a REP or LOOP
* instruction like x86 

PTLP   MOVB R1, @VDPWD
       DEC  R2
       JNE  PTLP

One small improvement is to load VDPWD into a register:

       LI   R0,VDPWD
PTLP   MOVB R1,*R0
       DEC  R2
       JNE  PTLP

This is faster because the MOVB instruction is now only one word instead of two. Then you can start unrolling the loop, e.g:

       LI   R0,VDPWD
PTLP   MOVB R1,*R0
       MOVB R1,*R0
       DECT R2
       JNE  PTLP

You can go further and unroll the loop up to 8 times. After that the effect becomes negligible. Don't worry about pauses between writes, Tursi has shown you cannot overrun the VDP on writes.

 

Nice! Thanks for the feedback and good ideas. I'll definitely be making use of them :cool:. Btw, do you know of any documentation of the number of clock cycles each instruction uses? If I unroll the loop 8 times, I imagine it would be faster (and more space efficient) to use S R2, 8 then DECT R2, 4 times (actually, I'm not even sure you can use an immediate value with S?), but I'd like some documentation to back that up.

Edited by orbitaldecay
Link to comment
Share on other sites

 

Nice! Thanks for the feedback and good ideas. I'll definitely be making use of them :cool:. Btw, do you know of any documentation of the number of clock cycles each instruction uses? If I unroll the loop 8 times, I imagine it would be faster (and more space efficient) to use S R2, 8 then DECT R2, 4 times (actually, I'm not even sure you can use an immediate value with S?), but I'd like some documentation to back that up.

 

I use the debugger in Classic99 to time my loops. You can use AI R2,-8, but you can also divide it by 8 (SRL R2,3) before the loop and just use DEC R2.

Link to comment
Share on other sites

 

Nice! Thanks for the feedback and good ideas. I'll definitely be making use of them :cool:. Btw, do you know of any documentation of the number of clock cycles each instruction uses? If I unroll the loop 8 times, I imagine it would be faster (and more space efficient) to use S R2, 8 then DECT R2, 4 times (actually, I'm not even sure you can use an immediate value with S?), but I'd like some documentation to back that up.

As you suspect, you can't use an immediate value with the SONY instruction. You'd use the AI instruction.

 

AI R2,-8

 

That would do it. :-)

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...
 Share

  • Recently Browsing   0 members

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