Interrupt behaviour of the 6502 in emulation

You need an actual VIC.

Moderator: Moderators

Post Reply
lance.ewing
Vic 20 Afficionado
Posts: 413
Joined: Sat Nov 10, 2012 3:19 pm
Website: https://sites.google.com/site/mos6561vic/

Interrupt behaviour of the 6502 in emulation

Post by lance.ewing »

Mike wrote:Did you try out my raster demo with your emulator in the meantime?
lance.ewing wrote:I haven't implemented support for disk images yet, or for the disk drive, so at the moment I can only run standalone program files or cartridge images.

The disk drive is probably the next thing on my list to take a look at.
Well I now have support for the 1541 disk drive and .d64 disk images. I was using your mg_raster.d64 disk Mike as the test disk throughout. I didn't know much at all about the 1541 disk drive until I started to add support for it. All I ever had with my original VIC 20 were cartridges and tapes, and I didn't grow up with a C64. So I've certainly learnt a lot over the past week. I delved deep into the various documents online (some of them very good by the way, such as the "Inside Commodore DOS" book), and the 1541 schematics, and the 1541 ROM disassembly. Some of Michael Steil's recent posts on the 1541 disks and the Serial Bus at http://www.pagetable.com were also helpful in solidifying my understanding. I had to extend my 6522 VIA implementation a bit, because I didn't have support for the serial port yet, or for port latching and CA1/CB1 interrupts. It was certainly worth the effort then, because its always good to add in things that weren't previously supported.

It was pretty easy to get the "1541 machine" itself up and running. I already had the 6502 and 6522 emulation. I just had to define the right memory map, load the ROM image, and then run it cycle by cycle interleaved with the VIC 20 emulation. I also had to write the disk drive logic, including the GCR encoding, head movement, etc. The hard part was getting the serial lines connected up properly to the VIA chips and making them behave as they should. At one point I was getting it to build up timing diagram data that I could visualise on wavedrom.com so I could see what was going on. I understood the Open Collector concept straight away, and emulated the serial bus with that in mind. The bits that tripped me up were mainly with the input latching not being implemented, how ATNA behaves, and then just a few genuine bugs I made along the way where I'd coded it differently than how I thought I had. Glad its working now. I think I'd nearly had enough of trying to work out where in the ROM code it was and what it was trying to do. At one point I could see it was waiting for a SYNC, and I could see that the SYNC was happening, but it wasn't responding to it. That's when I discovered it was reliant on the input latching. I had a latch register for input latching, but didn't have the logic to put anything in it when the CA1 and CB1 interrupts occurred. So reading from the input latch was working, i.e. it returned the input latch value when input latching was enabled, but the value was always 0. - I still have a few 6522 features not implemented, but it seems I've taken it far enough for the 1541 and serial comms to be happy.

So to finally get to answering your question about how the mg_raster demo runs on my emulator: It is clear from having tried it now, and then comparing it to it running in VICE, that I still don't have a few things right with the VIC chip emulation.

Is it correct to say that what I see when it runs on VICE is correct?

I seem to have multiple colour changes partway down the screen that VICE doesn't have. I'll need to take a close look at your source code to see what its doing and think about where I'm going wrong.

Having .d64 support has opened a few more avenues now. I can test out many more demos, and also all the recently released games. Many weeks of testing and hopefully identifying and ironing things out are ahead of me.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Interrupt behaviour of the 6502 in emulation

Post by Mike »

lance.ewing wrote:Well I now have support for the 1541 disk drive and .d64 disk images. [...] I still have a few 6522 features not implemented, but it seems I've taken it far enough for the 1541 and serial comms to be happy.
Makes one once more appreciate the enormous work that has gone into VICE and other emulators. :)
So to finally get to answering your question about how the mg_raster demo runs on my emulator: It is clear from having tried it now, and then comparing it to it running in VICE, that I still don't have a few things right with the VIC chip emulation.

Is it correct to say that what I see when it runs on VICE is correct?
Correct. If you use at least a fairly recent version of VICE, that is.

That being said, the routine (or better said, the design/algorithm behind it) is also confirmed working on real hardware, both PAL and NTSC. Ghislain uses the exactly the same setup/init routine, and a variant of the IRQ server in Realms of Quest V.
I seem to have multiple colour changes partway down the screen that VICE doesn't have. I'll need to take a close look at your source code to see what its doing and think about where I'm going wrong.
You should see a plain stable yellow border, the greyscale image is produced by interlacing light green and light purple for light grey and green and purple for (normal) grey. If there are any yellow patches/stripes within the picture, that's wrong. If you see black stripes within the border, that's also wrong. Hardware has it, that changes of the colour registers happen one pixel late with respect to (half-)char boundaries, so there's a noticable single hires pixel thick black line between picture and right yellow border, that's O.K. - there's nothing one can do about this.

The routine critically depends on the correct number of cycles for each raster (71 for PAL, 65 for NTSC), number of rasters for each frame (312 for PAL, 261 for NTSC non-interlaced [1]), the correct position of the change of the $9004 raster counter for the next "double-line" (somewhere in the HSync/HBlank area for PAL, in the middle of the raster line with NTSC - for non-obvious reasons!), the correct behaviour of the VIA timer #1 (it underflows to $FFFF and restarts with the latched value in the next cycle) and, of course, a cycle-correct implementation of the CPU interrupt sequence. If any of those isn't to spec, the routine doesn't work as intended.


[1]: as enabled/disabled by bit 7 in $9000. The colour interlace of the routine doesn't have anything to do with that and is done by changing between two colour tables on alternate frames.
lance.ewing
Vic 20 Afficionado
Posts: 413
Joined: Sat Nov 10, 2012 3:19 pm
Website: https://sites.google.com/site/mos6561vic/

Re: Interrupt behaviour of the 6502 in emulation

Post by lance.ewing »

Mike wrote:Correct. If you use at least a fairly recent version of VICE, that is.
I've tried 3.1 and 3.3. They both appear the same. This is what it looks like on VICE when it is partway down "converting" the image to grayscale:
avril_yellow_band.png
avril_yellow_band.png (28.26 KiB) Viewed 4769 times
What my emulator doesn't have is the yellow band in the middle. I described it wrong in my previous post.

Taking a closer look, there are three main differences between VICE and my emulator:

1. During the grayscale conversion, I have black borders to the side of the whole text window area, up until the conversion line crosses each line, after which the border is yellow. In VICE, it has that yellow band in the middle that goes across the whole of the text window area before the conversion line gets to that point. My emulator doesn't have this.

2. The screen refresh rate after the whole image is converted is different. In VICE, the colours are changing fast enough for my eyes to nearly be tricked into thinking it is grayscale (on a real machine with CRT, it probably works even better, due to phosphor fading I'd imagine). On my emulator, I get a lot more obvious flashing, almost as if the screen isn't being updated as often as in VICE. This must be something to do with the rate at which the emulator window is being refreshed and not the rate that the VIC screen is being drawn, i.e. the emulator is failing to show some of the frames even though they've been drawn. That's my current theory. Update: I've done some checking and the screen refresh is fine. It is actually updating the screen 60 times a second (confirmed by counting render calls), which is more often than the VIC screen is updating. What I mean is that the window content is being redrawn 60 FPS but a VIC screen frame is being completed 50 times a second. The window render is only ever given completed VIC frames, so there is no chance of a partially rendered VIC frame being shown. So maybe its the yellow images mentioned in #3 below that are making it flash more obviously.

3. On VICE, when I drag the window and the screen refresh pauses, I can sometimes see a predominantly purple image, sometimes green. On my emulator when I do the same, i.e. drag to pause the refresh, I also sometimes seem predominantly purple, sometimes green, but also a predominantly yellow image. So it seems to be flashing through that as well, which appears to be wrong. That could be contributing to the more "flashy" appearance as well. - Any thoughts on what could be causing this?

The other difference is the palette I'm using for the colours. I still haven't settled on a final set of RGB values. Due to the way I'm doing it, I have to define the RGB values in RGB565 format, i.e. in 16-bits with Green getting an extra bit. A little unusual I know, but its what I have at the moment (I switched to using this years ago when I thought it would help reduce data being sent to the GPU. I was doing a lot of testing on various Android phones and trying to come up with something that would still perform okay even on older lower spec phones).
Mike wrote:You should see a plain stable yellow border,
Yes, have this.
Mike wrote:the greyscale image is produced by interlacing light green and light purple for light grey and green and purple for (normal) grey.

If there are any yellow patches/stripes within the picture, that's wrong.
So if sometimes the whole image is mostly yellow, then that sounds bad. It's not just a stripe or patch, but mostly yellow.
Mike wrote:If you see black stripes within the border, that's also wrong.
I don't have any black stripes in the border, so that is good.
Mike wrote:Hardware has it, that changes of the colour registers happen one pixel late with respect to (half-)char boundaries, so there's a noticable single hires pixel thick black line between picture and right yellow border, that's O.K. - there's nothing one can do about this.
I don't have this either, but sounds like I should.
Mike wrote:The routine critically depends on the correct number of cycles for each raster (71 for PAL, 65 for NTSC), number of rasters for each frame (312 for PAL, 261 for NTSC non-interlaced [1]), the correct position of the change of the $9004 raster counter for the next "double-line" (somewhere in the HSync/HBlank area for PAL, in the middle of the raster line with NTSC - for non-obvious reasons!), the correct behaviour of the VIA timer #1 (it underflows to $FFFF and restarts with the latched value in the next cycle) and, of course, a cycle-correct implementation of the CPU interrupt sequence. If any of those isn't to spec, the routine doesn't work as intended.
I'm running it in PAL mode, and the cycles per line are 71, and the lines are 312. So that part is fine. The raster counter should in theory be correct, but I'll take a look at that to see if maybe I'm setting that at the wrong time. - I have the underflow to 0xFFFF in the VIA timer 1 already. I fixed that about mid last year when I was working on an Oric emulator and discovered I didn't have that underflow bit working properly. The cycle correct interrupt sequence might need some looking at. It is possible there could be something in there that isn't happening at the right time.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Interrupt behaviour of the 6502 in emulation

Post by Mike »

The forum software ate a longer reply, so here's the short version:

Any difference during the 'greyscale conversion' (which really is the setup of the colour tables) can be attributed to different RAM init patterns. Nothing serious.

The appearance of pre-dominantly green or purple colour when stopped is due to the dithering pattern. The colour tables interleave the green and purple scheme between even and odd rasters in a frame, and exchange those schemes on alternate frames. Bands of intermediary colours with single height pixels expose this. Nothing serious either.

If you see flashes of yellow inside the border - in your emulator - when the colour tables have been set up, then the IRQ jitter compensation is outside range and bails out for that frame. It is supposed to work for all combinations of instructions, as long as interrupts are enabled - sadly, the processing of the keyboard buffer disables IRQs for a short time, which may trigger that bail-out, but that shouldn't be relevant here. There's a quirk in the 6502 where a taken branch of 3 cycles delays interrupt processing until the next instruction has also been executed - have you taken this into account?

...

The effect *is* a nightmare for any frame rate converter, though. Best thing is to output at exactly the original frame rate to avoid time-domain moiré/aliasing effects. :)
lance.ewing
Vic 20 Afficionado
Posts: 413
Joined: Sat Nov 10, 2012 3:19 pm
Website: https://sites.google.com/site/mos6561vic/

Re: Interrupt behaviour of the 6502 in emulation

Post by lance.ewing »

Mike wrote:The forum software ate a longer reply, so here's the short version:
That has certainly happened to me before... multiple times. That's what happens when we write too much, and I'm the worst offender. :D
Mike wrote:Any difference during the 'greyscale conversion' (which really is the setup of the colour tables) can be attributed to different RAM init patterns. Nothing serious.
Hmmm, okay. I'll try different RAM configurations and see what difference that makes in my emulator. - Do you mean different RAM configurations? Or different default values for the RAM (prior to being written to)?
Mike wrote:If you see flashes of yellow inside the border - in your emulator - when the colour tables have been set up, then the IRQ jitter compensation is outside range and bails out for that frame. It is supposed to work for all combinations of instructions, as long as interrupts are enabled - sadly, the processing of the keyboard buffer disables IRQs for a short time, which may trigger that bail-out, but that shouldn't be relevant here. There's a quirk in the 6502 where a taken branch of 3 cycles delays interrupt processing until the next instruction has also been executed - have you taken this into account?
I can't remember implementing that, which probably means it doesn't take that into account. I wrote most of the 6502 code back in 2003. It is a cycle based emulation, and based mostly on the information in the Synertek Programming/Hardware Manuals (which I had a physical copy of at the time). I guess even if they covered this quirk (which I'm assuming is unlikely), then I could easily have missed it.

I'm going to check this over this evening. It sounds like, if you have thought of it as a possibility, and I can't remember implementing that, then it could be the offender.

I was trying Cheese and Onion on the emulator last night and noticed that it was shaking quite a lot, which doesn't happen on the real VIC machine. So there is definitely something not right. - I also tried Pitfall but that seemed to be working fine.
Mike wrote:The effect *is* a nightmare for any frame rate converter, though. Best thing is to output at exactly the original frame rate to avoid time-domain moiré/aliasing effects. :)
I suspect that on some devices, I won't be able to specify the "frontend FPS" rate and have it reliably be adhered to. But on desktop it seems that it respects it.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Interrupt behaviour of the 6502 in emulation

Post by Mike »

lance.ewing wrote:Or different default values for the RAM (prior to being written to)?
This.

Your emulator for sure presets the RAM with all bytes zero. That's not what you'll usually see on real h/w after power on: with my VIC-20 prior to the VFLI mod, I had the pattern 0,255,0,255,0,255,... - the last one or two bytes on each page having differing values.

VICE per default presets/inits the RAM with 64x 0, 64x 255 (and repeat), that's why you see the yellow stripe while the colour tables are written. This RAM init pattern is more typical though for DRAM machines.
lance.ewing
Vic 20 Afficionado
Posts: 413
Joined: Sat Nov 10, 2012 3:19 pm
Website: https://sites.google.com/site/mos6561vic/

Re: Interrupt behaviour of the 6502 in emulation

Post by lance.ewing »

Mike wrote:Your emulator for sure presets the RAM with all bytes zero.
Yes, that's correct.
Mike wrote:that's why you see the yellow stripe while the colour tables are written.
Hmmm, I see. Make's sense.
Mike wrote:This RAM init pattern is more typical though for DRAM machines.
This reminds me that when I wrote my Oric emulator, I couldn't get it to work unless I initialised the RAM in a certain way. It wouldn't work if all the RAM started with zero.
Mike wrote: There's a quirk in the 6502 where a taken branch of 3 cycles delays interrupt processing until the next instruction has also been executed - have you taken this into account?)
I have now implemented this behaviour (it wasn't there already, which isn't surprising, because I wrote that code back in 2003, and the earliest reference I can find to the discovery of this IRQ behaviour is from 2006). But having done this, it didn't seem to make any difference. The "yellow" frames were still showing up just as frequently.

I did manage to make them completely disappear though. But that was by adding another cycle to my IRQ steps. It already had the seven cycles, which should have been right. But after putting another cycle at the start (just a dummy fetch of memory using the PC that is discarded), thereby making it 8 cycles, the "yellow" frames completely disappeared, and it now looks pretty much like it does in VICE.

This has made me start to think that something else is going on in my emulator. Maybe the IRQs are not actually taking up 7 cycles. Maybe the switch from a normal instruction to the IRQ "instruction" is happening too quickly and there is actually a cycle in between. I think I need to read up more on the cycles that happen over the last instruction before an IRQ, through the IRQ, up to the IRQ routine. There must be something not quite right.

Strangely, if I add yet another cycle to it (9 cycles), then your Avril program still works fine without any "yellow" frames.
User avatar
Mike
Herr VC
Posts: 4841
Joined: Wed Dec 01, 2004 1:57 pm
Location: Munich, Germany
Occupation: electrical engineer

Re: Interrupt behaviour of the 6502 in emulation

Post by Mike »

You didn't tell at first that the glitches would appear much more often. :wink:
lance.ewing wrote:This has made me start to think that something else is going on in my emulator. Maybe the IRQs are not actually taking up 7 cycles. Maybe the switch from a normal instruction to the IRQ "instruction" is happening too quickly and there is actually a cycle in between. I think I need to read up more on the cycles that happen over the last instruction before an IRQ, through the IRQ, up to the IRQ routine. There must be something not quite right.
This instruction trace here is for PAL and was intended to infer the maximum value that can appear in the low-byte of VIA #2 timer 1 when the register fetch of the SBC instruction is performed. This is crucial for the correct choice of the 'phase' value in the source (see the LDA #xx down there). In that case, the IRQ has performed in the minimum time thus the branch distance is supposed to be zero to 'waste' the most cycles in the LDA #$A9 slide to compensate the jitter:

Code: Select all

                                               Bxx        3  $FF, $86..$85
                                    ..$FF      RMW ABS,X  7  $84..$7E
       00        BRK          7  $86..$80                    $7D..$77
.FF72  48        PHA          3  $7F..$7D                    $76..$74
.FF73  8A        TXA          2  $7C..$7B                    $73..$72
.FF74  48        PHA          3  $7A..$78                    $71..$6F
.FF75  98        TYA          2  $77..$76                    $6E..$6D
.FF76  48        PHA          3  $75..$73                    $6C..$6A
.FF77  BA        TSX          2  $72..$71                    $69..$68
.FF78  BD 04 01  LDA $0104,X  4  $70..$6D                    $67..$64
.FF7B  29 10     AND #$10     2  $6C..$6B                    $63..$62
.FF7D  F0 03     BEQ $FF82    3  $6A..$68                    $61..$5F
.FF82  6C 14 03  JMP ($0314)  5  $67..$63                    $5E..$5A
       D8        CLD          2  $62..$61                    $59..$58
       38        SEC          2  $60..$5F                    $57..$56
       A9 xx     LDA #$xx     2  $5E..$5D                    $55..$54
       ED 24 91  SBC $9124    4  $5C..$59                    $53..$50
Even though I thought it to be derived from first principles - IRQ happening when timer underflows to $FFFF, and happening in the last cycle of the preceding instruction, then entering the interrupt sequence immediately by inserting a BRK instruction in the instruction stream - the derived value of $59 is not correct!

What you see empirically is, that the value never exceeds $58 (and this is what I use in my routine for PAL), on the proviso there are no extended code blocks enclosed in SEI/CLI, of course. I 'measured' this with a small test program with some mixed instructions in the non-IRQ main part (to hopefully produce all kind of delays) and then storing away the value of $9124 at that position into a truth table instead of performing a raster effect:

Image

As you see, there are no 'hits' for 89 (corresponding to $59), rather the maximum value is 88.

You find this bahaviour explained in the Synertek Programming Manual, see page 131: the 6502 performs minimal pipelining: IRQ going low is checked for in the last execute stage of an instruction, but that is done while the first byte of the following instruction is already fetched! Now 6502 does that dummy (opcode) fetch of the following instruction and only then inserts the BRK instruction. This incurs an extra cycle you don't see in the instruction trace above. The Interrupt Sequence truly needs 8 cycles! :mrgreen:

Now what we see in the photo above is, that the values span the range 88 down to 80, with 80 corresponding to the maximum delay before entering the IRQ sequence. The right side of my table (RMW + 3-cycle branch) isn't quite correct either, even if it seems to come out at the correct value - with 8 cycles in the IRQ sequence that would go down to $4F. In some cases, when the IRQ happens 'early' enough, the IRQ sequence can proceed as normal for the 3-cycle branch. Nonetheless, that quirk extends the jitter range to 9 different values even though you'd normally only expect 7 different values, for the maximum number of instruction cycles of the official opcodes: 7 cycle opcodes can delay 0..6 cycles before the IRQ sequence is started, 2 cycle opcodes can still delay either 0 or 1 cycle.

Note the combination of a 3-cycle branch + undocumented RMW instruction can add yet another cycle (I didn't test that in the photo above), getting you a value of $4F (^= 79), as those instructions take up to 8 cycles!
Strangely, if I add yet another cycle to it (9 cycles), then your Avril program still works fine without any "yellow" frames.
Yes. The delay slide can cope with slightly bigger jitter because an earlier version of VICE made me think that would be necessary.

In any case, the IRQ sequence is confirmed to take 8 cycles (with a dummy opcode fetch of the following instruction). I still have to find out, where and why the 3-cycle branch sometimes does introduce the extra delay, and when it does not.

Greetings,

Michael
lance.ewing
Vic 20 Afficionado
Posts: 413
Joined: Sat Nov 10, 2012 3:19 pm
Website: https://sites.google.com/site/mos6561vic/

Re: Interrupt behaviour of the 6502 in emulation

Post by lance.ewing »

Thanks for this information Mike. I'll need to spend some time studying it.

Another thing I haven't implemented yet are the undocumented 6502 instructions. I think I figured there wasn't much use of these on the VIC 20, but I've come across a few things that are using them recently, so I'm going to have a go now at implementing those.
Post Reply