Jump to content
IGNORED

Creating bank switched cartridges with gcc


TheMole

Recommended Posts

@TheMole: There are some issues with that bank switch test.

 

 

6126:     LI   R2,>0001
612A:     MOV  R2,@>6006

 

This is not quite correct from a stylistic point of view, but it works. The value 0001 is irrelevant and may be misleading. The only important fact is that you do a write operation to 6006 (with whatever value). What these lines do is to write 01 to 6007 and then 00 to 6006. Note that a MOVB would not change anything, because the TI-99/4A never writes single bytes, only words, even with MOVB). Maybe a simple

 

 

SETO @>6006

 

would be more intuitive.

 

Another more important point:

 

 

613C:     LI   R1,>0001
6140:     MOV  R1,@>6000
6144:     RT

 

This is the reason for the crash. You turn on bank 3 with this write operation (6000 = bank 3, 6002 = bank 2, 6004 = bank 1, 6006 = bank 0). However, the bin file in the RPK does not have executable code at offsets 6000-7FFF, only a "6000" at offset 6000. I suppose the actual banking code is missing here.

 

That is, the carttest.rpk won't work this way.

Link to comment
Share on other sites

  • 4 weeks later...
  • 5 months later...

I finally got this working in Classic99. I've attached the bin cart file as well as the source project after my tweaks. I haven't done any testing with the rpk build so I cannot say if that works or not.

 

The reason the old bin didn't work on Classic99 is that, as Mindlord points out, it doesn't have all the correct headers. The old build only has the cart header in bank 0. Apparently on Classic99 as well as real hardware, bank 0 is not always the bank that starts up - it can be any of the other banks.

 

My tweaks put the header (cart_header.asm), as well as the startup code (crt0.c) in all banks. I tweaked crt0 so that no matter which bank is running at startup, the code will then switch to bank 0. From there things work as they would have with the old code.

 

To make it all work I of course updated the Makefile as well as the linker script (cart.ld). If you are interested, you can do a diff to see what changes I made.

bankswitched2.zip

carttest8.bin

Edited by chue
  • Like 2
Link to comment
Share on other sites

  • 2 weeks later...

Any way to do this without the 32k expansion? I am tinkering with it trying to put a single trampoline in scratchpad, but it's not working for me.

 

There are 500+ bytes of C/ assembly code under the "persistent" directory that gets copied to expansion ram at startup. You could put this code in rom instead, but need to make sure that it is callable from all banks. You can use crt0.c as a guide on how to do the C code. Unfortunately I don't know how to do the same with assembly but that's probably key to your answer.

 

Other than the above you will also need to move the data and bss sections to scratchpad.

Edited by chue
Link to comment
Share on other sites

 

There are 500+ bytes of C/ assembly code under the "persistent" directory that gets copied to expansion ram at startup. You could put this code in rom instead, but need to make sure that it is callable from all banks. You can use crt0.c as a guide on how to do the C code. Unfortunately I don't know how to do the same with assembly but that's probably key to your answer.

 

Other than the above you will also need to move the data and bss sections to scratchpad.

I find it odd you do not use the one thing TI used for this.....GPL which is designed to set up the system and support menus, not to mention embedded Assembly into GPL moved to Scratch Pad.

All of my SAMS routines for RXB are assembly routines moved from GPL into Scratch pad and executed, than return back to GPL.

I mean after all you have 40K of space in a single cart and it takes just over 1 second to fill the 32K and Scratch Pad from GPL.

 

A Lot of people are hung up on making the TI exactly like a PC, which is puzzling as the TI was never laid out or designed this way.

This explains all the Brute Force methods being used to bypass the easy route, I guess easy is boring.

Edited by RXB
Link to comment
Share on other sites

I find it odd you do not use the one thing TI used for this.....GPL which is designed to set up the system and support menus...

 

It might be odd for you, but I have no idea how to do such a thing :). I'm all ears, so some pointers would be great.

Edited by chue
Link to comment
Share on other sites

@RXB:

 

Thanks for the Video. I know absolutely zero about GPL, but it does look like something worth knowing. So I will be adding them to my playlist for viewing later.

 

@Chue & Everyone else:

 

Success! Kinda. I hacked and hacked and hacked until I made it work. The cart.ld file has 4 banks, two of which are unused. Data and BSS live in scratchpad, persistent code was added to the header of each bank and the trampolines had to be dumbed down to not use the bankswitch header file anymore. I will post my hackery here later tonight once I clean it up.

 

It's now the responsibility of the programmer not to call banked functions from one another, only from bank0. Which is fine for my purposes. This could probably be fixed by putting the variables for bankswitch.h in the scratchpad, but I'm at the "if it ain't broke, don't fix it" stage.

 

It's fun because it means I can make programs with lots and lots of data in cartridge ROM, and still run on an unexpanded TI.

  • Like 2
Link to comment
Share on other sites

Attached is the source to my dirty bankswitch for unexpanded TI development. Hope it helps someone. Credits to all the giants who came before me. Would've never been able to do this without TheMole, Tursi, Chue, and Lee and everyone else. Now Graxx can grow up to be the fun little game I always wanted it to be and still play without 32k. :D

Dirty Bankswitch.zip

Edited by mindlord
  • Like 7
Link to comment
Share on other sites

* Cue "The Price is Right" lose sound *

My code doesn't work on real iron. Just a purple screen. Not sure what's causing that.

 

Just realized something... I just tried your code on js99er.net and got the purple screen. Then I checked the options and turned on 32k RAM and it suddenly works. So it looks like your code may still need the 32K for something.

Link to comment
Share on other sites

If you look in the crt0.c the C stack is still set to lower expansion ram.

 

li sp, 0x4000 ; The stack grows down from there. The compiler chooses when to use the stack, and goes to great lengths not to, or so it seems... I haven't looked inside the compiler.

 

I've set the stack to 0x8400 for cartridges if I don't care about GPL workspace at all.

 

So the ram map becomes:

 

>8300 -> >8320 C WS

>8320 -> C data ( global variables and such ) grows up, but I believe it is not dynamic

<- >8400 C stack parameters and local function variables, grows down.

 

Life will crash when data meets stack.

 

-M@

  • Like 3
Link to comment
Share on other sites

Is it possible to move the declaration of the C stack pointer to the linker script? So that the memory map is defined in one file...

 

I don't know anything about linker scripts, yet, but I'm hoping something like being able to define an external symbol to use in that line of assembly.

 

-M@

  • Like 1
Link to comment
Share on other sites

Is it possible to move the declaration of the C stack pointer to the linker script? So that the memory map is defined in one file...

 

Ah, great idea! I got it working with the following

 

cart.ld:

SECTIONS
{
   _sp_init = 0x8400;

crt0.c:

 // Set stack
 extern unsigned int  _sp_init;
 __asm__
 (
    "li sp, %0 \n\t" : : "i" (&_sp_init)
 );

 

 

 

 

  • Like 2
Link to comment
Share on other sites

So how does global variables work with bank switching? If I put them in the same space as the trampolines and cart headers I have to declare them 4 times with four different symbols.

#include "vdp.h"
#ifdef BANK0
int nTextRow,nTextEnd;		// definitions for the bottom line of the screen
int nTextPos;
#endif
#ifdef BANK1
int nTextRow1,nTextEnd1;		// definitions for the bottom line of the screen
int nTextPos1;
#endif
#ifdef BANK2
int nTextRow1,nTextEnd1;		// definitions for the bottom line of the screen
int nTextPos1;
#endif
#ifdef BANK3
int nTextRow3,nTextEnd3;		// definitions for the bottom line of the screen
int nTextPos3;
#endif

Which seems to make them unavailable to the other banks. Ever since getting the cart.ld to work for without 32k, I'm having a heck of a time working out how to get Tursi's VDP library to work. I've cherry picked out the methods I need and I am loading them into the "Shared Space" as I am now calling it.

However, it seems that it's clobbering what little RAM I have, doing weird stuff like writing register values right to the screen, corrupting the stack, or all three. I'm not really sure.

Is there an easy way to see how much RAM is being used, or what's on the stack?

I'm used to having a real debugger like GDB, sometimes the assembly code flying by in Classic99 totally looses me. :D

Link to comment
Share on other sites

I haven't checked, does Insomnia's GCC work give us a 9900-aware GDB? If so, I can build a stub into Classic99. ;)

 

The Classic99 debugger memory watch, set to view the scratchpad, would give you an idea, at least. One of the registers is the stack pointer so you can see how far down the stack has gone. If you compare that to the memory map for your globals, you'll be able to see if you're trashing your data.

 

Global variables shouldn't normally require any special effort -- but I haven't looked at how you're building and linking banks. As long as the linker knows it's all one program, you should be able to just declare them once and extern them... that's not working?

 

As for my libraries... I never expected people to try to run them without memory expansion, but I'm a bit surprised that the VDP code doesn't "just work". Yes, it does VDP register writes directly, it's coded to work with a minimum of dependencies. But it shouldn't be messing with your RAM... my first thought is stack overflow. 256 bytes won't take you very far, especially at 2 bytes per entry. Try rebuilding with a map file and compare against your stack pointer, see if you've got a collision there.

Link to comment
Share on other sites

Some of the libti99 input routines assume the GPL workspace is viable for things like KSCAN. If we are letting the stack run over the GPL workspace, then kscan won't work. There are other input routines that can be modified to not write directly to scratchpad.

 

And of course, make sure the vdp interrupt routine is off or it will corrupt your stack when using only scratchpad.

 

-M@

  • Like 2
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...