More interesting 6522 VIA emulation discrepancies

want to talk about MESS/model b/beebem/b-em/electrem/elkulator? do it here!
Post Reply
User avatar
scarybeasts
Posts: 84
Joined: Tue Feb 06, 2018 7:44 am
Contact:

More interesting 6522 VIA emulation discrepancies

Post by scarybeasts » Mon Dec 03, 2018 9:44 am

Hi,

I'm tooling up to emulate the 6522 VIA best I can and I've some pretty basic differences in timings and behaviors, particularly between MAME vs. the rest. I'm not quite sure who to believe this time: "the rest" generally handle the legendary Kevin Edwards copy protection, which requires quite some precision. On the flipside, MAME was the accuracy winner with the recently discussed PB7 behavior.

The cases (all in the attached ssd file), would be super interesting to know how these shake down on a vanilla beeb.

- VIA.T21
Simple little test case that writes a value to T2C while T2 is in pulse counting mode. In this instance, the counter is "frozen". MAME exhibits a couple of differences:
a) The counter starts and runs on MAME even though we're in pulse counting mode. Not sure about that.
b) Once the counter has expired, MAME gives back the same value that was written. Other emulators tend to give back (value + 1) which seems wrong. I doubt that value is ever stored on silicon and perhaps the emulators just use the +1 to align the timing correctly on the assumption that the +1 state is not normally observable. I suspect the correct implementation may in fact be to delay the counter update taking effect by 1 VIA 1Mhz timer tick, and that may be a way to get Kevin Edwards protection working without having to implement a hack to preserve a missing interrupt, but I'll confirm that another time.

- VIA.T22
Measures successive T2 counter low values around expiry and reload.
b-em, jsbeeb, b2 run 1 -> 0 ->255 -> 254 -> ...
But MAME runs 4 -> 3 -> 2 -> 1 -> 255 -> 254
The timing is different (writing the counter actually adds 3 in the source code) and 0 is missing?

- VIA.T21
Measures successive T2 counter low values around expiry and reload of "4".
b-em, jsbeeb, b2 run 1 -> 0 -> 255 -> 4 -> 3 -> ...
MAME runs 1-> 0 -> 255 -> 254 -> 255 -> 254 -> 253 -> ...
What? :)


Cheers
Chris
Attachments
tests.ssd
(100 KiB) Downloaded 11 times

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Mon Dec 03, 2018 10:56 am

The (value + 1) stuff in B-Em (and, hence also jsbeeb) seems to be to correct the off-by-one error that occurs as a consequence of having to choose an order to tick components which, in reality, happen in parallel. When emulating LDA &FE64, B-Em does a catchup of 4 cycles before performing the read, meaning the VIA is essentially a tick ahead of the CPU - hence the adjustment. This sounds like it would indeed give the wrong results though in pulse-counting mode.

I think the MAME thing about the timer values skipping 0 came up before, and we deemed it to be incorrect. Certainly from testing on real hardware, we can see that the VIA timers go through 1, 0, 255 and then back to the latch value - this is even the case for T1 in one-shot mode, and for T2 (despite what some revisions of the 6522 datasheet may imply).

In case you're interested, I've attached another reference - the beginnings of an emulator I started which just emulates as much of the 6502 and VIAs as it needs to in order to pass the Dormann tests and Kevin Edwards' protection systems. I decided to take a different approach - it works on a cycle-by-cycle basis and doesn't require any special hacks in the VIA emulation. The CPU emulation works in a way much closer to a real 6502, in that the address bus is set, and the following cycle a result is fetched or a value stored.

I decided to abandon this as I always intended wasm to be a viable target, and this approach to emulation, while accurate, just wasn't going to be fast enough. I'll revisit it one day with a more high-level approach to managing interaction between components, allowing them to run as many cycles as possible before requiring a context switch.
Attachments
VirtualBeeb.zip
(91.62 KiB) Downloaded 15 times

User avatar
hoglet
Posts: 8214
Joined: Sat Oct 13, 2012 6:21 pm
Location: Bristol
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by hoglet » Mon Dec 03, 2018 10:59 am

With VIA.T21 I get:

Code: Select all

>RUN
USER VIA T2CL: 1
USER VIA T2CL: 255
USER VIA T2CL: 255
With VIA.T22 I get:

Code: Select all

1, 0, 255, 254, 253, 252
With VIA.T11 I get:

Code: Select all

1, 0, 255, 4, 3, 2
Results are the same on a Model B and a Master 128.

Dave
Last edited by hoglet on Mon Dec 03, 2018 10:59 am, edited 1 time in total.

User avatar
scarybeasts
Posts: 84
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by scarybeasts » Mon Dec 03, 2018 11:22 am

Rich Talbot-Watkins wrote:
Mon Dec 03, 2018 10:56 am
I think the MAME thing about the timer values skipping 0 came up before, and we deemed it to be incorrect. Certainly from testing on real hardware, we can see that the VIA timers go through 1, 0, 255 and then back to the latch value - this is even the case for T1 in one-shot mode, and for T2 (despite what some revisions of the 6522 datasheet may imply).
A follow up note on T2 -- what is the conceptual latch value? It always rolls back over to 0xFFFF, so a conceptual latch value of 0xFFFF. This might imply a sequence of 1, 0, 255 (expiry), 255 (latch), 254, ...? But the results from Dave (thanks Dave!) show clearly that it's 1, 0, 255, 254 on real hardware. Interesting :-)


Cheers
Chris

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Mon Dec 03, 2018 11:24 am

I may have misremembered on T2; I'll have to check my notes. KE's protections require the correct behaviour so I assume my code above is doing the same thing as Dave's results!

User avatar
scarybeasts
Posts: 84
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by scarybeasts » Mon Dec 03, 2018 11:30 am

hoglet wrote:
Mon Dec 03, 2018 10:59 am
With VIA.T21 I get:

Code: Select all

>RUN
USER VIA T2CL: 1
USER VIA T2CL: 255
USER VIA T2CL: 255
With VIA.T22 I get:

Code: Select all

1, 0, 255, 254, 253, 252
With VIA.T11 I get:

Code: Select all

1, 0, 255, 4, 3, 2
Results are the same on a Model B and a Master 128.

Dave
Thanks, Dave, that's awesome! So a slew of emulator bugs:

- MAME shouldn't be starting T2 if it's in pulse counting mode.
- b-em, b2, jsbeeb shouldn't be adding one to the T2 counter when in pulse counting mode.
- No idea what's with MAME adding 3 to the T2 counter.
- No idea what's with MAME skipping 0 in T2.
- No idea what's with MAME's T1 counter handing at expiry.


Cheers
Chris

Coeus
Posts: 1235
Joined: Mon Jul 25, 2016 11:05 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Coeus » Mon Dec 03, 2018 2:15 pm

scarybeasts wrote:
Mon Dec 03, 2018 11:30 am
- b-em, b2, jsbeeb shouldn't be adding one to the T2 counter when in pulse counting mode.
I can see that this is an improvement in that, from a software perspective, the 6522 emulation looks correct, and it should be easy to add a test for pulse count mode and not add the 1. I am not convinced it makes the pulse counting mode usable for counting pulses, i.e. returning the right number of pulses, but I assume from the fact nothing has appeared broken previously that nothing attached to the system VIA uses pulse counting mode?

Of course, we can't know of all the possible hardware that could be connected to the user port but until someone writes the emulation for something that uses pulse counting more we don't need to worry.

Of course, the other approach is to ditch the +1 for all cases and change the CPU emulation so that:

Code: Select all

                case 0xAD:      /*LDA abs */
                        addr = getw();
                        polltime(4);
                        takeint = (interrupt && !p.i);
                        a = readmem(addr);
                        setzn(a);
                        break;
becomes

Code: Select all

                case 0xAD:      /*LDA abs */
                        addr = getw();
                        polltime(2);
                        takeint = (interrupt && !p.i);
                        a = readmem(addr);
                        polltime(2);
                        setzn(a);
                        break;
but if we only fix the particular load instruction Kevin's protection uses that's still really a bodge. To do it properly would required finding every case where the CPU could read from the VIA including cases where the effective address is the result of indexed/indirect addressing and split the stepping on of non-CPU hardware (which is what polltime does) in the same way.

Once you start down that road, the obvious final destination is to stop having pre-calculated total clock ticks for each opcode but to add clock ticks based on the micro-ops the instruction is made up of but that's no longer a quick fix.

Do we even have a test suite to determine if the CPU emulation is cycle accurate? Without one there is the risk of making things theoretically better but with bugs creeping in that affect the ability to run existing software.
Last edited by Coeus on Mon Dec 03, 2018 2:20 pm, edited 2 times in total.

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Mon Dec 03, 2018 4:25 pm

Having a quick look at B-Em, I see it's already a bit haphazard as to which instructions are implemented accurately and which are not. For example, LDA #imm correctly checks for interrupts at the penultimate cycle, but LDA abs doesn't.

If the timer read were to be moved to before the timer tick as you suggest (although it should be polltime(3) / readmem() / polltime(1)), that would break other things, for example, the timer IRQ triggering at the right place. The approach I took was to have the VIA update follow the CPU update, and to defer the VIA timer store by incorporating it into its update, but this would be a substantial change to B-Em. I would say that a simple patch to perform the read differently in pulse counting mode is probably the safest option.

One of my goals with my emulator code attached above was to implement the CPU and VIAs without hacks, so that it all 'just works'. But updating components cycle-by-cycle in a round robin fashion like that isn't the fastest approach, and it would've run terribly once emscripten'd to Javascript.

User avatar
SarahWalker
Posts: 1171
Joined: Fri Jan 14, 2005 3:56 pm
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by SarahWalker » Mon Dec 03, 2018 6:10 pm

I think part of the mess in B-em's 6502/VIA timing was to deal with the case where an interrupt fired in the same cycle as a VIA read/write that would clear that interrupt; there's a one cycle delay between the VIA access and the 6502 acknowledging that the IRQ line is no longer firing, meaning that the 6502 can run the interrupt handler with no bits set in the VIA IFR. I definitely ran into that case emulating Nightshade.

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Mon Dec 03, 2018 8:40 pm

When I was investigating this, I did run into that case, but it wasn't especially unexpected. That's what happens if (for example):
  • The timer times out and generates an IRQ
  • The 6502 commits to taking the interrupt instead of the next opcode (on the penultimate cycle of an instruction)
  • The final instruction cycle acknowledges the interrupt (e.g. read from T1CL or write to T1CH)
The case which was surprising was, when an interrupt is fired just prior (500ns) to a read from T1CL. In this case, the IRQ doesn't get acknowledged, although you might expect it to be, and the interrupt gets taken without problem.

Here's the test program, here are the expected results (courtesy of BigEd), and here are those results tabulated in a graphical way.
Last edited by Rich Talbot-Watkins on Tue Dec 04, 2018 10:04 am, edited 1 time in total.
Reason: Updated the table link

User avatar
scarybeasts
Posts: 84
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by scarybeasts » Tue Dec 04, 2018 7:42 am

Rich Talbot-Watkins wrote:
Mon Dec 03, 2018 8:40 pm
Here's the test program, here are the expected results (courtesy of BigEd), and here are those results tabulated in a graphical way.
Oh that table is money. Thanks Rich.

I'm having a hard time conceptualizing the cycle boundaries, though. Is the dotted line in between the two T1CL 255 values the IRQ? Does that represent action at the half-cycle of the 1Mhz 6522 VIA?

Cheers
Chris

User avatar
scarybeasts
Posts: 84
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by scarybeasts » Tue Dec 04, 2018 7:51 am

Rich Talbot-Watkins wrote:
Mon Dec 03, 2018 4:25 pm
Having a quick look at B-Em, I see it's already a bit haphazard as to which instructions are implemented accurately and which are not. For example, LDA #imm correctly checks for interrupts at the penultimate cycle, but LDA abs doesn't.
Oh for sure. There's another test case in the ssd I posted, that writes 20 to T1 and then gets 20 back under b-em if you read T1CL with LDA (),y. This is because polltime(5) is after all the memory reads for that opcode. Maybe only the ones that need to be correct for Kevin Edwards protection are actually correct!


Cheers
Chris

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Tue Dec 04, 2018 10:08 am

scarybeasts wrote:
Tue Dec 04, 2018 7:42 am
I'm having a hard time conceptualizing the cycle boundaries, though. Is the dotted line in between the two T1CL 255 values the IRQ? Does that represent action at the half-cycle of the 1Mhz 6522 VIA?
Yes, exactly. The dashed line is the point at which the VIA generates an IRQ. I've updated the table (new link) to indicate the points at which the CPU checks interrupts and commits to servicing any pending ones (in red).

Edit to add: To make sense of this, we have to consider that the CPU does the important work on the falling edges of the clock. So when we have a block labelled (for example) "ld FE64", the load actually happens on the edge at the very end of the block. At the beginning of the block, think of it as the CPU having set the address bus to the address it wishes to access, and the interim being time waiting for the next cycle.

One thing I've realised is that rows 6 and 7 aren't a good test of whether writing T1CH 500ns after the IRQ is generated acknowledges the IRQ or not, because the store in the previous CPU cycle will restart the timer before it has a chance to interrupt. I need to update the test and get someone to run it on a real Beeb.
Last edited by Rich Talbot-Watkins on Tue Dec 04, 2018 2:13 pm, edited 1 time in total.
Reason: Clarified meaning of the table further

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Tue Dec 04, 2018 10:13 am

scarybeasts wrote:
Tue Dec 04, 2018 7:51 am
Oh for sure. There's another test case in the ssd I posted, that writes 20 to T1 and then gets 20 back under b-em if you read T1CL with LDA (),y. This is because polltime(5) is after all the memory reads for that opcode. Maybe only the ones that need to be correct for Kevin Edwards protection are actually correct!
Yeah, that seems to be the case. For jsbeeb we reimplemented the CPU emulation by building the opcode logic procedurally by the power of Javascript and eval(). This CPU/VIA timer test was our bible for determining the order things should be checked in! The take away is that the CPU seems to already commit to an interrupt somewhere before the end of the penultimate cycle, as we can simply see from cases like row 24.

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Tue Dec 04, 2018 4:39 pm

I've updated the test program to check whether writing T1CH right after the IRQ acknowledges it or not.

Would somebody with a real BBC B be able to try this sometime and post the output? Would be much appreciated!

Disk image + plaintext BASIC program in the zip:
viatest.zip
(2.19 KiB) Downloaded 8 times

User avatar
BigEd
Posts: 2502
Joined: Sun Jan 24, 2010 10:24 am
Location: West
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by BigEd » Tue Dec 04, 2018 4:50 pm

On a Beeb:

Code: Select all

>RUN
4436 (AD 1 10)        0       DD
4443 (AD 2 10)        0       DD
4450 (AD 3 10)        0       DD
445E (AD 4 10)        0       DD
0                     0       0
0                     0       0
4488 (AD 7 10)        0       FF
4497 (AD 8 10)        0       0
0                     0       0
44B8 (E6 71 8C)       C0      FF
44C5 (E6 71 8C)       C0      FF
0                     0       0
0                     0       0
44F6 (AD E 10)        C0      DB
4506 (AD F 10)        C0      DC
4516 (AD 10 10)       C0      FF
4527 (AD 11 10)       C0      0
453A (8E 64 FE)       C0      1
454A (8E 64 FE)       C0      1
4559 (AD 14 20)       C0      0
4569 (AD 15 20)       C0      0
4578 (AD 16 20)       C0      1
458A (E6 71 8C)       C0      FF
4599 (E6 71 8C)       C0      0
45A6 (E6 71 8C)       C0      0
0                     0       0
45C7 (AD 1B 20)       C0      DB
45D7 (AD 1C 20)       C0      DB
0                     0       0
>
On a Master:

Code: Select all

>RUN
4436 (AD 1 10)        0       DD
4443 (AD 2 10)        0       DD
4450 (AD 3 10)        0       DD
445E (AD 4 10)        0       DD
446E (E6 71 8C)       C0      DB
447B (E6 71 8C)       C0      DB
4488 (AD 7 10)        0       FF
4497 (AD 8 10)        0       0
0                     0       0
44B8 (E6 71 8C)       C0      FF
44C5 (E6 71 8C)       C0      FF
0                     0       0
0                     0       0
0                     0       0
0                     0       0
4519 (8E 64 FE)       C0      1
452A (8E 64 FE)       C0      0
453A (8E 64 FE)       C0      1
454A (8E 64 FE)       C0      1
4559 (AD 14 20)       C0      FF
4569 (AD 15 20)       C0      0
4578 (AD 16 20)       C0      0
458A (E6 71 8C)       C0      FF
4599 (E6 71 8C)       C0      FF
45A6 (E6 71 8C)       C0      0
0                     0       0
45C7 (AD 1B 20)       C0      DB
45D7 (AD 1C 20)       C0      DB
0                     0       0
>

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Tue Dec 04, 2018 4:56 pm

Wow, fast turnaround Ed, thanks a million!

I just spotted a potential bug which might cause the last values to be overwritten. Would you mind trying this version to see if the last four results are different please?
viatest.zip
(2.17 KiB) Downloaded 11 times
Sorry 'bout that.

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Tue Dec 04, 2018 4:58 pm

Also, it's interesting to see how different the results are on a Master. I'd certainly expected a difference, e.g. because the RMW opcodes perform two reads instead of two writes, and because IRQ entry time is slightly longer on a Master due to JMP (ind) having an extra cycle, but it's also possible that the actual behaviour of the VIA in the Master is different too (it's a CMOS version, right?).

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Tue Dec 04, 2018 5:11 pm

Updated the timing chart, assuming that the extra tests have worked OK. Looks like writing T1CH also doesn't acknowledge the IRQ right after it's generated (will need to correct jsbeeb), so at least it's kind of symmetrical in terms of unexpected behaviour!

Will take a look through those Master results now I have them, to see if there's anything surprising there!

User avatar
BigEd
Posts: 2502
Joined: Sun Jan 24, 2010 10:24 am
Location: West
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by BigEd » Tue Dec 04, 2018 5:24 pm

Updated results:

Beeb:

Code: Select all

>RUN
4436 (AD 1 10)        0       DD
4443 (AD 2 10)        0       DD
4450 (AD 3 10)        0       DD
445E (AD 4 10)        0       DD
0                     0       0
0                     0       0
4488 (AD 7 10)        0       FF
4497 (AD 8 10)        0       0
0                     0       0
44B8 (E6 71 8C)       C0      FF
44C5 (E6 71 8C)       C0      FF
0                     0       0
0                     0       0
44F6 (AD E 10)        C0      DB
4506 (AD F 10)        C0      DC
4516 (AD 10 10)       C0      FF
4527 (AD 11 10)       C0      0
453A (8E 64 FE)       C0      1
454A (8E 64 FE)       C0      1
4559 (AD 14 20)       C0      0
4569 (AD 15 20)       C0      0
4578 (AD 16 20)       C0      1
458A (E6 71 8C)       C0      FF
4599 (E6 71 8C)       C0      0
45A6 (E6 71 8C)       C0      0
0                     0       0
45C4 (E6 71 8C)       C0      DB
45D1 (E6 71 78)       C0      DB
0                     0       0
>
Master:

Code: Select all

>RUN
4436 (AD 1 10)        0       DD
4443 (AD 2 10)        0       DD
4450 (AD 3 10)        0       DD
445E (AD 4 10)        0       DD
446E (E6 71 8C)       C0      DB
447B (E6 71 8C)       C0      DB
4488 (AD 7 10)        0       FF
4497 (AD 8 10)        0       0
0                     0       0
44B8 (E6 71 8C)       C0      FF
44C5 (E6 71 8C)       C0      FF
0                     0       0
0                     0       0
0                     0       0
0                     0       0
4519 (8E 64 FE)       C0      1
452A (8E 64 FE)       C0      0
453A (8E 64 FE)       C0      1
454A (8E 64 FE)       C0      1
4559 (AD 14 20)       C0      FF
4569 (AD 15 20)       C0      0
4578 (AD 16 20)       C0      0
458A (E6 71 8C)       C0      FF
4599 (E6 71 8C)       C0      FF
45A6 (E6 71 8C)       C0      0
0                     0       0
45C4 (E6 71 8C)       C0      DB
45D1 (E6 71 78)       C0      DB
0                     0       0
>

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Tue Dec 04, 2018 5:42 pm

Thank you Ed! Results are consistent with the original run, so I didn't screw up.

So the VIA doesn't acknowledge the IRQ if a load/store happens in the same cycle that it's generated. We can probably theorise all sorts of reasons why this might be the case, but as far as emulating it goes, it's a clear extra bit of logic which needs to be taken into account. In this respect, the Master VIA seems to behave the same!

Coeus
Posts: 1235
Joined: Mon Jul 25, 2016 11:05 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Coeus » Tue Dec 04, 2018 11:14 pm

Rich Talbot-Watkins wrote:
Tue Dec 04, 2018 5:42 pm
Thank you Ed! Results are consistent with the original run, so I didn't screw up.

So the VIA doesn't acknowledge the IRQ if a load/store happens in the same cycle that it's generated. We can probably theorise all sorts of reasons why this might be the case, but as far as emulating it goes, it's a clear extra bit of logic which needs to be taken into account. In this respect, the Master VIA seems to behave the same!
What do you mean by the VIA acknowledging the interrupt? Surely the VIA generates the interrupt and the CPU responds? Or do you mean that there are cases where the VIA will generate an interrupt but if the CPU reads the IFR too quickly bit 7 will not be set, i.e. an interrupt service routine would incorrectly conclude this VIA is not responsible for the interrupt?

Sorry, to be a nuisance but the test program is not so easy to follow without comments - I would need to look at it when I have rather more time to figure this out from there.

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Wed Dec 05, 2018 8:44 am

This program came from trying to make full sense of Kevin Edwards' Nightshade protection which routinely does mad things like ROL &FE65, and also enables a custom IRQ routine. Essentially it sets a timer countdown period of 4, and then contrives to execute various instructions which would acknowledge VIA IRQs around the moment that the timer times out. The reason for this was to determine how to emulate certain edge cases:
  • If the opcode being executed checks for interrupts on the same cycle as the VIA generates an IRQ, does it notice it at that moment?
  • If the opcode being executed checks for interrupts on the same cycle as the interrupt is acknowledged, which happens first? i.e. is the IRQ taken?
  • Can an IRQ be lost completely if it's acknowledged between it being generated and the CPU's next check?
There were a few types of observed behaviour:
  • Timer times out during the instruction, and an IRQ is serviced directly afterwards.
  • Timer times out during the instruction, but happens too late to be serviced immediately afterwards, and is deferred until after the following instruction.
  • Timer times out during the instruction, CPU commits to taking the IRQ but the instruction acknowledges it before the interrupt service routine is entered; this results in no IFR flags being set when the interrupt is serviced.
  • Timer times out during the instruction, but it is acknowledged before the IRQ is noticed, hence the IRQ is lost.
  • Timer times out during the instruction, and an IRQ is serviced directly afterwards, even though an intervening operation ought to have acknowledged the IRQ before the CPU checked.
This final type of behaviour was the most surprising: if an operation tries to acknowledge the IRQ 500ns after it's generated (i.e. at the end of the same 1MHz cycle), the IFR is not cleared and the IRQ remains unacknowledged. I believe this is what B-Em's hacks were to work around, but I think Sarah misdiagnosed the issue.

User avatar
1024MAK
Posts: 8795
Joined: Mon Apr 18, 2011 4:46 pm
Location: Looking forward to summer in Somerset, UK...
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by 1024MAK » Wed Dec 05, 2018 9:17 am

Rich Talbot-Watkins wrote:
Tue Dec 04, 2018 4:58 pm
...but it's also possible that the actual behaviour of the VIA in the Master is different too (it's a CMOS version, right?).
In the two Master 128 machines that I checked, yes, CMOS versions of the VIAs are fitted. Both of these IIRC are issue 2 PCBs.
But I believe that at least one member here has a Master 128 with a NMOS VIA.

Mark

User avatar
scarybeasts
Posts: 84
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by scarybeasts » Wed Dec 05, 2018 10:38 am

Hi Rich,

Those results in the new sheet are super interesting. Can I offer some questions and comments?

1) Timer restarts.
I've been unable to convince myself that the test case correctly accounts for timer restarts. For example, the read-modify-write in row 6 is interesting / instructive.
I may have this wrong of course because it's a nuanced area -- please cast a critical eye over this description!
The read from T2CH at P will be 0. The first write at T will be the unmodified decremented value, which is 0. Writing 0 to T2CH will relatch the timer to 4, effective starting at the next VIA cycle. So instead of 255 + interrupt, perhaps that next cycle would be 4 + no interrupt. This would mean the interrupt line is drawn incorrectly for that row.
The second write at AB will write the post-decrement value of 255 to T2CH. That'll set up a running timer for about ~65ms, so that's not going to expire before the next test case starts and resets matters by writing to T2CH again.
This will result in the same observable though as the test case result: no interrupt.

Assuming this analysis is correct, it could explain the jarring discrepancy between row 6 and row 28 -- it seems suspicious that they'd behave differently.


2) 6502 interrupt check timing.
I don't think the red bar for interrupt check timing is in the write place. For an IRQ to be recognized at the end of the penultimate cycle, the IRQ pin actually needs to have been pulled low the half cycle prior.

Vague-ish reference: https://wiki.nesdev.com/w/index.php/CPU_interrupts

Better demo via visual 6502:
[irq delay]: http://visual6502.org/JSSim/expert.html ... rq&irq0=10
[irq fire]: http://visual6502.org/JSSim/expert.html ... irq&irq0=9

I believe this makes rows 10 / 27 make sense. As-is, 10 / 27 appear to be a special case: the IRQ is raised at the same time the 6502 checks for it and yet there's no interrupt?? Move the 6502 check back a half cycle and it makes sense: there wasn't yet an IRQ to see.


3) Timer restarts #2.
I'm not sure about the T2CH reloads in cases 27 - 29. It looks like the value 1 is stored in T2CH. Wouldn't this start a timer for 256 + 4 cycles? Would that be short enough to trigger before the the user IRQ vector is called? The MOS 1.2 does quite a bunch of work before it realizes it's a user VIA that's asserting the interrupt.


4) Alternative simpler behavior proposal with no special casing.

If we fix the quirks of 1) and 2) above, I think the following simple rule might work to describe 6522 IFR behavior and match all the test cases:
- For T1CL read / T2CH writes, clear the IFR at the start of the VIA cycle. (The writes take effect next cycle and do not affect any expiry in the current cycle.)
- If timer expiry is happening, raise IFR at the VIA half-cycle.

Perhaps my charge at simplicity is misplaced but every time I write a highly predicated "if" statement to emulate 1970s silicon, it hurts.


Cheers
Chris

User avatar
scarybeasts
Posts: 84
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by scarybeasts » Wed Dec 05, 2018 10:55 am

(And where I say T2 all over the place I mean T1 of course.)

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Wed Dec 05, 2018 12:22 pm

Hey Chris,

Great to have another pair of eyes looking critically over this stuff!
scarybeasts wrote:
Wed Dec 05, 2018 10:38 am
Assuming this analysis is correct, it could explain the jarring discrepancy between row 6 and row 28 -- it seems suspicious that they'd behave differently.
Yeah, I noticed that the results for rows 6 and 7 were likely due to the timer being restarted before the IRQ could fire, rather than because of the IRQ being acknowledged by the write - that's why I added rows 27-29, which would be a fairer test. Rows 28-29 show the same kind of results as rows 11-12, which makes me happy as it shows some consistency.
2) 6502 interrupt check timing.
I don't think the red bar for interrupt check timing is in the write place. For an IRQ to be recognized at the end of the penultimate cycle, the IRQ pin actually needs to have been pulled low the half cycle prior.
Yes, I agree with you. What actually happens is that the 6502 latches the IRQ signal half a cycle before, and then checks that on the penultimate cycle - but to save having to emulate the 6502 at 4MHz granularity with both phi1 and phi2 doing different things, it's generally good enough to assume that the interrupt status should be known before the end of the penultimate cycle.

We talked about this a bit on this thread: viewtopic.php?p=213747#p213747
I believe this makes rows 10 / 27 make sense. As-is, 10 / 27 appear to be a special case: the IRQ is raised at the same time the 6502 checks for it and yet there's no interrupt?? Move the 6502 check back a half cycle and it makes sense: there wasn't yet an IRQ to see.
Indeed. On jsbeeb it's not a special case: we handle this by just performing the irq check before ticking the VIA prior to its read/write. On "VirtualBeeb" (the abandoned emulator I posted above), it does it properly: caching the irq signal, and checking that cached value on the final cycle (T0), and then using the results of that check at the opcode fetch (T1) to determine whether to decode it, or replace it with the interrupt sequence.

The only special case we had to make was this one of the VIA not clearing the IFR when an acknowledging read or write happens half a 1MHz cycle after it has generated an IRQ. This seems to be reproducible but undocumented 6522 behaviour (according to these tests at least).
3) Timer restarts #2.
I'm not sure about the T2CH reloads in cases 27 - 29. It looks like the value 1 is stored in T2CH. Wouldn't this start a timer for 256 + 4 cycles? Would that be short enough to trigger before the the user IRQ vector is called? The MOS 1.2 does quite a bunch of work before it realizes it's a user VIA that's asserting the interrupt.
Yeah it'll start the timer again, but only after it's already generated an IRQ, so we don't care (because the code then sets it back to 0004 for the next test). The IRQ handler replaces the OS one entirely.
4) Alternative simpler behavior proposal with no special casing.

If we fix the quirks of 1) and 2) above, I think the following simple rule might work to describe 6522 IFR behavior and match all the test cases:
- For T1CL read / T2CH writes, clear the IFR at the start of the VIA cycle. (The writes take effect next cycle and do not affect any expiry in the current cycle.)
- If timer expiry is happening, raise IFR at the VIA half-cycle.
I don't believe there is any special casing other than the VIA behaviour I already alluded to. Everything else seems to work fairly predictably, and my "Kevin Edwards emulator" posted above gets the right results without hacks. However I think you'll always have problems with sequencing: depending on the order you update the components, you can change the emulated behaviour. In reality, these updates will be occurring in parallel on the falling clock edge. Even VirtualBeeb relies on a particular update order: CPU, then VIA. However certain things like latch reload are deferred, so that a CPU store doesn't change the timer value straight away, but waits until the VIA update.

User avatar
Rich Talbot-Watkins
Posts: 1463
Joined: Thu Jan 13, 2005 5:20 pm
Location: Palma, Mallorca
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by Rich Talbot-Watkins » Wed Dec 05, 2018 1:30 pm

Rich Talbot-Watkins wrote:
Wed Dec 05, 2018 12:22 pm
Indeed. On jsbeeb it's not a special case: we handle this by just performing the irq check before ticking the VIA prior to its read/write.
In case you're wondering, here's what gets generated for LDA abs in jsbeeb:

Code: Select all

cpu.polltime(3);
cpu.checkInt();
var addr = cpu.getw() | 0;
cpu.polltimeAddr(1, addr);
REG = cpu.readmem(addr);
cpu.a = cpu.setzn(REG);
Aside: you can examine any opcode gen in jsbeeb by typing the following in the browser console:

Code: Select all

require('6502.opcodes').cpu6502().getInstruction("LDA abs").join("\n")
(obviously replacing "LDA abs" with the instruction you're interested in!)

User avatar
scarybeasts
Posts: 84
Joined: Tue Feb 06, 2018 7:44 am
Contact:

Re: More interesting 6522 VIA emulation discrepancies

Post by scarybeasts » Thu Dec 06, 2018 10:13 pm

scarybeasts wrote:
Wed Dec 05, 2018 10:55 am
(And where I say T2 all over the place I mean T1 of course.)
Actually this gives me a thought. Rich, did you ever try your neat little test program but aimed at the T2 registers instead? T1 and T2 are clearly not identical beasts, based on capability. Maybe there other differences.


Cheers
Chris

Post Reply