Jump to content
IGNORED

ROM cartridge with multiple banks


senior_falcon

Recommended Posts

Here is a question that pertains to a project I am working on. I think I know the answer but the job is easier if I am wrong.

In a cartridge with multiple banks of rom that are selected by writing to >6000 for bank 0, >6002 for bank 1, etc.:

At powerup on a real TI99, is the cartridge rom in an indeterminate state or does it always start up set to bank 0.

I suspect you cannot count on that happening. A workaround would be to start with GPL and use that to set the rom to bank 0, then go from there, but it would be nice if I didn't have to do that.

 

  • Like 1
Link to comment
Share on other sites

I put this routine into my XB ROMs as you are right it was sometimes unpredictable so all routines now end with this:

 

1049            *********************************************************** 
  1050 73E8 C24B  XISRON MOV  R11,R9       * save return address  
  1051 73EA C820         MOV  @FAC,@ISR    * Put FAC into ISR Interupt hook   
       73EC 834A  
       73EE 83C4  
  1052 73F0 100A         JMP  NEXIT        * exit   
  1053            *********************************************************** 
  1054            * CALL ISROFF(variable)                                   * 
  1055            *********************************************************** 
  1056 73F2 C24B  XISROF MOV  R11,R9       * save return address  
  1057 73F4 C820         MOV  @ISR,@ISR    * Compare if new ISR HOOK  
       73F6 83C4  
       73F8 83C4  
  1058 73FA 1303         JEQ  NHOOK        * No   
  1059 73FC C820         MOV  @ISR,@FAC    * Put ISR Hook into FAC  
       73FE 83C4  
       7400 834A  
  1060 7402 04E0  NHOOK  CLR  @ISR         * Clear ISR Hook   
       7404 83C4  
  1061 7406 04E0  NEXIT  CLR  @STATUS      * Clear GPL stuse byte   
       7408 837C  
  1062 740A 0460         B    @PAGER       * return to XB   
       740C 7FFA  
  1063            ************************  
  1064 740E D601  SPRLP  MOVB R1,*R8     * Write a byte to next VRAM location 
  1065 7410 0602         DEC  R2         * COUNT-1  
  1066 7412 16FD         JNE  SPRLP      * LOOP   
  1067 7414 045B         RT   
  1068            *********************************************************** 
  1069 7FFA              AORG >7FFA   
  1070 7FFA 04E0  PAGER  CLR  @>6000   * RESTORE PAGE ONE   
       7FFC 6000  
  1071 7FFE 0459         B    *R9      * return to caller   
  1072            *********************************************************** 
  1073                   END  

PAGER IS THE ROUTINE SO ALL END UP THERE AND IT ALWAYS HAS THOSE LAST 6 BYTES IN ALL PAGES SO NO PROBLEMS RESULT.

Link to comment
Share on other sites

Put the cartridge header in each bank, and in the header code select the bank you want to continue running from. It then doesn't matter which bank it starts in. If you wanted to just copy the code from the cartridge banks to 32K RAM then run the program from RAM, the cartridge headers in each bank can be identical.

  • Like 1
Link to comment
Share on other sites

12 hours ago, senior_falcon said:

...

At powerup on a real TI99, is the cartridge rom in an indeterminate state or does it always start up set to bank 0.

I suspect you cannot count on that happening. A workaround would be to start with GPL and use that to set the rom to bank 0, then go from there, but it would be nice if I didn't have to do that.

 

Yes, on real hardware with 74'379, 74'378 or 74'377 latches for the bank address, they do not have a deterministic or specified starting value for the latch data. So it is effectively random on power up. Some chips are consistent, but a different physical chip makes no promise to agree with any other physical chip. 

 

This includes uber-grom ROM only boards. There was some nuance here, which I do recall, but it is inconsequential for practical application. 

 

I believe the FlashROM99 was still nondeterministic. 

 

I believe the FinalGROM99 was deterministic. But for community sake, that detail is best ignored.

  • Like 1
Link to comment
Share on other sites

3 hours ago, Stuart said:

Put the cartridge header in each bank, and in the header code select the bank you want to continue running from. It then doesn't matter which bank it starts in. If you wanted to just copy the code from the cartridge banks to 32K RAM then run the program from RAM, the cartridge headers in each bank can be identical.

Yes, this copies 32K into RAM and then runs the program. For this application, bank 0 is copied to >2000->3FFF. The cartridge header and the code to copy is compact and located in what will become a buffer when it is in low memory. Then I branch to the rest of the loader which is now safely stored in low memory and this selects banks 1,2, and 3 and copies them to high memory.

I think it would be a problem to put headers in all 4 banks because that would corrupt the 24K of data being copied to high memory. Of course, by using 5 banks you could work around this.

Others have done this, so maybe I am missing something here?

As I see it right now, the easiest solution is to have no headers in rom. Instead, use 1 bank of grom with gpl code containing the cartridge header and enough code to select bank 0, then execute the code in rom that copies 32K from rom and starts the program.

 

 

Link to comment
Share on other sites

5 hours ago, Stuart said:

Put the cartridge header in each bank, and in the header code select the bank you want to continue running from. It then doesn't matter which bank it starts in. If you wanted to just copy the code from the cartridge banks to 32K RAM then run the program from RAM, the cartridge headers in each bank can be identical.

XB ROMs do not have a header and even if I did this the other problem is it only selects for 2 banks and adding banks to XB would fail to work.

Though this would really solve that issue, rewriting the XB ROM is not for anyone that is not willing to go slightly insane attempting it.

Link to comment
Share on other sites

6 minutes ago, RXB said:

XB ROMs do not have a header and even if I did this the other problem is it only selects for 2 banks and adding banks to XB would fail to work.

Though this would really solve that issue, rewriting the XB ROM is not for anyone that is not willing to go slightly insane attempting it.

As @senior_falcon references adding 1 bank of GROM, I would infer that this thread has nothing to do with XB ROMs.

 

1 hour ago, senior_falcon said:

I think it would be a problem to put headers in all 4 banks because that would corrupt the 24K of data being copied to high memory. Of course, by using 5 banks you could work around this.

Others have done this, so maybe I am missing something here? 

As I see it right now, the easiest solution is to have no headers in rom. Instead, use 1 bank of grom with gpl code containing the cartridge header and enough code to select bank 0, then execute the code in rom that copies 32K from rom and starts the program.

 

The trick to having a header in each bank, and not corrupting the data that wants to be copied, is to not assume that the data is squarely in a ROM bank, but that you are copying segments with a begin and end, into an address, much like an EA5... but, yes, it is more complicated.

 

If you want this for free, you can just write an EA5 program and then in the classic99 debug menu, there are tools for dumping memory into a cartridge binary. It'll interview make the cartridge and menu entry and give you the ROM to RAM copier all for free. Fred Kaal also has a module creator tool. Both will pack things in efficiently, and if you are not using all 8k of the lower ram expansion, it'll likely pack to a single 32k ROM. If it can be just ROM, then making real cartridges is far cheaper.

 

If you include a GROM, then FinalGROM99 or UberGROM become the minimum requirements for real hardware.  

  • Like 1
Link to comment
Share on other sites

Answering the original question: the 74LS377, 378, and 379 all start in an indeterminate state, as already noted. However, each chip tends to default to a specific bank on startup, so when I build boards, I verify that the board will always start in the first or last bank. This way, if your header software is in both of those banks, the board "should" always start up properly.

 

Using a single bank of GROM for your loader is definitely a viable solution, as it ignores all of the vagaries of the ROM startup bank, but it does add a complication for physical cartridges: you would need to use an UberGROM or FinalGROM cartridge board to run it.

 

Making it as a permanent UberGROM cartridge would be very interesting, and if you were trying for a good generic solution, the GROM header would always just select >6000 and execute from there. This way, one GPL startup routine would be usable for any cartridge designed to use it.

 

TI did something similar with their ROM-launching GROM (CD4326) as used in Sneggit, Early Logo Learning Fun, Crossfire, and Hopper and Funware did the same with their St. Nick GROM. Both of these examples were designed to force use of GROM, not to set bank-switching addresses, but the basic idea of a GROM controlling a ROM launch is the same.

 

  • Like 2
Link to comment
Share on other sites

2 hours ago, jedimatt42 said:

As @senior_falcon references adding 1 bank of GROM, I would infer that this thread has nothing to do with XB ROMs.

 

 

The trick to having a header in each bank, and not corrupting the data that wants to be copied, is to not assume that the data is squarely in a ROM bank, but that you are copying segments with a begin and end, into an address, much like an EA5... but, yes, it is more complicated.

 

If you want this for free, you can just write an EA5 program and then in the classic99 debug menu, there are tools for dumping memory into a cartridge binary. It'll interview make the cartridge and menu entry and give you the ROM to RAM copier all for free. Fred Kaal also has a module creator tool. Both will pack things in efficiently, and if you are not using all 8k of the lower ram expansion, it'll likely pack to a single 32k ROM. If it can be just ROM, then making real cartridges is far cheaper.

 

If you include a GROM, then FinalGROM99 or UberGROM become the minimum requirements for real hardware.  

QUOTE: "Put the cartridge header in each bank, and in the header code select the bank you want to continue running from. It then doesn't matter which bank it starts in. If you wanted to just copy the code from the cartridge banks to 32K RAM then run the program from RAM, the cartridge headers in each bank can be identical."

 

That is what he said, do you see any reference to GROM in that? 

I did not so it looked like he was talking about RAM or ROM not GROM. 

After all why would you need a copy header in each bank of GROM, WHY?

We previously were talking about headers in each bank of ROM so maybe you did not follow the conversations.

I think I better understood what was being asked than your reply to me.

Link to comment
Share on other sites

I have to confess to being a bit of an "information miser" on this topic. Here is a more full description of what I am doing:

In a P.M., tmop69 asked if it was possible to make a cartridge using multiple compiled XB programs. This could take several forms.

The main program could be a loader that lets you choose from a number of compiled programs.

It could be a long compiled program with a number of segments. Program A could run program B, which could run program C, or back to program A as necessary.

For this to be at all feasible it is very important to test the various program segments from XB to make sure everything loads as it should, values are passed as they should be, etc.

I have modified the compiler so that it now can run a compiled program from within another compiled program. Before, you had to exit the compiled program and return to XB. From there you could run a second program.

So far so good...

What I propose to do is this. Compiled code can know whether it is running from E/A or XB. So with the same line, let's say 3000 RUN "DSK1.PARTB", if the compiler was running in XB it would know to run DSK1.PARTB.

In a cart it would look at the last character which is a B and from that know to load the new program from banks 4, 5, 6, and 7. So with this method, a very large compiled program could be put together and run from XB using the disk system, or from a cart, using the banks of the cart as a rom disk.

Putting a header in each bank might be workable in this application, and since it avoids the grom then it is certainly more desirable.

How fast does the bank switch happen?

Let's say bank 3 has been selected and has this code to select bank 0

CLR @>6000

In the same memory location, bank 0 has this code:

CLR @>6000

followed by code to copy bytes from cartridge into ram.

Does the bank switch happen before the cpu comes to the next instruction?

 

 

  • Like 5
  • Thanks 1
Link to comment
Share on other sites

It looks like I will be able to put a header in each of the rom banks and still restore all the necessary code into the 32K memory using only 4 banks.

The next question is this:

How many banks need to have a header? Let's say there are 8 banks. It is easy enough to put a header in each of those banks, but is that enough? If there is a 512K cartridge, wouldn't you need to do that for all 64 banks?

  • Like 1
Link to comment
Share on other sites

Jim was saying in practice that the latches either power up to all zero bits, or power up to all 1 bits. So in practice, he suggests you could get away with the first and the last bank. But since that power up state is not a promise from the chip manufactures, in practice I ( and I believe all the bank switched ROM only carts I've seen ) put the header in all banks.

  • Like 1
Link to comment
Share on other sites

7 minutes ago, jedimatt42 said:

Jim was saying in practice that the latches either power up to all zero bits, or power up to all 1 bits. So in practice, he suggests you could get away with the first and the last bank. But since that power up state is not a promise from the chip manufactures, in practice I ( and I believe all the bank switched ROM only carts I've seen ) put the header in all banks.

How many banks are there? Do all carts have the same amount of memory? (I kind of doubt this.)

Edited by senior_falcon
  • Like 1
Link to comment
Share on other sites

4 minutes ago, senior_falcon said:

How many banks are there? Do all carts have the same number of banks? (I kind of doubt this.)

Jim makes available pcbs for a variety of EPROMs... I think the 'black' boards are typically 64k, and the 'red' boards are typically 512k, but some jumpers allow switching... 

 

The thing to do, is build your ROM to the smallest of 32k, 64k, 128k, that you need, and let the user making a physical cartridge replicate the data to fill out the size of EPROM they are using...

 

So, if you make a 32k rom, and we stick it in a 64k EPROM, we would load the EPROM with 2 copies of your 32k rom. 

  • Like 1
Link to comment
Share on other sites

8 hours ago, jedimatt42 said:

Jim makes available pcbs for a variety of EPROMs... I think the 'black' boards are typically 64k, and the 'red' boards are typically 512k, but some jumpers allow switching... 

The thing to do, is build your ROM to the smallest of 32k, 64k, 128k, that you need, and let the user making a physical cartridge replicate the data to fill out the size of EPROM they are using...

So, if you make a 32k rom, and we stick it in a 64k EPROM, we would load the EPROM with 2 copies of your 32k rom. 

 

This page might be interesting, if you have seen it before: http://www.stuartconner.me.uk/ti/ti.htm#bank_switching

Thank you Matt, that is very helpful.

  • Like 3
Link to comment
Share on other sites

Black boards have between 8K and 128K chips on them, for a maximum of 16 banks in inverted mode. Red boards have between 8K and 512K chips on them, for a maximum of 64 non-inverted banks. Yellow boards have chips between 512K and 2M, for a maximum of 256 non-inverted banks. Note that there are 128K and 256K chips in the correct 40-pin form factor for a Yellow board, but they generally cost more than their 32-pin counterparts (used on Black or Red boards) and so it makes little or no sense to use them most of the time. UberGROM boards use PLCC ROM chips from 128K to 512K, and so have a maximum of 64 non-inverted banks, like the Red boards.

  • Like 1
Link to comment
Share on other sites

The cartridge saver is almost done. It will make 4 banks, each with its own header and just enough code to select rom bank 0, then go on from there. As far as I can tell, the code should work fine, but it hasn't actually been tested yet on a compiled program. 

I don't know what happens if you have a yellow board with 512K and only load 4 banks to it. It doesn't seem practical to make a version of the cart for every possible size of memory that might exist.

 

This is much faster than the previous version. I had some insights that have really helped the performance and simplified the program.

 

CALL LOAD(-31868,0,0,0,0) tells XB not to use the expansion ram. This way I can run the XB program from VDP memory, and interestingly enough, you can still use assembly routines.

To do the CALL LOAD, you must first do CALL INIT, and then the program loads fine into vdp memory. However, if you have a reason to do CALL INIT again (I did!) you cannot just do CALL INIT because you get an error message.

The workaround for this is: CALL LOAD(-31868,1)::CALL INITG::CALL LOAD(-31868,0)

For XB 2.9, INITG does call init and also loads code for GPLLNK and DSRLNK. Then back to the XB program running in vdp memory.

 

Edited by senior_falcon
  • Like 5
  • Thanks 1
Link to comment
Share on other sites

5 minutes ago, FarmerPotato said:

A deterministic cartridge board design could use 74LS174, 6x D flip flop with clear, instead of the latch. (Clear on reset)
 

But we hardly need another standard! ROM bank headers from here on out. 
 

 

I do have a 512K board that Marc Hull and I designed that works like a standard 378 (non-inverted) Red board, but which always starts in Bank 0. We used it for the Tex Turbo cartridges.

  • Like 2
Link to comment
Share on other sites

Finally the pieces are starting to come together.

From a compiled program it is now possible to run another compiled program when running in the XB environment.

Also, you can also run a cart with compiled XB code from another cart.

Here is a quick video to show one way of using this. COMBOCART has 4 compiled carts. Essentially, it is using the cartridge rom as a romdisk.

The first cart is a compiled XB program that displays a menu.

From the menu you can choose 3 different compiled cartridges. I didn't do this, but any cart can run any other cart, so you could return directly to the menu, rather than the master title screen.

This is a very simple menu, but it would be possible to make a much fancier one with animation, attract mode, etc.

You can combine over 60 carts into one cart.

Next on the plate is to work out the details so you can have a compiled cart run another one without initializing the VDP. This would make a multi segment compiled XB program possible without losing any of the graphics.

COMBOCART.GIF.6453414e128ee4294649d0705947d1f7.GIF

Here is the menu program:


10 CALL CLEAR
20 DISPLAY AT(6,1):"COMBO OF COMPILED CARTRIDGES"
40 DISPLAY AT(18,6):"1 FOR APERTURE"
50 DISPLAY AT(19,6):"2 FOR TMLDEMO"
60 DISPLAY AT(20,6):"3 FOR 256DEMO"
70 CALL KEY(0,K,S):: IF S<1 THEN 70 ELSE IF K<49 OR K>51 THEN 70
80 ON K-48 GOTO 110,120,130
110 RUN "B"
120 RUN "C"
130 RUN "D"

I didn't have to test the menu program from XB, but if I had to do that, I would have had:

110 RUN "DSK2.PARTB"

120 RUN "DSK2.PARTC"

130 RUN "DSK2.PARTD"

and that would work the same in the cartridge.

 

 

 

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

Here is a "proof of concept" demo to show that a compiled XB program can run another compiled program from a cartridge, without messing up the graphics.

To the XB program 256DEMO, I added lines 4120 and 4121, and saved it as 256DEMOA. After printing 256 characters with unique patterns and 28 sprites on the screen, the extra lines show screen1, then a message, and then wait for a key press. Screen2 is still thee, just not displayed. Pressing a key will run 256DEMOB, the second program in the chain. This prints the program name and that we are using screen1. Then some squares and square roots are printed just to show that XB is working. Then press a key and screen2 is displayed, just as it was in line 4115 in 256DEMOA. This can be tested running in XB.

Then the 2  programs were compiled and converted to cartridges. The 2 cartridges were combined into a single cart using a new utility I wrote.

This will make it possible to combine large XB programs spanning multiple files contained in a single cart.

**256DEMOA**

4115 CALL LINK("PLAY",SCALE)
4120 CALL LINK("SCRN1"):: PRINT "We are now using screen1    but screen2 is unchanged    press any key to run part B"
4121 CALL KEY(0,K,S):: IF S<1 THEN 4121 ELSE RUN "DSK4.256DEMOB"

**256DEMOB**

10 PRINT "We are now running 256DEMOB The program uses screen 1"
20 FOR I=1 TO 15 :: PRINT I;I*I;SQR(I):: NEXT I
30 PRINT "Press any key to return to  screen2"
40 CALL KEY(0,K,S):: IF S<1 THEN 40
50 CALL LINK("SCRN2")
60 GOTO 60

CHAINTEST.GIF.c5fe97b234a51aed87114bf867b10613.GIF

 

 

  • Like 7
Link to comment
Share on other sites

  • 3 weeks later...

The latest developments in making a cartridge from a compiled program is shown in the video below. The program is very simple:

1 - It starts The Missing Link

2 - It displays a polyspiral to show that TML is active, then waits for a keypress

3 - After the keypress, the screen changes to white characters on dark blue, then waits for a keypress.(there are no characters, so the screen is just blue)

4 - After the 2nd keypress, a bitmapped image is loaded, then the program is in an endless loop waiting for "quit" The image was built into the cartridge.

 

I was thinking it might be a good exercise to compile Who's Behind the Mexican UFO's, but there is some disk access to save/load your game position that might be difficult.

CAIRO.GIF.1428bf80000e97a621d61529d5676bc0.GIF

  • Like 5
Link to comment
Share on other sites

  • 4 weeks later...

Is there a utility that will run in Windows or Windows DOS prompt that will convert Inverted rom bin files  to Non-Inverted roms bin files and vice versa ? ( Up to 32k )

 

For my purposes , I need to operate out of actual physical cartridges with roms . The non-inverted rom boards are hard for me to obtain ( always sold out ) . I do have a few spare inverted rom boards I can use on hand though . ( Uses the 74LS379 )

 

If there is an IC that replaces the 74LS379 directly , or with minor rewiring , that makes my boards non-inverting , that would be fine too .

 

Thanks .

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