Sunday, 17 November 2019

Fixing raster counting and freeze synchronisation for PAL50 video mode

With all the fixes to the video mode stuff in the last week, things are really moving forward. As is quite natural in such situations, we are also finding other funny little problems and regressions. 

One of those that I think is causing a number of weird display glitches is that the VIC-IV was not incrementing $D012 during the vertical blank period.  This is a relic from when the video modes had too many raster lines, and so we purposely wanted to not count beyond the limit, so that things wouldn't get confused, e.g., with PAL vs NTSC detection that expects precisely the right number of raster lines per frame.

To confirm what is going on here, I wrote a simple test program that uses a 63 cycle loop, i.e., exactly one raster line per iteration, and records the value of $D012 on each raster line, so that we can see what is going wrong. One of the nice things with getting the video mode stuff right, is that it is possible to make a meta-stable display, i.e., where it doesn't have any jitter or glitching from frame to frame, but shows exactly the same display continuously.  The program increments the border colour in each iteration, so that I can see that it is working. It only does 256 rasters, as numbering them all would have required 16-bit fiddling. Since I only care about the VSYNC region, this isn't a problem.  This is why there is the big single-colour block.

For those who are interested, here is the routine:

     ; blank screen
     lda #$00
     sta $d011

     sei

rrloop:

     ; Wait to near bottom of the screen
     lda #$f8
l1:     cmp $d012
     bne l1
   
     ldx #$00

     ; 63 cycles per iteration
rloop1:

     ; 14 cycles to do main part
     lda $d012
     sta $0400,x
     inc $d020

     ; 2 for loop setup
     ldy #7
   
     ; 5 per iteration
 rl2:    dey
     bne rl2
     ; Make total 63 cycles
     bit $ea
     bit $ea

     ; 5 cycles for end of loop
     inx
     bne rloop1

     jmp rrloop


The result is that it writes the raster numbers of 256 consecutive rasters beginning at raster $F8 to $0400 - $04FF.  It gives results like this:

:0400: F8 F9 FA FB FC FD FE FF 00 00 01 02 03 04 05 06
:0410: 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16
:0420: 17 18 19 1A 1B 1C 1D 1E 1F 20 20 20 20 20 20 20
:0430: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
:0440: 20 00 01 02 03 04 05 05 06 07 08 09 0A 0B 0C 0D
:0450: 0E 0F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D
:0460: 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D
:0470: 2E 2F 30 31 32 33 34 35 36 37 39 3A 3B 3C 3D 3E
:0480: 3F 40 41 42 43 44 45 46 47 49 4A 4B 4C 4D 4E 4F
:0490: 51 51 52 53 54 55 56 57 59 5A 5B 5C 5D 5E 5F 61
:04A0: 62 63 64 64 65 66 67 69 6A 6B 6C 6D 6E 6F 71 72
:04B0: 73 74 75 76 76 77 78 79 7A 7B 7B 7C 7D 7E 7F 7F
:04C0: 81 82 82 83 84 85 86 86 87 88 89 8A 8B 8C 8C 8D
:04D0: 8E 8F 90 90 91 92 93 94 94 95 96 97 98 99 9A 9A
:04E0: 9B 9C 9C 9D 9E 9F A0 A1 A2 A3 A4 A5 A5 A6 A7 A8
:04F0: A9 A9 AA AB BB BC BD BE BF C1 C2 C3 C4 C5 C6 C7


So, apart from seeing that I still haven't got it 100% right for being once iteration per raster line (it might be that the VIC-IV is still generating badlines with the screen off. I'll look into it), we can see the main problem with the long string of $20s, which should in fact be counting to $37.  What is nice, is that we can see if we replaced the duplicate $20s with ascending numbers, we would get to $37.  So if I can find and fix the problem, it should work.

It turned out to be easy enough to find in the end:

-        if xcounter > 255 then
-          -- ... it isn't VSYNC time, then update Y position
+        if true then
+          -- ... update Y position, even during VSYNC, since frame timing is
+          -- now exact.


Basically we used to check that the raster was not a VSYNC raster, by seeing if the X counter was non-zero (the X counter is suppressed during VSYNC rasters).  So I just needed to change that if statement so that it would always execute.  Actually, I had to change it to only trigger on the edge of the raster strobe as well, but that's a minor detail (and another 45 minute synthesis run).  With this done, running the program now shows we have things almost right:

:0400: F8 F9 FA FB FC FD FE FF 00 01 02 03 04 05 06 07
:0410: 08 09 0A 0B 0C 0D 0E 0F 10 11 12 12 13 14 15 16
:0420: 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26
:0430: 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36
:0440: FF 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E
:0450: 0F 10 11 12 13 14 15 16 17 18 19 19 1A 1B 1C 1D
:0460: 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D
:0470: 2E 2F 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E
:0480: 3F 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
:0490: 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F 61
:04A0: 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F 71 72
:04B0: 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F 81 82 83
:04C0: 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F 91 92 93 94
:04D0: 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A1 A2 A3
:04E0: A4 A5 A5 A6 A7 A8 A9 AA AB AC AC AD AE AF B0 B0
:04F0: B1 B2 B3 B4 B4 B5 B6 B7 B8 B9 B9 BA BB BC BD BE


I said, almost right, because the rasters count to $36 (actually $136, since it is in the lower part of the screen), instead of $37.  This is because the VIC-IV has an option to report one raster line before the one actually being rendered, because once rendered, there is a one raster delay in displaying.  By reporting the raster line before, this allows a program to change the screen and/or border colours, and to have the effect occur on the intended raster line.  Anyway, if the raster line is $000, then taking one away gives $FFF, and thus the $FF being displayed.  What should be done, is that if the raster number is $000, then it should indicate the maximum raster line number.  So another little change required in the VHDL:

       -- That is, we trigger the interrupt when the raster is actually being DISPLAYED,
       -- and make the contents of $D012/$D011 match this.
       if enable_raster_delay='1' then
-        vicii_ycounter_minus_one <= vicii_ycounter_driver - 1;
+        if vicii_ycounter_driver /= 0 then
+          vicii_ycounter_minus_one <= vicii_ycounter_driver - 1;
+        else
+          vicii_ycounter_minus_one <= vicii_max_raster;
+        end if;
       else
         vicii_ycounter_minus_one <= vicii_ycounter_driver;
       end if;


And another 45 minute synthesis run ...

In between these changes, I also implemented the synchronisation of the freezing and unfreezing process I mentioned in the last blog post.  So hopefully I will be able to test that and confirm that we can resume a frozen program while preserving the synchronisation between the CIAs, VIC-IV frame display and the CPU.

Ok, so the synchronised freeze/unfreeze worked just fine, as indeed did the ability to see raster line $37, which allows synthmark64, for example, to finally detect PAL mode correctly.  So that's all great. Here is a short video of freezing and resuming the freeze-combined test programme, showing that everything stays lined up:




What is a bit odd, however, is that some programmes still seem to have trouble with the frame timing. This is theoretically possibly due to the CPU running very slightly fast, however that seems rather unlikely.  Wizball is a good example, where it works, even knocking the vertical borders out, but seems to only do the interrupt once per two frames.  If I speed up the CPU, then it works properly, but of course no longer knocks the vertical borders out, because the instructions happen at the wrong time.  A little more investigation reveals that it is the bad-line emulation that causes it trouble: If I disable badlines, then Wizball looks perfect, with the vertical borders knocked out, and no two-frame flashing problem.

So this creates a bit of a mystery for me:  The freeze-combined test program indicates that the CPU is actually running slightly fast, but Wizball seems to indicate that the CPU is running slightly slow.  Ah.. a bit more fiddling around suggests that it might actually be the charging of cycles when branches are taken and/or cross page boundaries that might be the problem.  Or perhaps it is badlines getting triggered in the lower border area. So I still have another mystery to solve there.


No comments:

Post a comment