how do i code for bus conflicts ?

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
how do i code for bus conflicts ?
by on (#16798)
i understand what bus conflicts are, but do not know how to code for them. i suppose it depends on the transistor logic as to what will win? logic low or logic high. so i assume the conflict would be ORed or ANDed with write and rom. (hope that makes sense)

i was using the AND but that was causing problems with mmc1, took it out and it fixed a game.

matt

by on (#16801)
I'd make the write always win (as if the conflict never happened). If you want to be accurate, freeze the system when the data written isn't the same as the data at the address :)

Busconflicts don't apply to MMC1, generally only 74161 games.

by on (#16823)
I think generaly '0' logic would win anyway, so AND both ROM value and written value would be the correct way, trough this is bad for the transistors trying to maintain the '1' value on either chip.
If you're making an emulator for developpement, you may show an error message "bus conflict at adress $xxxx" so the user knows why his game isn't working.

Also, this is normal that doesn't work with MMC1, because the chip disable the rom automatically. Only distrete logic boards (ANROM aside I think) does have bus conflicts. Nomrally this should change nothing on commercial ROMs, only early homebrew and hacked ROM should have bus conflicts.

by on (#16830)
In my emulator I have a debug check that catches bus conflicts (on relevant mappers), since their presence usually means an emulator bug.

by on (#16835)
Well, a bus conflict could happen on the following cases :

- The ROM is a hack from another mapper, and had originally no bus conflicts. The hackers didn't take care of bus conflicts, and now there is some on the new version (typically Final Fantasy II and so)

- This is a homebrew ROM and the writer did have low experience with mappers, and by reading only old doccuments, created bus conflicts without knowing what exactly they are.

- This is a homebrew ROM that during devloppement accidentally jumped/returned somewhere wrong and when the game is crashing it writes to $8000-$ffff by error (for example by putting the programm counter in RAM accidentally). Or altenativly the devlopper could have done a small error with its bus conflict table or anything like that.

- This is a commercial ROM or a fine ROM, but your emulator is emulating PRG bankswitching wrong, and creating bugs.

by on (#16836)
All I do in my NROM to UNROM conversions is just write to the rom address space in an area which holds the same value as what I'm trying to write, that way the correct value ends up on the data bus despite the conflict. In my case though it just means looking for a "1" somewhere, since I usually only need to switch banks the one time (to bank 1), which is generally easy to find at some location or another in the rom's code.

You might want to use a "lookup table" at a particular place in your rom, making it simple to know exactly where the values you want are located at. For example, using some generic NESASM-ish code:

Code:
.org $C000
.db $00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $0A, $0B, $0C, $0D, $0E, $0F


So then if you want to switch to like, bank 5, you'd just write..

Code:
lda #5
sta $C005


..and so on.

by on (#16839)
Bregalad wrote:
Well, a bus conflict could happen on the following cases :
- The ROM is a hack from another mapper, and had originally no bus conflicts. The hackers didn't take care of bus conflicts, and now there is some on the new version (typically Final Fantasy II and so)
- [etc...]

In other words, it's a ROM that does not run on a NES. Whether an emulator author wants to accommodate this is up to the author, but it's not in the realm of NES emulation anymore.

Quote:
In my case though it just means looking for a "1" somewhere, since I usually only need to switch banks the one time (to bank 1), which is generally easy to find at some location or another in the rom's code.

Heh, I had to do this when dumping cartridges that used this mapping method (and I imagine CopyNES has to do similar). Have the code scan the ROM for a compatible byte in the current bank.

by on (#16841)
blargg wrote:
In other words, it's a ROM that does not run on a NES. Whether an emulator author wants to accommodate this is up to the author, but it's not in the realm of NES emulation anymore.

Sure it runs on a NES, just not a UOROM board. It should be thought of as a hack for a UOROM-like mapper with WRAM, mirroring and more which is directly compatible with UOROM games.

by on (#16845)
Quote:
Sure it runs on a NES, just not a UOROM board.


I'll buy that, as long as it specifies this custom mapper in the iNES/UNIF file. And if it does that, then it shouldn't have any problem running on an emulator (as long as it supports this custom mapper you describe).

by on (#16846)
FyberOptic wrote:
Code:
.org $C000
.db $00, $01, $02, $03, $04, $05, $06, $07, $08, $09, $0A, $0B, $0C, $0D, $0E, $0F


So then if you want to switch to like, bank 5, you'd just write..

Code:
lda #5
sta $C005


..and so on.

It's even easier:

Code:
instruction:
  lda #5
  sta instruction+1


Further proof that iNES is a jungle, but it's the best jungle we've got:
blargg wrote:
I'll buy that, as long as it specifies this custom mapper in the iNES/UNIF file.

Yes it is possible to specify this board in one of the extensions to iNES, by saying "Mapper 2 with bus conflicts turned off". I don't know whether UNIF has a name for this board.

by on (#16848)
tepples wrote:
It's even easier:

Code:
instruction:
  lda #5
  sta instruction+1


I actually tried that just yesterday, when trying to figure out the best way to squeeze some code into a small gap in a rom. But it was one of those possibly too good to be true types of things, since I wasn't completely sure of the consequence of swapping the same page the code was executing on. So even though it worked for me on the hardware that particular time, I thought I'd suggest the more foolproof method of a table. But I'm glad to see the instruction + 1 method is apparently fine.

by on (#16849)
Quote:
But it was one of those possibly too good to be true types of things, since I wasn't completely sure of the consequence of swapping the same page the code was executing on. So even though it worked for me on the hardware that particular time, I thought I'd suggest the more foolproof method of a table.


Good to be cautious about things that might be working only due to bad luck (it wouldn't be good luck if it worked by chance, because then you'd have a nasty hidden bug!). The write for STA occurs one cycle before the read of the next instruction opcode, and the mapper hardware should respond almost instantaneously, so I think this is a solid (and elegant) technique.

by on (#16852)
Everything said in this topic has already been said in [[Bus conflict]].

by on (#16855)
I don't think of myself as some master genius of any sort, but there's always that tiny bit of letdown when one thinks of something on their own, only to realize everyone else already knew it already. lol.

by on (#16863)
The method of avoiding bus conflicts depend of what you want to do.
If you want to swap only fixed bank at fixed points, go with the "instruction+1" method.
If you want to swap variable banks, and have a function that does it instead of doing it inline, you're forced to use a table (8 bytes typically for UNROM is nothing).
You may also use this method, especially to swap CHR banks in a CNROM or whatever board :
Code:
ldy StageIndex
lda StageCHRTable,Y
sta StageCHRTable,Y

This typically represent a table containing the CHR bank to be used in each respective stage. Since this is a variable number, insted of having a second table to write over it, it is easier to just write over the original data, and if of course prevent bus conflicts.

About mapper 2 hacked ROMs, I agree that modern emulators doesn't HAVE to emulate them, because proper MMC1 versions are available, and that they do run on a NES only with a MMC1. (Yeah in theory anybody could build another mapper doing more than the UNROM mapper with discrete logic chips, but this would be nothing but a kind of simplified MMC1 emulator with discrete logic chips. One could use the non-simplified one instead).

by on (#16880)
tepples wrote:
Everything said in this topic has already been said in [[Bus conflict]].


Heh, including what Bregalad said after your comment. But not really; the Wiki page doesn't discuss the instruction timing or fact that most bus conflicts are due to NES-incompatible code hacks. There are only a couple of paragraphs on that page.

by on (#16883)
Bregalad wrote:
Well, a bus conflict could happen on the following cases :

Thanks for the explanations.

blargg: Thanks for the suggestion to summarize them to [[Bus conflict]], which I just finished. But the explanations of the timing issues should probably go in some page about bank switching in general.

by on (#16903)
tepples wrote:
Everything said in this topic has already been said in [[Bus conflict]].

(i tried to use the quote button and it doenst look as nice as everyone else's. i dont know why.)

i had read that but was just asking for more info about what logic would actually win. this kinda went off topic. thanks for the replies.

matt

by on (#16904)
mattmatteh wrote:
(i tried to use the quote button and it doenst look as nice as everyone else's. i dont know why.)


Go to your profile and make sure "Always allow BBCode:" is set yo "yes"

by on (#16908)
mattmatteh wrote:
i had read that but was just asking for more info about what logic would actually win. this kinda went off topic. thanks for the replies.

Then this acrticle on wikipedia may help you :http://en.wikipedia.org/wiki/Push-pull_output
As I mentionned above, two push-pull outputs, if one tries to pull the output high and the other to push it down, I think the push-down will rather win, because usually the output is connected to ground via a single transistor, but is connected to the supply voltage via a couple of transistors and other diode/resistors componnant, that allow more flexibility to the output voltage.