Jump to content
phaeron

Acid800: An Atari test suite

Recommended Posts

<p>

Oops, good catch -- I'll fix that. This issue is the reason that the test falls back to command $00 if the sector 0 read succeeds, btw.

 

 

 

No, OS A/B handle this fine as they check for the absence of the reset NMI rather than the presence of the VBI.

Outch, then this is a bug in Os++ (my own).
Word from the C64 camp is that $0B is sensitive to the data bus -- it appeared to be stable on Ataris from what I've seen, but I could easily disable that part of the test. Acid800 doesn't test $2B. Are you seeing at least deterministic results?

No, I'm not. This is exactly the problem - 0B is not deterministic here. I tried to find out what it does, but it is not the "AND + ASL" combination everyone believes it to be. What is deterministic is that N and C flags "correlate" (are identical), and X,Y stay constant, and it is taking two bytes (one immediate operand). Result in A seems to be one of two cases here.
I'd recommend still emulating these instructions even if they are unstable, as a real 6502 still runs a deterministic number of cycles and instruction bytes. Quite a number of games accidentally run garbage for short amounts of time even though they don't intend to or use the results and signaling a crash would definitely be an emulation bug.
I've not seen such games then. What I've seen are games that (intentionally) run some of the known "no operation" instructions for copy protection purposes. Blue Max comes to my mind. The other unstable instructions I haven't seen in real life.
The effect is easier to see with the attached test program. What I see on my 800XL and 130XE is that when switching between 2x and 4x sizes, the construction of the shift clock register results in uneven timing for when the shift register begins clocking at the new rate. Haven't heard of a failure on this yet, even with PAL GTIAs, although if you're seeing something different on your hardware I'd be interested in that.

Well, two things: First, I'm not saying that your test fails on my hardware, just that I don't know yet. All I can say is that the tests I did on my hardware coincide with what my software does, though the software still fails this very test.

 

Second issue is the SIZEP0 writing. I'm not saying that the "shift register lock-up" happens for 4x to 2x switching. It happens (at least) for 4x to 1x switching, where, however, 1x is expressed by the value 2. Whether that's special to my machine I do not know.

 

Greetings,Thomas

Share this post


Link to post
Share on other sites

Yes, it's a standard brand "Sally" in a PAL 800XL. Must be one of the earlier models, chips still have all sockets. "Made in Hong Kong".

 

Please take a photo of mainboard.

Share this post


Link to post
Share on other sites
With a bit of luck, one can even enforce GTIA to continue generating data for the player and disabling the shift register alltogether, thus extending the player to all the far right. The bits are then of course simply replicated and no "pattern" can be generated by this. This seems to happen when switching to SIZEP0 3 (4x extension) to SIZEP0 2 (not zero!) which is "officially" simply a 1x extension, but somehow does to seem to do something different.

That is awesome! Can I have sample code, please? Does it work with missiles as well?

 

Share this post


Link to post
Share on other sites

Happy New Year to everybody here!

 

Back to the tests, there are two issues on the table, namely "extra instructions" aka "illegal instructions" and the serial timing.

 

I tested now the remaining set of the xB familiy of instructions and found a couple more that do not always work as indicated on my hardware. We already had opcode 0B on the list, the immediate AND + ROL combination, which sometimes does not generate a result. Actually, the same holds for 4B, the AND plus LSR combination, and CB, the AND + CPX combination. There is no clear way how to reproduce this, but sometimes these instructions do not set their result and forget to load the register with the final result, which is then just unchanged. It is interestingly not deterministic. What might probably happen is that there is some internal race in the CPU and sometimes one unit wins, sometimes the other. The AND is problably a result of an internal conflict of the lines on the internal data bus of the CPU, and this not necessarily goes well on all produced units. Again, this is an out of the box "sally" CPU, nothing special about it. This instability seems to be a problem of the whole xB instruction family, though I haven't seen (or at least, wasn't able to observe) any defects from the other members so far.

 

Second, serial port timing. I checked the direct IO in the test, and if my computations are correct, the test code seems to wait just a tad too long for the first bit. I understand that the code, after having detected the start bit, should wait 1 1/2 bits to sample at the middle of all subsequent bits, but the time period the code waits to read the first bit seems to be just a little bit too long. It might go well on real hardware by pure chance, but it samples so close at the end (and not the middle) of the next bit that it goes wrong in the emulation. I can "fix" this by extending the start bit by another half bit, something which unlikely happens in reality, but that doesn't seem to be a good model. Maybe my computations are a bit off, but that they are for more than 1/2 bit off I wouldn't quite believe.

Share this post


Link to post
Share on other sites

may I ask you to take a picture of mainboard?

 

Attached. As said, it's an early 800XL (Rev A it says). I also include a separate picture of the CPU for your convenience. The adapter to the upper right is just a replacement of the built-in BASIC. The machine came with a buggy Rev-B Basic which crashed a lot. I burned my own Rev.C BASIC, though the standard 2764 EPROMS do not quite fit into the pin-out of the motherboard. What you see there is just a tiny adapter to make the pins fit.

 

The machine came with the wires you see to the right near the keyboard adapter.

 

Greetings,

 

Thomas

post-17768-0-29094100-1357066081_thumb.jpg

post-17768-0-22212000-1357066109_thumb.jpg

Share this post


Link to post
Share on other sites

That is awesome! Can I have sample code, please? Does it work with missiles as well?

 

I do not know whether this works for missiles - I haven't tried. But it would be quite a bit more useful indeed (especially as missiles mix with Gr.9 and Gr.11 as player 4, regular players don't.).

 

Here is the code - should hopefully work, I recontructed from memory (no disk drive for the Atari right now):

 

10	   .OPT OBJ
20	   *=  $6000
30	   LDA #$7C
40	   STA $D000
50	   LDA #$FF
60	   STA $D00D
70	   LDA #$34
80	   STA $02C0
90	   LDA #$00
100	  STA $022F
110	  LDY #$02
120 LOOP: LDA #$03
140	  STA $D40A
150	  STA $D008
160	  LDX #$0B
170 WT:
180	  DEX
190	  BNE WT
200	  STY $D008
210	  JMP LOOP

 

As said, it is pretty much obvious switching from 4x to 1x, but 1x is expressed with the value 2.

  • Like 1

Share this post


Link to post
Share on other sites

Happy New Year to everybody here!

....

 

As an extension to this, the "hardware manual" should probably be extended concerning the two-tone mode. What I see there doesn't quite fit to reality. First, the two-tone mode does of course make a difference to the audio output, and thus changes the audio system. I could reproduce the effects of the two-tone output - in the sense that channel 2 must have a larger period than channel 1, and in the way that the serial output modulates the audio output.

 

The model I have is quite simple: an underrun of timer 2 resets timer 1, and an underrun of timer 1 resets timer 2, but only if the serial output is one.

 

This keeps both channels in sync by itself, it also ensures that the timer with the smaller period usually wins. It does not require an additional "switch" between the channels which is triggered by the serial output - the serial output just changes the synchronization of the channels.

Share this post


Link to post
Share on other sites

I tested now the remaining set of the xB familiy of instructions and found a couple more that do not always work as indicated on my hardware. We already had opcode 0B on the list, the immediate AND + ROL combination, which sometimes does not generate a result. Actually, the same holds for 4B, the AND plus LSR combination, and CB, the AND + CPX combination.

 

I'll run some tests on my hardware and see if I can spot some nondeterminism. That these haven't been flagged as unstable in C64 docs makes me suspicious. The $CB opcode in particular is thought to be stable on Atari and is definitely used in demos so this is worrying.

 

Second, serial port timing. I checked the direct IO in the test, and if my computations are correct, the test code seems to wait just a tad too long for the first bit. I understand that the code, after having detected the start bit, should wait 1 1/2 bits to sample at the middle of all subsequent bits, but the time period the code waits to read the first bit seems to be just a little bit too long. It might go well on real hardware by pure chance, but it samples so close at the end (and not the middle) of the next bit that it goes wrong in the emulation. I can "fix" this by extending the start bit by another half bit, something which unlikely happens in reality, but that doesn't seem to be a good model. Maybe my computations are a bit off, but that they are for more than 1/2 bit off I wouldn't quite believe.

 

This is the timing of the test in Altirra (in machine cycles):

 

T+0 | A=10 X=00 Y=3C | 2188: 2C 0F D2		 BIT SKSTAT
T+4 | A=10 X=00 Y=3C | 218B: D0 FB			 BNE $2188
T+6 | A=10 X=00 Y=3C | 218D: 8D 09 D2		 STA STIMER
T+10 | A=10 X=00 Y=3C | 2190: A9 01			 LDA #$01
T+12 | A=01 X=00 Y=3C | 2192: 8D 0E D2		 STA IRQEN
T+16 | A=01 X=00 Y=3C | 2195: A0 5A			 LDY #$5A
T+18 | A=01 X=00 Y=5A | 2197: 8C 00 D2		 STY AUDF1
T+22 | A=01 X=00 Y=5A | 219A: 2C 0E D2		 BIT IRQST
T+26 | A=01 X=00 Y=5A | 219D: D0 FB			 BNE $219A
+ Last 2 insns repeated 3 times
T+49 | A=01 X=00 Y=5A | 219F: 8E 0E D2		 STX IRQEN
T+55 | A=01 X=00 Y=5A | 21A2: 8D 0E D2		 STA IRQEN
T+60 | A=01 X=00 Y=5A | 21A5: 2C 0E D2 main.bitloop BIT IRQST
T+65 | A=01 X=00 Y=5A | 21A8: D0 FB			 BNE main.bitloop
+ Last 2 insns repeated 11 times
T+149 | A=01 X=00 Y=5A | 21AA: AC 0F D2		 LDY SKSTAT
T+153 | A=01 X=00 Y=67 | 21AD: 8E 0E D2		 STX IRQEN
T+157 | A=01 X=00 Y=67 | 21B0: 8D 0E D2		 STA IRQEN
T+161 | A=01 X=00 Y=67 | 21B3: 8C 08 34		 STY $3408
T+166 | A=01 X=00 Y=67 | 21B6: CE B4 21		 DEC $21B4
T+174 | A=01 X=00 Y=67 | 21B9: 10 EA			 BPL main.bitloop
T+178 | A=01 X=00 Y=67 | 21A5: 2C 0E D2 main.bitloop BIT IRQST
T+183 | A=01 X=00 Y=67 | 21A8: D0 FB			 BNE main.bitloop
+ Last 2 insns repeated 7 times
T+238 | A=01 X=00 Y=67 | 21AA: AC 0F D2		 LDY SKSTAT
T+242 | A=01 X=00 Y=77 | 21AD: 8E 0E D2		 STX IRQEN
T+246 | A=01 X=00 Y=77 | 21B0: 8D 0E D2		 STA IRQEN
T+250 | A=01 X=00 Y=77 | 21B3: 8C 07 34		 STY $3407
T+254 | A=01 X=00 Y=77 | 21B6: CE B4 21		 DEC $21B4
T+260 | A=01 X=00 Y=77 | 21B9: 10 EA			 BPL main.bitloop
T+263 | A=01 X=00 Y=77 | 21A5: 2C 0E D2 main.bitloop BIT IRQST

 

I don't have a precise way of checking the timing on the real hardware so all I have to go on there is that so far it works with an SIO2PC-style cable. In the emulator, it samples a little bit late, but not too much -- about one-half to two-thirds into the data bit, with about 30 cycles of margin. This should be more than enough to be reliable under emulation. What kind of timing are you seeing in Atari++?

 

This code does rely on some timing tricks with POKEY timer #1. In particular, it requires precision in STIMER timing and correct behavior when the AUDF1 register is changed without resetting the timers. If you look at the code above, you'll see that what it is actually doing is hitting timer with the initial half-bit AUDF1 delay and then changing AUDF1 to the full-bit delay without hitting STIMER again. This is so that POKEY starts counting off full bit intervals precisely after the half-bit interval.

 

As an extension to this, the "hardware manual" should probably be extended concerning the two-tone mode. What I see there doesn't quite fit to reality. First, the two-tone mode does of course make a difference to the audio output, and thus changes the audio system. I could reproduce the effects of the two-tone output - in the sense that channel 2 must have a larger period than channel 1, and in the way that the serial output modulates the audio output.

 

The model I have is quite simple: an underrun of timer 2 resets timer 1, and an underrun of timer 1 resets timer 2, but only if the serial output is one.

 

Whoops, I'll correct the manual. The description there matches the incorrect logic in Atari's Hardware Manual and not the actual hardware (and what Altirra emulates). The logic that you have is correct.

 

One gotcha: you need to make sure that the forced space bit (SKCTL bit 7) also affects this. Acid800 does not test this yet, but there was a music player that used it to hold down the serial output so that timer 2 always preempted timer 1.... too bad I don't remember which one it was off-hand. Might have been the one that showed a scrollable rendition of the first level of Super Mario Bros 3.

Share this post


Link to post
Share on other sites

When you get a chance, try this program on your real hardware:

 

sbx2.zip

 

It is a port of the VICE test program for SBX ($CB) to Atari 8-bit, and runs through 64M permutations of inputs (A / X / imm / flags). The program prints out dots as it goes and an 'F' if a failure occurs; it exits on success. It'll take about 20 minutes to run, but it works on my 130XE.

Share this post


Link to post
Share on other sites

When you get a chance, try this program on your real hardware:

 

sbx2.zip

 

It is a port of the VICE test program for SBX ($CB) to Atari 8-bit, and runs through 64M permutations of inputs (A / X / imm / flags). The program prints out dots as it goes and an 'F' if a failure occurs; it exits on success. It'll take about 20 minutes to run, but it works on my 130XE.

 

Sorry, found this too late. I'm currently not in reach of my XL, and I won't be able to access it for the next months, I afraid. Besides, it would be a major headache of getting it over to the system. If you have a *short* source code, I can type that in, using Mac/65, but that's about it.

Share this post


Link to post
Share on other sites

A related question to the test. There is something I really do not understand about the player overlay test (and the "Hardware manual", which is just confusing because it uses different units for the location of the write happening to PMPos, and the position of the player).

 

Anyhow, in "Pass 3" of the test I get a failure here. Player 0 is moved from location $60 to location $65, and no collision is detected even though the test assumes one.

 

Now, here is what I see: The coordinate system I use are "half color clocks from the first slot of GTIA", thus position = 0 is cycle #16 (first GTIA cycle here). The relation between this coordinate system and the player-missile position is

 

clock_pos = (gtia_pm_pos - 32) * 2

 

thus the player is moved from hcc #128 to hcc #138 (both numbers in decimal) in this coordinate system. The player size is x4, and graphp0 is 0x81. Thus, the old player data before the move is in hcc's [128,136) and [184,192). (Player width = 4x8 color-clocks = 64 hccs).

 

After moving it, player data is in [138,146) and [194,202).

 

The move itself happens at hcc #124 (cycle #47 from the start of the Hblank - remember, GTIA starts at cycle #16), but that is not relevant to the argument.

 

Now, missiles for player location detection are at hcc positions [176,184), which are GTIA P/M positions $78,$79,$7a,$7b.

 

This area does neither overlap with the *old* nor with the *new* player graphics area. Nada, nothing. Thus, regardless of whether the player is at the old position, or at the new position, it should not collide.

 

Yet, the test expects it to collide.

 

So what is going on here?

Share this post


Link to post
Share on other sites

This area does neither overlap with the *old* nor with the *new* player graphics area. Nada, nothing. Thus, regardless of whether the player is at the old position, or at the new position, it should not collide.

 

This is the false assumption. The output of GTIA is not the superposition of the graphics at the old and new positions. It is the superposition of the new shift state on top of the old shift state. This is different for 2x and 4x widths.

 

This is what the P/M overlap test is doing:

 

post-16457-0-36506700-1357878799_thumb.png

 

You can see the output of the player shifter and the detection missiles sweeping over the output. Note the serrated edge on the right side of the original sprite data. This occurs because the retriggering of the player's shift register results in the same data being re-merged into the shifter but also a change in the shift timing. The result is that the original data that was already in the shift register is shifted over sooner than it would otherwise. Each player only has a single 8-bit shift register, and therefore it is not possible for that player to be shifting out overlapping data in 4x width at two different sub-pixel offsets simultaneously.

 

This is the post I originally made about this behavior:

http://www.atariage....50#entry2522917

 

The source file gtia_pmoverlap.s contains the verification data for this test, and it is literally just the image you see above cut into vertical byte-wide strips. I've written it in binary, so it shouldn't be too hard to read.

Edited by phaeron
  • Like 2

Share this post


Link to post
Share on other sites

This is the false assumption. The output of GTIA is not the superposition of the graphics at the old and new positions. It is the superposition of the new shift state on top of the old shift state. This is different for 2x and 4x widths.

 

 

Sorry, but this is too brief to me to follow you. I would simply assume that each player has an output shift register (clear enough) that is either clocked by the color clock, half the color clock or one fourth the color clock to generate the output pixels. Setting the position would then reset the shift register to its initial value, i.e. load the pattern into the shift register, and restarting the shifting process as soon as the horizontal position matches.However, you say that this is not the case. What is the "shift state"?Thus, please let's make two cases: The player position is written to after the shift register is empty. I believe this should simply work as the above.The tricky case happens if the player is retriggered to a position where the shift register is still busy, i.e. the new hpos is within the range of the already drawn player on the screen.The following questions need to be answered: *) What is the value in the shift register, and when is it changed?*) By what is the shift register clocked? Still by the "divide-by-N" counter as above, I assume?*) What is the phase of the divide-by-N counter relative to the background? In a simplistic model, it would re-start at the position where the new player location is. But this is not the case, as far as I understand you.Does the phase simply stay constant if I re-trigger the player into an already active output shift register? Do you say that the value of the shift register is the current value, *or'd* with with the value in the player graphics register? At which location does the or-ing take place? At the new trigger location?

Share this post


Link to post
Share on other sites

I would simply assume that each player has an output shift register (clear enough) that is either clocked by the color clock, half the color clock or one fourth the color clock to generate the output pixels.

 

Yes, this is correct. There is a two-bit counter that drives the output shift register for each player/missile. The SIZEPx/SIZEM bits configure each counter to run with a period of 1, 2, or 4. This in turn runs the shift register at a rate of 1, 2 or 4 color clocks per graphics bit, producing single, double, and quad width.

 

Setting the position would then reset the shift register to its initial value, i.e. load the pattern into the shift register, and restarting the shifting process as soon as the horizontal position matches.However, you say that this is not the case. What is the "shift state"?

 

Correct, the retriggering of the sprite does not set the shift register to the GRAPFx/GRAFM value. It ORs that value into the shift register. Therefore, if the previous player has not finished shifting out, some of its bits may still be left and contribute to the output. By "shift state" I am referring to the contents of this shift register.

 

Thus, please let's make two cases: The player position is written to after the shift register is empty. I believe this should simply work as the above.

 

Correct. The shift register will have emptied out (shifted in all zeroes), and so the ORing in of the graphics data will be equivalent to setting the register.

 

The tricky case happens if the player is retriggered to a position where the shift register is still busy, i.e. the new hpos is within the range of the already drawn player on the screen. What is the value in the shift register, and when is it changed?

 

Whenever the shift register is loaded, it shifts out data starting at the MSB, since the video scan-out is from left to right. Therefore, the contents of the shift register at the time of the merge will be the previous graphics with some number of left shifts applied.

 

*) By what is the shift register clocked? Still by the "divide-by-N" counter as above, I assume?

 

Yes. Disregarding mid-screen changes to the SIZEPx/SIZEM register -- which produce another set of unusual outputs -- the shift register will still be counting at 1/4 rate.

 

*) What is the phase of the divide-by-N counter relative to the background? In a simplistic model, it would re-start at the position where the new player location is. But this is not the case, as far as I understand you.Does the phase simply stay constant if I re-trigger the player into an already active output shift register? Do you say that the value of the shift register is the current value, *or'd* with with the value in the player graphics register?

 

The phase of the shift counter is reset to match the new position. Thus, when the two positions are far enough apart that there is no overlap, the new image appears where you would expect.

 

When there is overlap, the counter reset effectively causes the old graphics to shift to match the timing of the new position. Since the image bits in the old image are always either aligned with those of the new image or shifted to the left, we can infer that this reset also causes a shift to happen immediately at the start of the new image. This can shorten whatever bit was being displayed. Therefore, the overlap effect can be described as follows: when the retrigger occurs, the bits that are used are the contents of the GRAFPx or GRAFM register, ORed with the previous graphics shifted left by however many bits have been displayed, even partially.

 

At which location does the or-ing take place? At the new trigger location?

 

Yes, it happens once when HPOSPx/HPOSMx register matches the horizontal position counter.

Share this post


Link to post
Share on other sites

When Phaeron and other brainies get going its like an episode of the Big Bang Theory in hyper-mode...

 

I wish I'd tried harder at school :)

  • Like 2

Share this post


Link to post
Share on other sites

Yes, this is correct. There is a two-bit counter that drives the output shift register for each player/missile. The SIZEPx/SIZEM bits configure each counter to run with a period of 1, 2, or 4. This in turn runs the shift register at a rate of 1, 2 or 4 color clocks per graphics bit, producing single, double, and quad width.

 

 

 

Correct, the retriggering of the sprite does not set the shift register to the GRAPFx/GRAFM value. It ORs that value into the shift register. Therefore, if the previous player has not finished shifting out, some of its bits may still be left and contribute to the output. By "shift state" I am referring to the contents of this shift register.

...

Yes, it happens once when HPOSPx/HPOSMx register matches the horizontal position counter.

 

Thanks, very helpful, that was exactly the missing piece of information. Works now!

Share this post


Link to post
Share on other sites

I wish I'd tried harder at school :)

 

Guess it's not really how hard you try at school. It's more like "how you play with computers". I never cared too much about the games. I played the system "my way". (-:

Share this post


Link to post
Share on other sites

Yes, this is correct. There is a two-bit counter that drives the output shift register for each player/missile. The SIZEPx/SIZEM bits configure each counter to run with a period of 1, 2, or 4. This in turn runs the shift register at a rate of 1, 2 or 4 color clocks per graphics bit, producing single, double, and quad width.

 

Thanks again, this was very helpful. In the meantime, I also got the player resize logic working, which was a bit tricky. However, the test currently trips on something unexpected with the WSYNC logic I do not at all understand.

 

Your test uses the INC WSYNC trick to trigger WSYNC twice to start at cycle 105. However, in some cases the code starts here instead at cycle 106. This happens exactly when the cycle immediately following the first write to WSYNC is blocked by the memory refresh.

 

Thus, if the write happens at cycle N, then the CPU halts at N+1 due to the refresh - this cycle would normally remain untouched by Antic, but isn't in this case. Cycle N+2 onwards up to 105 are blocked by antic. At cycle 105, the CPU is executing the second write into WSYNC, this time with the incremented value. Cycle 106 remains free, cycles 107 onwards up to cycle 105 of the next line are blocked again due to the second write. Which means that the instruction immediately following the INC WSYNC is decoded at cycle 106 of the first line, but its execution resumes at cycle 105 on the next line.

 

However, this means that the instruction behind the INC WSYNC is *one cycle* too early for the test to succeed in this rare case - something is wrong here.

 

It is not true that a "late" STA WSYNC doesn't have the one-cycle delay slot (which would resolve the situation).

 

Models:

 

Does the 6502 have a "prefetch" at instruction boundaries such that it usually "appears as if" the cycle following the WSYNC is free, and does this not hold if I'm running to the second write cycle of the INC WSYNC? That was my current working hypothesis, but that's neither very nice.

 

A second explanation would be that Antic is held up by the memory DMA, and thus cannot start to block the CPU until *after* the memory refresh is done, thus the free cycle is delayed until after the memory DMA is over. But that might or could mean that ANTIC would insert the free cycle very late after all PF DMA in the heavy duty PF modes - and that doesn't seem to be right either.

 

So what's going on here?

Edited by thorfdbg

Share this post


Link to post
Share on other sites

To understand what's supposed to happen here, you have to look closely at how ANTIC controls the 6502.

 

First, the way WSYNC works: when a write occurs to WSYNC, ANTIC waits for one additional cycle to go by before suspending the 6502 until the beginning of horizontal blank. If that cycle is free, the 6502 gets to run one additional cycle of execution, which is ordinarily to fetch the first byte of the next instruction. Otherwise, if it's taken by DMA, the 6502 loses that cycle. In the scenario you've outlined, this cycle is occupied by refresh DMA.

 

The subtlety here is in the two different ways that ANTIC can halt the 6502. For DMA cycles, ANTIC asserts HALT, which stops the clock to the 6502. For WSYNC, however, it asserts RDY instead. The NMOS 6502 has a quirk in that it will only stop for RDY on a read cycle and not a write cycle. The result is that the second write to WSYNC is not delayed until horizontal blank -- it instead occurs on the next unhalted cycle. Afterward, the 6502 is stopped when it tries to do an instruction fetch for the next instruction. Since WSYNC is already active, the second write to WSYNC is ignored, and because playfield DMA is disabled during this test, there is guaranteed to be at least one unhalted cycle before HBLANK to eat the second write. Result: the "free" cycle that may be available after a write to WSYNC and which can screw up timing is neutralized.

 

There is an issue with this trick, which is that it only works on NMOS 6502s. The CMOS versions, the 65C02 and 65C816, will stop on a write cycle and don't allow this trick. I've been slowly replacing the INC WSYNC instructions in Acid800 with other methods for this reason.

 

Finally, before you ask... yes, people have used this in the wild. The demo intro to ABBUC disk #20 uses DEC WSYNC instructions and shows artifacts if they are not emulated correctly.

Edited by phaeron

Share this post


Link to post
Share on other sites

When trying to sync the start of a IRQ to a horizontal position I remember to have needed to use two consecutive STA WSYNC, because with only one there were timing issues ... could that be the same thing as using INC WSYNC?.. or maybe the effect is minimized or it was just luck :) ?

Share this post


Link to post
Share on other sites

Yes, 2x STA WSYNC will work: the first WSYNC waits to horizontal blank, and then the second WSYNC can't happen in front of a DMA cycle instead there are no DMA cycles there. The downside is that you have to burn a scanline to do it.

 

This workaround will still give you unstable timing if a refresh cycle is pushed to cycle 105, but as candle said, this is rare. You need horizontal scrolling or a wide playfield for it to happen.

Share this post


Link to post
Share on other sites

To understand what's supposed to happen here, you have to look closely at how ANTIC controls the 6502.

...

 

Thanks, indeed, I know that it is been used, but I wasn't aware of the 6502 RDY bug. Fixed now, and works! Thus, the P/M retrigger and resize logic should do now.

Share this post


Link to post
Share on other sites

Guess it's not really how hard you try at school. It's more like "how you play with computers". I never cared too much about the games. I played the system "my way". (-:

 

I learned to program in assembly to an extent but my awful maths meant I never could take the programming to a seriously good level, I simply never had the aptitude to improve the maths which is why and bringing it back on topic why I love reading the tech stuff, its nice to see there are dead clever people out there doing great programs.

Share this post


Link to post
Share on other sites

Thanks, indeed, I know that it is been used, but I wasn't aware of the 6502 RDY bug. Fixed now, and works! Thus, the P/M retrigger and resize logic should do now.

not a bug, a feature - it was intended for use as a wait-states for very slow mask ROM chips, thus only READ was affected

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