RAMBO-1 Mapper Investigation

Discuss hardware-related topics, such as development cartridges, CopyNES, PowerPak, EPROMs, or whatever.

Moderators: B00daW, Moderators

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Wed Feb 12, 2020 12:03 pm

I am simulating it more accurately now and I am seeing something interesting. It sure looks like my test is still screwed up but I thought I would share in case it triggers any ideas for you. The green channel inverts each time I start a new scanline. I am probably off by a scanline, either that or they somehow are reloading right before the IRQ, which doesn't really make sense.
zoom.png
overview.png

Edit:
I had not implemented pre-render scanline 261 correctly. It now makes more sense:
tek00024.png


Edit 2:
Focusing on this example, where it writes $04 to $C000:

Code: Select all

Scanline | PA12 | PPUCycle | Event
---------+------+----------+---------------
241      |   1  | 28       | NMI
258      |   0  | 261      | $C000=$BC
258      |   0  | 279      | $C001=$00
258      |   0  | 291      | $E001=$00
188      |   1  | 295      | IRQ
188      |   0  | 304      | $E000=$00
189      |   0  | 44       | $E001=$00
189      |   0  | 62       | $C000=$04
193      |   0  | 288      | IRQ
193      |   0  | 297      | $E000=$00
194      |   0  | 133      | $E001=$00
194      |   0  | 151      | $C000=$17
217      |   1  | 303      | IRQ
217      |   0  | 312      | $E000=$00
241      |   1  | 24       | NMI
I bumped this write later and later until it didn't use the new value. I found this:

Code: Select all

                       _______     _______     __
PA12 __________________|     |_____|     |_____|
      ^                 ^     ^
      |                 |     +----After first falling edge PA12 (NOT using new value)
      |                 +----------After first rising edge PA12 (still using new value)
      +----------------------------PPU cyc 62 (uses new value - original example)
I ensured that there was always a small delay after changing PA12 to avoid any potential race condition. I.e. PA12 was definitely high, followed by a delay, before writing to $C000 in the middle test result.

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Wed Feb 12, 2020 3:13 pm

Scopeshots:
orig.png
after first rising edge.png
after first falling edge.png

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Thu Feb 13, 2020 4:49 pm

Latest text description, untested, but now at least considering this behavior where you can use a new reload value right away. It is not narrowed down to the IRQ being ACKed enabling this ability, that is still unknown what exactly opens the doors to make that immediately writable -- I just know that the door closes after the first falling edge of PA12. In addition, I do not know if the falling edge of PA12 itself triggers it or if it is actually M2 edge triggered with PA12 as an input. Lots to be carefully thought about and narrowed still, but we have made a step in the right direction finally.

Of the 4 main bullets in the M2 falling edge, there are conflicting statements there. I do not yet know which precedence or hierarchy these go in. It is now harder to avoid having an 8-bit comparison happening, but I think it is still valid for that to be a goal. I changed the 8-bit counter to an up-counter which is a step in the wrong direction from that goal. Lots more work to do here.

On M2 falling edge:
  • If PA12 = 0:
    • If 4-bit counter < 16: 4-bit counter++.
    • else keep the same value.
  • If PA12 = 1:
    • If 4-bit counter = 16: Clock the 8-bit counter. (see below)
    • Always reset 4-bit counter to 0.
  • If writing to $C001 (reset):
    • Clear 8-bit counter
    • Set 4-bit counter to 17.
  • If writing to $C000 (reload value):
    • If 8-bit counter = 0: Also reload 8-bit counter with new value being written to $C000
    • Do not reset the 4-bit counter, but do count it as an M2 cycle for that counter.

On 8-bit counter clock:
  • If value = $C000:
    • If IRQ is enabled, trigger IRQ (wait 1 more cycle before doing that though, regardless of PA12 next cycle...)
    • Always clear 8-bit counter.
  • Else value++.

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Fri Feb 14, 2020 2:42 pm

New drawing, definite progress being made understanding this thing.

The work I did before without toggling PA12 within each scanline turns out is still very valid information. It is not necessary to toggle it for the info I was looking for. It takes 1 M2 cycle with PA12 high to detect entering the sprite area of the scanline, and 16 M2 cycles with PA12 low to detect exiting it the sprite area of the scanline. So, filling it in with PA12s all high vs. toggling doesn't end up entirely invalidating that information.

I found that the unlocking of the reload is not anything triggered by writing to a register. The concept in the 2nd state machine in the diagram shows that it will constantly be loading the value from $C000 into the 8-bit counter each M2 cycle until that state becomes locked. This can explain the ability to "directly" write the 8-bit counter in this condition.

Note that in this diagram, the counters and state machines have a few references to each other. Since everything is clocked from M2, this means that the existing state resulting from the previous M2 cycle is used for this reference -- not the next state resulting from the present M2 cycle being considered. It gets me every time. Therein explains the "next cycle" / "1 cycle late" stuff we have known about with IRQ, and just demonstrated in the previous scopeshots with the locking of the 8-bit reload 1 cycle later than we might expect, etc.
state_machine.png


Edit:

I am not sure if this explains the +1 scanline anymore, I still have to think about that versus my older observations.

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Mon Feb 17, 2020 9:53 pm

Just a quick update,

I updated the A/B/C1/C2 simulator from before with the 3 state machine / 2 counter idea from the previous diagram I shared. I don't understand how yet but it does usually get the extra scanline correct when doing the A/B/C1/C2 test. I have at least 2 A/B/C1/C2 combinations that do not match the chip. For example, 10/10/15/15 gets an extra scanline before the IRQ on the chip but not in the simulator. I understand that the A/B/C1/C2 test is not realistic and might not even make much sense, but if the diagram matches the chip, it should give the same answer, so the fact that it doesn't means it is valuable. Whatever I am doing in that test gets it to hiccup in a different way.

Also, one detail I did not share about the scope shots. In those tests, when I got to the sprite area, I toggled PA12 for each M2 cycle. So that is not exactly a perfect test but I thought I should clarify that. So, PA12 rose the first time, followed by an M2 cycle, then PA12 fell, followed by another M2 cycle. And it was that 2nd M2 cycle where, if it was a write to $C000, was no longer allowed to take immediate effect. I think there is still something there not captured in my diagram because the way I drew it, it gets locked following that first M2, which is good. But if $C000 was written at the first M2, the 8-bit counter would not get reloaded until the 2nd M2, which is expressly forbidden by the statement "reload 8-bit counter if 8-bit reload unlocked". Almost as if the unlock needs to jump through another state before becoming truly locked... I will try adding an additional state there to the simulator tomorrow and see if it makes any improvement.


Edit:
Alternatively, I could try making the 8-bit counter's reload asynchronous/transparent (i.e. not waiting for M2).

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Wed Feb 19, 2020 4:08 pm

I got sort of stuck the way I was looking at this with the A/B/C1/C2 test. The problem with that test is that it runs through many loops before giving a result, so anything within the whole loop could propagate to the result, making it very difficult to debug. So I started a new type of test that does a 1-shot from power on. The challenge here (or possibly benefit?, see below) is that you start with a random state.

1-shot test:

Power on: PA12 = 0, wait 3.6msec
- Write 00 to E000 (IRQ Ack / Disable)
- Write 01 to C000 (Reload value)
- Write 00 to C001 (Set IRQ mode to scanline counter mode)
- Write 00 to E001 (IRQ enable)
- Goto [X]
[X]
- PA12 = 0
- Do A1 dummy reads
- Goto [Z]
[Y]
- PA12 = 0
- Do A2 dummy reads
- Goto [Z]
[Z]
- PA12 = 1
- Do B dummy reads
- Loop to [Y] 20 times (i.e. trigger 20 scanlines)
- After 20 times, stop test, examine waveform triggered on scope.


Results from these values:
A1, A2, B, result
20 20 10 3
20 20 1 3
16 16 10 3
15 15 10 Never
14 14 10 Never
12 16 10 3
11 16 10 3
1 16 10 3

Result=3 means IRQ went low on the 3rd time I got to [Z]. Since this is a power-on test, the internal state machines may come up in any random state. I find that in some cases I get a 2 on at least some of these tests. However, I found no combination that made it ALWAYS 2. It proves that writing to all 4 registers E000, C000, C001, E001 in itself is not enough to completely initialize all of the scanline state machines into known states.

I modified the test as follows:
Insert 514 dummy reads before the register writes. No change.

I then removed that modification and did a different modification as follows:
Before writing to any of the registers, set PA12 = 1, delay, do a dummy read, set PA12 = 0, delay, then proceed with the normal test. Always the result is 2 scanlines with this modification. To me, this change represents entering sprite region, so it suggests that the 8-bit counter reload can only be unlocked from within sprite region. I made this change on the state diagram.

I then added to this test an additional 20 dummy reads like this:
Before writing to any of the registers, set PA12 = 1, delay, do a dummy read, set PA12 = 0, delay, [20 DUMMY READS], then proceed with the normal test.
I still get result = 2 scanlines when doing this, even though this test will have returned to background region before writing to the registers. So 8-bit reload remains unlocked even when entering background region. We already knew and are again confirming that PA12 must be 1 (i.e. re-enter sprite region) in order to lock out the 8-bit reload.

Since there are now 2 inter-dependencies between the sprite/background state machine and the lock/unlock state machine, I merged them into 1. They are still functionally the same, just providing 2 different ways of looking at it. This is another incremental progress but not finished and not tested enough yet.
merged.jpg

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Fri Feb 21, 2020 10:55 am

I am running into a lot of dead ends with this lately. I thought I would put together a list of knowns and unknowns:

What is considered a scanline:
- There is an internal counter that counts scanlines. It is considered a scanline if it steps this counter.
- It is very likely but not exactly proven that the counter is clocked from M2.
- PA12 = 1 indicates a sprite tile fetch, PA12 = 0 background tile or nametable fetch.
- PA12 = 1 theoretically triggers sprite area detection right away, since this spot marks the last clock where a write to $C000 can take effect for the next IRQ.
- Approx. 16 consecutive M2 clocks with PA12 = 0 is theoretically triggers background area detection.
- It is not known if the scanline counter steps on the transition from sprite mode to background mode, or the transition from background mode to sprite mode. It is presumably happening at, or 1 cycle after, one of those 2 points.

Initialization:
- "Inconsistent initial state" refers to usually an extra scanline before the first IRQ, but sometimes not an extra scanline.
- PA12 must be high during an M2 clock for the scanline counter to get into a consistent initial state (no extra scanline before the first IRQ).
- PA12 high during M2 clock can be the very first M2 clock at power on, before writing to any registers.
- PA12 high and back low without clocking M2 does not affect the inconsistency; M2 clock is required.
- PA12 never high but 514 M2 cycles before writing to all registers C000, C001, E000, E001 before proceeding does not consistently initialize.
- An additional 20 M2 cycles with PA12 low after writing to the registers has no effect on IRQ, it remains consistent with no more or fewer scanlines. (This represents a transition back to background mode.)

Reload:
- The value written to C000 is loaded separately into an internal counter because IRQs can loop with the period specified by C000 without rewriting C000.
- Normally, IRQ will occur in the C000 value +1 scanlines, and in some cases +2 when writing to the registers normally. This is confused by the fact of the prerender scanline on real hardware triggering an extra count.
- When not reloading, IRQs happen with a period EQUAL to the number of scanlines specified, i.e. +0.
- If C000 is written at the time of IRQ, it may be written at any time up to and including the first M2 clock with PA12 = 1 to take effect on the next IRQ.
- If C000 is written after the first M2 clock with PA12 = 1, the next IRQ will still use the previous C000 value, and then subsequent IRQs will use the new value written here.
- Automatic reload from the C000 value, triggered when the internal counter reaches 0.
- It is not known if the reload happens repeatedly for every M2 cycle for a period of time, or if it happens just at just 1 specific point in time.
- If value zero causes immediate reload, there must also be a state machine latching reloadability because C000 remains writable per above statements.
- If value zero causes reload specifically at transition from background to sprite, a separate state machine tracking this may not be necessary.

IRQ:
- IRQ can only go low on the next M2 clock, regardless of PA12, after an M2 clock with PA12 = 1.
- IRQ can only go high by writing to $E000 (IRQ disable).
- Writing to $E001 does not cause IRQ to go high.
- If IRQ is looking for value zero in the internal scanline counter, it is complicated by the fact that enabling IRQ before a value gets reloaded does not cause immediate IRQ to go low. Therefore, reload and the IRQ decision can't both happen at the same time, i.e. transition from background to sprite modes. Unless there is a separate state machine involved, or counting 2 triggers to the IRQ before really doing an IRQ low, etc. So that gets overly-complicated there.
- Clearing the IRQ has no apparent effect on scanline counting. If you let it auto-reload and just keep clearing and reenabling IRQ, it does not matter when or where you clear. The actual period of the scanline causing IRQ remains the same regardless if you left IRQ low for a few extra scanlines before resetting it.

Writing to $C001
- This is known to have some sort of reset characteristic.
- It seems that the present number of scanlines being counted can be aborted when writing to this, and forcing IRQ to happen earlier or later than originally planned.
- It is not known if there are blacked-out areas where this register can't be written to cause a reset.
- It is not known if this register directly reloads the internal 8-bit counter, clears the internal counter causing it to naturally have a reload later, or operates in some other way, possibly with its own state machine.
- It is not know if writing to this register affects the count-to-16 for background area detection.
- $C001 write can't fully initialize the scanline counter (see initialization section).

FrankWDoom
Posts: 191
Joined: Mon Jan 23, 2012 11:27 pm

Re: RAMBO-1 Mapper Investigation

Post by FrankWDoom » Fri Feb 21, 2020 1:26 pm

Most of this is over my head but it's fascinating to follow along anyway. Thanks for putting in the work.

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Fri Feb 21, 2020 1:36 pm

FrankWDoom wrote:
Fri Feb 21, 2020 1:26 pm
Most of this is over my head but it's fascinating to follow along anyway. Thanks for putting in the work.
Thanks, Believe me, it is over my head too...

I found something interesting. I made my test do a write instead of a dummy read specifically at the exact cycle that makes IRQ go low. If I write to $C001(reset/scanline mode) or $E000(disable IRQ) for this specific cycle, it DOES prevent IRQ going low, even though IRQ doesn't care about PA12 in that cycle. Writing to these addresses does not prevent IRQ low:

E001 (enable IRQ), C001 (reload, also with larger reload value), A001 (the missing register), A000, 8001, 6000, 4001, didn't test any others.


Edit:
Scopeshots:

Normal scanline IRQ: Writing FF to $0000 (FF lasts a while due to data bus going Hi-Z after write)
write FF to 0000 - normal IRQ.png

Write FF to $C001 in the same cycle where IRQ would have happened:
write FF to C001 - prevents IRQ.png

Edit 2:
I got a little excited for a second there, actually writing FF to C001 put it into M2 cycle counter mode instead of scanline mode, that explains where M2 went low at an unusual spot in that screenshot. When writing $FE instead, it went low after C000+1 BG->sprite transitions, no surprises there.


Edit 3:
This is actually a really great discovery because it makes us think about what gets triggered on the rising edge of M2, and what gets triggered on the falling edge of M2. I had not thought about it at that level yet, I was only considering everything happening at the same time, once per cycle.

User avatar
Ben Boldt
Posts: 491
Joined: Tue Mar 22, 2016 8:27 pm
Location: Minnesota, USA

Re: RAMBO-1 Mapper Investigation

Post by Ben Boldt » Fri Feb 21, 2020 6:42 pm

It looks like PA12 is checked on falling edge of M2:
rising edge.png
falling edge.png

IRQ rises on rising edge M2 (due to disable IRQ register write):
irq_rise.png

IRQ falls on falling edge M2 due to scanline interrupt:
irq_fall.png


Known edges so far:

Falling Edge M2 triggered:
  • PA12 high to enter sprite region
  • IRQ going low
Rising edge M2 triggered:
  • Register writes
  • IRQ going high due to register write
Unknown edge M2 triggered:
  • PA12 low to increment 4-bit counter (I think that's testable with a bit of work, i.e. set PA12 high momentarily for all rising edges of M2 and see if it makes any difference, also low for all rising edges to be complete)
  • lock vs. unlock reload (if that is an actual independent function as I have described it -- that one is still only a theory)
  • clocking of the 8-bit counter
  • reloading of the 8-bit counter


Edit:
I did the test with PA12 always high for every M2 rising edge. It works the same, but hard to show a scope shot of it. So, PA12 is only ever looked at during falling edge M2.

Post Reply