Jump to content
IGNORED

64kSC multi sprite ROMs error out in Stella (for me)


Gemintronic

Recommended Posts

I tried this from the latest 64-bit bB release (1.7), VisualbB and Stella (6.7) from a new C:\bB directory.

 

Multi Sprite 64k, Standard 64k and 64kSC compiles and runs just fine.  64kSC Multi Sprite ROMs error out in Stella citing an invalid instruction.

 

TO BE CLEAR this is most likely a Windows thing and not a bug in bB, VisualbB or Stella.  My working solution is to use Gopher2600 for 64kSC multi sprite projects.

https://github.com/JetSetIlly/Gopher2600

 

UPDATE:  Added project files.

 

64kproj.zip

Link to comment
Share on other sites

39 minutes ago, Gemintronic said:

I tried this from the latest 64-bit bB release (1.7), VisualbB and Stella (6.7) from a new C:\bB directory.

 

Multi Sprite 64k, Standard 64k and 64kSC compiles and runs just fine.  64kSC Multi Sprite ROMs error out in Stella citing an invalid instruction.

The bB multisprite kernel seems to issue ghost reads on the SC RAM write port. @splendidnut has fixed this for the multisprite_kernel and the multi-color-sprite kernel of 1942:

https://forums.atariage.com/topic/176639-1942-wip/?do=findComment&comment=5184552

 

You can try to copy the fixed version to your project directory:

https://github.com/batari-Basic/batari-Basic/blob/master/includes/multisprite_kernel.asm

 

 

 

39 minutes ago, Gemintronic said:

TO BE CLEAR this is most likely a Windows thing and not a bug in bB, VisualbB or Stella.  My working solution is to use Gopher2600 for 64kSC multi sprite projects.

https://github.com/JetSetIlly/Gopher2600

I am not sure, but maybe it is because Stella has "Trap on ghost read" active in the developer settings:
1141131713_Bildschirmfoto2023-01-09um15_11_57.thumb.png.d373cb70e0af0c0e2623d37a2aaf28b8.png

 

  • Thanks 1
Link to comment
Share on other sites

The detected bankswitching seems to be correct, but I wonder why the zeropage RAM is displayed in the "Disassembly" tab? Is Stella trying to execute code from there?

 

Maybe not all start vectors of the ROM are correct? Is "random startup bank" set in your Stella settings?

2073580562_Bildschirmfoto2023-01-09um15_38_35.thumb.png.97bc6846ca2e314a5e77925e3830a6a8.png

  • Like 1
Link to comment
Share on other sites

37 minutes ago, Gemintronic said:

 

Didn't tell anyone, but, I updated the first post to have an example project :)

Thanks. I was able to fix it by changing the first line to include multisprite_superchip instead of multisprite_bankswitch:

 

; includesfile multisprite_bankswitch.inc
 includesfile multisprite_superchip.inc

 

  • Thanks 1
Link to comment
Share on other sites

@Random Terrain - it doesn't look like the bB manual has any reference to multisprite_superchip.inc. Maybe it should be added to the section on the multisprite kernel that mentions multisprite_bankswitch.inc? It is used in the same way, and in place of (not in addition to) multisprite_bankswitch.inc.

  • Like 2
Link to comment
Share on other sites

42 minutes ago, Karl G said:

Thanks. I was able to fix it by changing the first line to include multisprite_superchip instead of multisprite_bankswitch:

 

; includesfile multisprite_bankswitch.inc
 includesfile multisprite_superchip.inc

 

 

That was it!  Thank you!

 

I don't think I saw mention of 64k support in R.T.s romsize or multi sprite section so it must be pretty new.

https://www.randomterrain.com/atari-2600-memories-batari-basic-commands.html#romsize

 

UPDATE: To be clear 64kSC seems to not need multisprite_bankswitch.inc at all.  I tested by calling a label on bank 16 from bank 1 that increments the score.

  • Like 1
Link to comment
Share on other sites

28 minutes ago, Gemintronic said:

UPDATE: To be clear 64kSC seems to not need multisprite_bankswitch.inc at all.  I tested by calling a label on bank 16 from bank 1 that increments the score.

Yeah; superchip implies bankswitching, so it covers both. For some reason it never made it into the manual though.

  • Like 1
Link to comment
Share on other sites

3 hours ago, Al_Nafuur said:

The detected bankswitching seems to be correct, but I wonder why the zeropage RAM is displayed in the "Disassembly" tab? Is Stella trying to execute code from there?

"Stella trying to execute code" would be a good assumption to make.

 

When the disassembly shows zero page addresses, that usually indicates that the PC (program counter / code address) ended up there.  This usually indicates a bad jmp/jsr or corrupted return address (corrupted stack / stack pointer) in the program.  ...I've had this happen a few times recently.

 

It's interesting that Gopher2600 ran without issues.  If you still have the bugged program, you might want to let @JetSetIlly take a look to see if something is being handled improperly in Gopher2600.

 

 

  • Like 1
Link to comment
Share on other sites

11 minutes ago, splendidnut said:

"Stella trying to execute code" would be a good assumption to make.

 

When the disassembly shows zero page addresses, that usually indicates that the PC (program counter / code address) ended up there.  This usually indicates a bad jmp/jsr or corrupted return address (corrupted stack / stack pointer) in the program.  ...I've had this happen a few times recently.

 

It's interesting that Gopher2600 ran without issues.  If you still have the bugged program, you might want to let @JetSetIlly take a look to see if something is being handled improperly in Gopher2600.

 

I've just uploaded the binary to my Pluscart and it works fine on hardware (2600 Jr in this case). So if anything, I would say the error is in Stella.

 

It's an interesting bug though and it would be instructive to understand what's causing it.

 

Does Stella have a way of outputting disassembly as it happens in sequence, as a log? It's difficult to understand the error without being able to see the instructions that led up to the invalid instruction (at PC $0f1f).

Link to comment
Share on other sites

A quick run thru in Stella shows the code go off into the woods and fall into the zeropage via a corrupted stack pointer.  It's a bit all over the place so it's hard to follow.

 

@JetSetIlly  Do you have anything in place to catch code that tries to execute from the bottom of the zeropage in the TIA register area?

Link to comment
Share on other sites

A good way of seeing where the two emulations diverge is by placing a breakpoint on 0xffdd of bank 0 The RTS instruction at that address sends execution to address 0xf000 (of bank 0) in both emulators.

 

Stella is reporting that the instruction at that address is an RTI instruction. Gopher2600 thinks this is an LDA instruction.

 

This is the block of code between $f000 and $f019 according to Gopher2600

image.png.c9b64bdb28993e24356a24469f95867e.png

 

Looking at the binary of the ROM file itself, these instructions correspond to the raw data.

 

image.thumb.png.07d0f88a3b15aa4481d86418bfcaa937.png

 

 

So I think this is a difference in the implementation of EF. I'm not sure what the correct behaviour is. I've taken the view that reading from a cartridge RAM write address will access the corresponding byte in the ROM.

 

Stella appears to be doing something different. I'm not sure where the RTI instruction is coming from but it's not coming from the ROM file.

 

 

Link to comment
Share on other sites

I should also mention that the placing of code at $f000 means that the RAM will be written to when those instructions are read. In our case, this is the state of cartridge RAM after reading the instructions between $f000 and $f019

 

image.png.4b8cec184d88c206c265ba487c53a517.png

 

(I suppose this is the reason why you should build projects with "multipsprite_superchip.inc" . I'm not really familiar with batariBasic but I'm guessing that that inc file causes ROMs to be built that don't execute code in between $f000 and $f07f)

 

  • Like 1
Link to comment
Share on other sites

4 hours ago, JetSetIlly said:

I've taken the view that reading from a cartridge RAM write address will access the corresponding byte in the ROM.

 

That's seems like an odd approach to me, reading from ROM in a designated RAM area.  I would think that reading from the write address would still be in RAM... but that's assuming that the Superchip is definitely a 128-byte RAM chip with a 7-bit address bus with the 8th bit from the Cartridge address bus connected to the R/W line of the RAM chip, and bits 9-12 doing the chip select.

 

Can you elaborate on why you chose that approach?

Link to comment
Share on other sites

6 hours ago, splendidnut said:

That's seems like an odd approach to me, reading from ROM in a designated RAM area.  I would think that reading from the write address would still be in RAM... but that's assuming that the Superchip is definitely a 128-byte RAM chip with a 7-bit address bus with the 8th bit from the Cartridge address bus connected to the R/W line of the RAM chip, and bits 9-12 doing the chip select.

 

Can you elaborate on why you chose that approach?

I haven't left any comments in the code explaining why I did this, so maybe it was just a mistake. As I said, I'm not sure what the correct behaviour is for this bank switcher but if it can be implemented in hardware with an actual superchip then what you're saying is correct.

Link to comment
Share on other sites

When accessing the write port of cartridge ram, the cartridge does not drive the data bus, as the CPU is supposed to do that with a write operation (to write data to ram).

So, if you instead try to read from the write port, nothing is driving the bus and the value read is undetermined.

Remember that the cartridge cannot differentiate write and read operations, so it behaves the same in both cases. This is the reason why cartridige ram needs separate write and read addresses.

 

The actual result of that read can change depending on the hardware in the cartridge, the specific console, temperature, interferences from nearby electrical appliances, etc.
I think on most modern implementations (Unocart, Pluscart, Melody board, etc.) you typically get the "last value on the bus", but we know for experience that in some cases consoles can (and will) behave differently, causing bugs hard to track down. Anyway, I remember testing actual superchip carts and the results were very different. It might be that either the the rom or the ram gets selected and drive the bus briefly while the address bus is not yet stabilized, but in any case, the results were not completely stable even on the few tests I did. I think that Stella returns a random, but static pattern when reading the write port, to approximate the results of those tests, and that's where that RTI opcode comes from.

 

For developing purposes, I think that a good solution is to just randomize the results in case of undriven bits, so that programmers can immediately spot errors like that and fix the code early during developmenmt.

 

 

 

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

6 hours ago, alex_79 said:

For developing purposes, I think that a good solution is to just randomize the results in case of undriven bits, so that programmers can immediately spot errors like that and fix the code early during developmenmt.

That makes sense. A cartridge putting a random/uncertain value on the data bus is something I've not considered. I always put something on the bus and for most affected bankswitchers I just generate a zero; but for EF I decided to use the corresponding value from the binary file (for some reason). In this case, it had the consequence of making the ROM appear to work correctly.

 

The question now moves to the PlusCart and why the problem ROM works there. I'll take a closer look at that later.

 

The other thing I didn't notice is that EF is effectively just a 64k standard Atari cartridge. Now that I know that I can simplify the implementation.

  • Like 1
Link to comment
Share on other sites

47 minutes ago, JetSetIlly said:

The question now moves to the PlusCart and why the problem ROM works there.

The "last value on the bus" on the next instruction after a "RTS" would be the byte at the address stored in "Stack Ptr + 1" (lsb) and "Stack Ptr + 2" (msb).


In the case of the "RTS" at $ffdd in bank 0, the address pulled from the stack is $0fff, which is the TIMINT riot register. The timer has not expired when the instruction is executed, so reading that address returns $00.

 

If, with the Pluscart, reading from the write port returns the last value on the bus, then the opcode that the CPU sees at $f000 in bank 0 is $00, that is "BRK". And there's a valid interrupt vector in bank 0 ($1fbc, the same as the reset vector). So that might explain why it doesn't crash there. (I'm just guessing, I'm currently unable to test on real hardware and won't be for a while).

 

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