Jump to content
ijor

ANTIC decap and reverse engineering

Recommended Posts

How are you guys doing these simulated waveforms?

 

Don't you see the Simulate button at the schematics? :)

 

The waveforms are producing using ModelSim, an excellent HDL simulator. They are performed with partial simulation models I extracted from the reverse engineered netlist. For quite some time I was meaning to complete and release full simulation models for the chipset. Not yet there I'm afraid, but hopefully shortly. Note that simulations models are designed to be accurate to the original behavior, usually not suitable for a modern implementation and might be even not fully synthesizable.

 

 

 

  • Like 2

Share this post


Link to post
Share on other sites

Question on this part of the schematic:

 

post-16457-0-40291500-1556177404.png

 

I'm curious about the lack of the pfDmaDis (playfield DMA disable) signal inhibiting mScanOe (memory scan output enable). In normal circumstances, pfDmaReq (playfield DMA request) is active at the same time due to both being triggered by hzDmaEn (horizontal DMA enable), so this is fine.

 

However, I think I've found an odd case where it isn't, which is the case where playfield DMA is shut off mid-scanline by clearing DMACTL[1:0]. When this happens, pfDmaDis inhibits pfDmaReq, so no playfield DMA cycles occur, but it looks like mScanOe will still activate to drive the internal address bus from the memory scan counter -- the playfield DMA clock is still running and the horizontal position is within the active region. A refresh cycle can then occur at the same time, which will also try to drive the low bits of the internal address bus from the refresh counter. It looks like this will result in a corrupted refresh row address, the bitwise AND of the memory scan counter and refresh counters. Is there some logic I'm missing to arbitrate this situation? I'm unable to determine the refresh address programmatically since nothing drives the data bus on refresh cycles.

 

Share this post


Link to post
Share on other sites

Can you get refresh addresses affecting subsequent data fetches in similar fashion to pointing Antic to a memory hole on the old 400/800?

 

(though I'm guessing you've just confirmed it as a no with the previous statements)

Edited by Rybags

Share this post


Link to post
Share on other sites

I'm curious about the lack of the pfDmaDis (playfield DMA disable) signal inhibiting mScanOe (memory scan output enable). In normal circumstances, pfDmaReq (playfield DMA request) is active at the same time due to both being triggered by hzDmaEn (horizontal DMA enable), so this is fine.

 

However, I think I've found an odd case where it isn't, which is the case where playfield DMA is shut off mid-scanline by clearing DMACTL[1:0]. When this happens, pfDmaDis inhibits pfDmaReq, so no playfield DMA cycles occur, but it looks like mScanOe will still activate to drive the internal address bus from the memory scan counter -- the playfield DMA clock is still running and the horizontal position is within the active region. A refresh cycle can then occur at the same time, which will also try to drive the low bits of the internal address bus from the refresh counter. It looks like this will result in a corrupted refresh row address, the bitwise AND of the memory scan counter and refresh counters. Is there some logic I'm missing to arbitrate this situation?

I would need to analyze, but I wouldn't be too surprised if a corner case can disrupt a refresh cycle.

 

Can you provide some sample code? Or at least a detailed "poke" sequence? I can even check for a sequence that the CPU wouldn't be able to perform, such as multiple consecutive write cycles. Or you mean just to disable playfield DMA anywhere at the middle of the scanline (and not necessarily at a precise cycle)?

Edited by ijor

Share this post


Link to post
Share on other sites

@phaeron you are correct that the mScanOe is not blocked. However this signal is moving address to the internal buffer only, not the the output pins (as @ijor kindly explained to me few responses before). The ultimate (and as far as I can see the only) signal to update physical address bus is AddrOe and in the schema on page #1 where the HALT pin is shown you can see AddrOe is parallel to HALT, only 1/2 clock delayed. As HALT is not set due to pfDmaReq not being set physical address is not updated.

 

It is hard to say if this unnecessary population of address buffer can have any side effect, but I doubt it. I would guess the buffer is meant only to keep prepared address and then wait for AddrOe signal.

  • Like 1

Share this post


Link to post
Share on other sites

I'm curious about the lack of the pfDmaDis (playfield DMA disable) signal inhibiting mScanOe (memory scan output enable). In normal circumstances, pfDmaReq (playfield DMA request) is active at the same time due to both being triggered by hzDmaEn (horizontal DMA enable), so this is fine.

 

However, I think I've found an odd case where it isn't, which is the case where playfield DMA is shut off mid-scanline by clearing DMACTL[1:0]. When this happens, pfDmaDis inhibits pfDmaReq, so no playfield DMA cycles occur, but it looks like mScanOe will still activate to drive the internal address bus from the memory scan counter -- the playfield DMA clock is still running and the horizontal position is within the active region. A refresh cycle can then occur at the same time, which will also try to drive the low bits of the internal address bus from the refresh counter. It looks like this will result in a corrupted refresh row address, the bitwise AND of the memory scan counter and refresh counters. Is there some logic I'm missing to arbitrate this situation?

I need to double check and will try to post some simulation, but seems you are right. If playfield DMA is disabled at the middle of the scan line, after playfield DMA logic was already initialized, then memory scan output might overlap refresh. There is no logic to prevent this scenario and the refresh address might be corrupted.

 

Probably RAM will tolerate a single scan line with wrong refresh cycles. But I guess that if this is performed in enough scan lines, some RAM might lost content.

Share this post


Link to post
Share on other sites

Can you get refresh addresses affecting subsequent data fetches in similar fashion to pointing Antic to a memory hole on the old 400/800?

 

Hi Rybags. Sorry, not sure I understand exactly what you want to do?

 

@phaeron you are correct that the mScanOe is not blocked. However this signal is moving address to the internal buffer only, not the the output pins (as @ijor kindly explained to me few responses before). The ultimate (and as far as I can see the only) signal to update physical address bus is AddrOe and in the schema on page #1 where the HALT pin is shown you can see AddrOe is parallel to HALT, only 1/2 clock delayed. As HALT is not set due to pfDmaReq not being set physical address is not updated.

No. Both HALT and AddrOe are enabled also on refresh cycles.

Edited by ijor

Share this post


Link to post
Share on other sites

Can you get refresh addresses affecting subsequent data fetches in similar fashion to pointing Antic to a memory hole on the old 400/800?

 

(though I'm guessing you've just confirmed it as a no with the previous statements)

 

No, not that I've been able to find. The DMACTL trick allows you to turn ANTIC into a bus monitor by having it read from the data bus into the line buffer without actually issuing read cycles. The contents of the line buffer can then be read out by repeating it with a tall mode line and scanning the output with P/M graphics collisions. This includes refresh cycles.

 

Problem is, the memory systems don't output to the data bus on refresh cycles. On the 400/800, the memory boards have a latch in between that disconnects the memory chips from the data bus. On the XL/XE systems, the MMU withholds /CAS so that the memory does RAS-only cycles and doesn't output data. On real hardware I see the same undriven bus data that you would get from $D600-D7FF, $FF on the 800XL and floating bus data on the 130XE. As far as I know there is no case where the address bus floats, so that's out for reading the counter.

 

The one case that might be interesting is trying to override the refresh addresses to deliberately exclude some rows from being refreshed. This is impractical for PAL since it has 72*9 = 648 refresh cycles that will guarantee all rows are refreshed within 15ms, probably enough for some memory to survive. NTSC only has 198 refresh cycles in VBLANK, however. Very careful jamming of the refresh cycles and use of memory addresses may make it possible to force at least one row to remain unrefreshed for a long period of time, though it would probably make 2600 programming look easy. Systems with static or shadowed RAM will also just ignore this outright.

 

I would need to analyze, but I wouldn't be too surprised if a corner case can disrupt a refresh cycle.

 

Can you provide some sample code? Or at least a detailed "poke" sequence? I can even check for a sequence that the CPU wouldn't be able to perform, such as multiple consecutive write cycles. Or you mean just to disable playfield DMA anywhere at the middle of the scanline (and not necessarily at a precise cycle)?

 

Program attached, but it sounds like you already know the sequence: wait until ANTIC starts fetching data for a bitmap row and then clear bits 0-1 of DMACTL, with horizontally scrolling set to align the PF cycles with the refresh cycles.

anticid.zip

Share this post


Link to post
Share on other sites

Program attached, but it sounds like you already know the sequence: wait until ANTIC starts fetching data for a bitmap row and then clear bits 0-1 of DMACTL, with horizontally scrolling set to align the PF cycles with the refresh cycles.

 

Yes, sorry if I made you work. Initially I thought it required some special cycle accurate trick. Then I realized that a simple write to DMACTL without strict timing was enough to provoke the behavior.

Share this post


Link to post
Share on other sites

Attached a simulation waveform of the ANTIC behavior found by Phaeron. If playfield DMA is disabled somewhere at the middle of the scanline, after DMA clock was already initialized, ANTIC might output a corrupted address on refresh cycles.

 

Disabling DMA will deassert the pfDmaReq signal immediately for the rest of the scanline. pfDmaReq normally prevents and delays refresh cycles, giving priority to playfield cycles. If this signal is forced low, refresh would not be blocked. But because the DMA clock logic is still working, there is the possibility that refresh and playfield cycles would overlap. In that case memory scan, or character pointer might still load the internal address bus on the assigned timeslots. If this happens the address bus will get the logical AND of both values.

 

Note that his happens only if DMA is disabled after DMA clock was initialized. Otherwise, as expected, there won't be any timeslots assigned to playfield for the current scanline and there won't be any overlap with refresh cycles. For the same reason the wrong behaviour lasts for a single scanline only, unless of course DMA is reenabled early enough and disabled again at the next scan.

 

The waveform illustrates a case where memory scan pointer overlaps with refresh cycles. But depending on the mode and horizontal scrolling the overlap might happen when fetching character names.

 

post-6585-0-04552500-1556300634_thumb.jpg

 

The three yellow vertical guides mark three refresh cycles, just before the external address bus is loaded from the internal bus. The LSB value is the logical AND of refAddr and Mem Scan Ptr. See also how refAdOe and mScanOe are both asserted together at the same cycle. Something that should never happen.

  • Like 4

Share this post


Link to post
Share on other sites

 

Yes, sorry if I made you work. Initially I thought it required some special cycle accurate trick. Then I realized that a simple write to DMACTL without strict timing was enough to provoke the behavior.

 

Nah, it's fine. I already had written this before checking the schematics to determine why it wasn't working as expected. Thanks very much for taking the time to run the simulation.

Share this post


Link to post
Share on other sites

Attached a simulation waveform of the ANTIC behavior found by Phaeron. If playfield DMA is disabled somewhere at the middle of the scanline, after DMA clock was already initialized, ANTIC might output a corrupted address on refresh cycles.

 

Disabling DMA will deassert the pfDmaReq signal ...

 

I think a more conceptual description of the bug (or feature) will be useful for those not as familiar with the schematics.

 

The unexpected behavior is produced because when DMA is disabled, some things take effect immediately while other things take effect only at the next scan line. The actual DMA is disabled immediately, but the assignment of timeslots for reading playfield data continues for the rest of the scanline. The consequence of this is, that at a playfield cycle, the corresponding playfield DMA address is still loaded into ANTIC internal bus. If DMA would have been enabled, a refresh cycle couldn't happen on the same cycle. But because it is disabled, nothing prevents the conflict and it's like ANTIC is attempting (partially) both a refresh and playfield DMA at the same cycle.

Edited by ijor
  • Like 2

Share this post


Link to post
Share on other sites

Bumping thread again, this time for a reset question. :grin:

 

The vertical counter shows all cells being connected to a reset signal (VcntRst) that is strobed both on line 262 and a stretched version of the master reset signal. It would make sense for the vertical counter to start from 0 on reset. However, this appears to be at odds with what I am seeing on real hardware, which is showing VCOUNT to be random both on power-up and on XL/XE reset when checked from a diagnostic cart. I've checked a few things:

  • The cart is actually running as a diagnostic cart, as CRB=0 on the PIA, and the RNMI bit 5 in NMIST is still set (probably the goofiest way yet to detect a cold boot).
  • Schematic shows that WSYNC might be random on power-up, but that would only be a scanline of delay at most.
  • Happens on 800, 800XL, and 130XE.
  • Schematics show ANTIC and 6502 receiving the same reset signal on all models.
  • Full range of VCOUNT values for NTSC is showing up ($00-82). 16ms of reset skew seems unlikely.

Is the vertical counter actually cleared on the master reset, or does ANTIC use a different edge for reset than the 6502?

  • Like 1

Share this post


Link to post
Share on other sites

If it was cleared, wouldn't that cause a vertical roll problem given that you'd almost always get a truncated TV frame?

 

You do get the occasional roll but that tends to be caused if you're at a certain part of the display when pressing Reset.

Share this post


Link to post
Share on other sites

The horizontal counter may also be reset independently, so the screen glitch probably isn't enough to infer the behavior of the vertical counter.

 

I wonder if I can count cycles since power-up with RANDOM.

Share this post


Link to post
Share on other sites

With a diag cart or custom OS you'd get control before any register clears - so you'd probably also (if not already known) be able to work out if RANDOM starts in a known state.

I guess if it didn't, wouldn't there be a strong chance of the lockup condition where all 0s or 1s persists?

Share this post


Link to post
Share on other sites

The vertical counter shows all cells being connected to a reset signal (VcntRst) that is strobed both on line 262 and a stretched version of the master reset signal. It would make sense for the vertical counter to start from 0 on reset. However, this appears to be at odds with what I am seeing on real hardware, which is showing VCOUNT to be random both on power-up and on XL/XE reset when checked from a diagnostic cart. I've checked a few things:

 

That reset, the Reset_02 signal, is not a normal standard reset. Sorry, I should have documented that at the schematics. It is some kind of power up detector and I'm not sure how reliable it is. Most power up detectors of the era weren't very reliable.

 

Reset_01 is the standard internal reset signal.

  • Like 3

Share this post


Link to post
Share on other sites

This topic goes way over my head, but it seems very exiting.

 

Do you guys see any chance this work will reveal unexplored tricks that could be utilized in demos/games?

I love tricks like stretching missiles (my jaw dropped seeing that one), shifting by half pixels, etc...

 

For example I'm hoping someone will discover a trick to fool the PM DMA to shift/offset the read address (tied to VCOUNT normally if I'm not mistaken).

 

If you wanted to describe the potentials you're currently seeing (for dummies like me) what would you say?

Share this post


Link to post
Share on other sites
19 minutes ago, Sandor / HARD said:

Do you guys see any chance this work will reveal unexplored tricks that could be utilized in demos/games?

I love tricks like stretching missiles (my jaw dropped seeing that one), shifting by half pixels, etc...

 

For example I'm hoping someone will discover a trick to fool the PM DMA to shift/offset the read address (tied to VCOUNT normally if I'm not mistaken).

 

If you wanted to describe the potentials you're currently seeing (for dummies like me) what would you say?

Pretty low, ANTIC is probably the best behaved and best known of the custom chips. So far all of the stupid ANTIC tricks I've found have been pretty useless for actual production use, besides further chip exploration or breaking emulators. POKEY is the least well known and the chip that has seen the most new interesting tricks, followed by GTIA.

 

Probably the most useful ANTIC discovery has been the scanline 247 hires bug (credit Rybags for originally bringing to my attention), which lets you use DMACTL to modify the video signal in vertical blank. The best result of this is opening the vertical border for extended P/M graphics in PAL, though it's too far in overscan for NTSC. Otherwise, interlace experiments have been mixed as you can't actually modify the horizontal timing to do proper interlace, and TVs vary in response to fake interlace. Maybe someone will come up with some interesting hack like closed captioning.

 

With regard to shifting P/M DMA, there's no direct way to do it as the chip is hardwired to route the vertical counter to the lower address bits. Thus, sneakier ways are required:

  • Using HSCROL or mode 9/10 to force abnormal playfield DMA to overlap the P/M DMA slots. This is of limited use because it burns a lot of cycles to set up and for the abnormal DMA, and the address is the AND of the playfield and the P/M DMA addresses.
  • Forcing abnormal playfield DMA in lieu of the P/M DMA slots, by also turning on P/M DMA only in GTIA. This allows DMAing into missiles and two players using playfield DMA, but still takes a bunch of cycles and trashes the other two players.
  • Fooling GTIA into false P/M DMA slots triggered by the display list fetch instead of ANTIC fetching missile DMA, and loading player 3 off the LMS high byte. Arguably useless, you can't have a playfield.
  • Fooling GTIA into false P/M DMA slots triggered by the display list fetch, then loading missiles and/or players off of _CPU_ cycles. Might be useful in limited circumstances where a kernel is already in use, since objects can be loaded for free or almost for free as a side effect of CPU read/write cycles.
  • Fooling GTIA into false P/M DMA slots triggered by a display list LMS fetch without an IR fetch. Haven't checked whether GTIA allows P/M fetch to start this late, and LMS-only fetch is also difficult as it requires either toggling display list DMA at the right time or using vertical scrolling to stretch a jump instruction.

 

  • Like 4

Share this post


Link to post
Share on other sites

The other immensely useful Antic trick, though maybe not a bug exploit and in some uses it's just following the textbook decription is the VScrol trick.

Shorter characters, longer characters, extra height for bitmap modes.

  • Like 1

Share this post


Link to post
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.

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