Rybags Posted July 4, 2010 Share Posted July 4, 2010 The old Scanline 240 bug... a mystery and annoyance for decades, but hey - it does allow us to do the 480i Interlaced mode. But still, for those instances where we want a full 240 scanlines of hires, or simply just to have the last displayed line as hires, it sticks it's head in and spoils the party. But, it can be overcome. I've devised a few methods, each with it's advantages and disadvantages. Why does this bug even occur? The problem occurs because Antic doesn't properly disable it's display generation on the normal last line of the display if it happens to be a Hires mode (2, 3 or F). What happens is that rather than sending a constant HBLANK command to GTIA, it will constantly send the command to generate 2 pixels of hires "on" pixels when the display would normally be active, then send the HBLANK command again each scanline, except at the wrong time. The effect of this is that the HSync pulses jump out of step, and most TV displays will become warped. How can we fix it? The fix is easy. All we need to do is have a DLI on the last line displayed, and set DMACTL such that screen DMA is turned off, but Display List DMA is left on. That's only half the job though, we need to set things back to normal, but it has to be done again after the VBlank, just before the normal display resumes again. SL240a.xex Note that a real machine is needed here, emulation doesn't reproduce the Scanline 240 bug. Also, if you don't know what this bug is, just type "POKE 560,0" in BASIC and it should manifest itself. Method 1 uses a DLI at the top and bottom of the screen. The DLI at the top enables normal screen DMA, the one at the bottom sets Antic DMA such that DList instructions will be read but screen DMA won't be attempted. Advantage: low CPU usage, simple programming with just the 2 DLIs required. Disadvantage: at minimum, you will lose at least one scanline at the top of the display, which in a way defeats the purpose of the whole process. The problem with using the DLI at the top is that the DLI itself doesn't get executed until the screen display has already started. Getting late here and the other examples I have planned aren't ready, but I can give the overview. Method 2 uses a DLI at the bottom of the screen as per 1, but instead of a DLI at the top of screen, we can utilise the VBlank NMI. Then all we do is loop around waiting for just before the active display, and re-enable DMA before it starts. Advantage: we can use the entire 240 scanlines unimpeded. Disadvantage: somewhat large waste of CPU in the wait loop, although of course most of that time could be dedicated to doing other stuff. Alternatively of course, a Pokey Timer could be used, but that brings problems of its own. AtAsm Source Listing of Method 1: ; ; Defeat the Scanline 240 bug ; sdslst = $230 sdmctl = $22f wsync = $d40a nmien = $d40e dmactl = $d400 ; *=$4000 ; ldx 20 inx wait1 cpx 20 bne wait1 lda #<dlist ldx #>dlist sta sdslst stx sdslst+1 lda #<dli1 ldx #>dli1 sta $200 stx $201 lda #<vbi ldx #>vbi sta $222 stx $223 lda #$20 sta sdmctl lda #$c0 sta nmien ldx #3 setcols lda colour_table,x sta $2c5,x dex bpl setcols wait2 jmp wait2 vbi lda #<dli1 ldx #>dli1 sta $200 stx $201 jmp $e45f ; dli1 pha lda sdmctl ora #2 sta dmactl lda #<dli2 sta $200 lda #>dli2 sta $201 pla rti dli2 pha lda sdmctl and #$fc sta wsync sta dmactl pla rti colour_table .byte $ca,$82,$48,$32 ; dlist .byte $f0 .byte $42 .word screen1 .byte 2,2,2,2,2 .byte 2,2,2,2,2 .byte 2,2,2,2,2 .byte 2,2,2,2,2 .byte 2,2,2,2,2 .byte 2 .byte 2,$82,$41 .word dlist screen1 .sbyte " " ; 1 .sbyte " " ; 2 .sbyte " How to defeat the Scanline 240 bug " ; 3 .sbyte " Method 1 " ; 4 .sbyte " " ; 5 .sbyte " This method uses a DLI at the top of " ; 6 .sbyte " screen and bottom of screen. " ; 7 .sbyte " The advantage is we use less CPU. " ; 8 .sbyte " But the disadvantage is that we lose " ; 9 .sbyte " The top scanline of the display, which " ; 10 .sbyte " sort of defeats the purpose. " ; 11 .sbyte " " ; 12 .sbyte " Note that the blank 8 lines above " ; 13 .sbyte " are just filler in this example. ANTIC" ; 14 .sbyte " won't run a DLI on a text line that is " ; 15 .sbyte " truncated by the last scanline, but " ; 16 .sbyte " that problem could be overcome by " ; 17 .sbyte " generating a shortened character line " ; 18 .sbyte " by using V-Scrolling. " ; 19 .sbyte " " ; 20 .sbyte " " ; 21 .sbyte " " ; 22 .sbyte " " ; 23 .sbyte " " ; 24 .sbyte " " ; 25 .sbyte " " ; 26 .sbyte " " ; 27 .sbyte " " ; 28 .sbyte " Last visible line of the display here. " ; 29 2 Quote Link to comment Share on other sites More sharing options...
atariksi Posted July 5, 2010 Share Posted July 5, 2010 The old Scanline 240 bug... a mystery and annoyance for decades, but hey - it does allow us to do the 480i Interlaced mode. But still, for those instances where we want a full 240 scanlines of hires, or simply just to have the last displayed line as hires, it sticks it's head in and spoils the party. But, it can be overcome. I've devised a few methods, each with it's advantages and disadvantages. Why does this bug even occur? The problem occurs because Antic doesn't properly disable it's display generation on the normal last line of the display if it happens to be a Hires mode (2, 3 or F). What happens is that rather than sending a constant HBLANK command to GTIA, it will constantly send the command to generate 2 pixels of hires "on" pixels when the display would normally be active, then send the HBLANK command again each scanline, except at the wrong time. The effect of this is that the HSync pulses jump out of step, and most TV displays will become warped. How can we fix it? The fix is easy. All we need to do is have a DLI on the last line displayed, and set DMACTL such that screen DMA is turned off, but Display List DMA is left on. That's only half the job though, we need to set things back to normal, but it has to be done again after the VBlank, just before the normal display resumes again. SL240a.xex Note that a real machine is needed here, emulation doesn't reproduce the Scanline 240 bug. Also, if you don't know what this bug is, just type "POKE 560,0" in BASIC and it should manifest itself. Method 1 uses a DLI at the top and bottom of the screen. The DLI at the top enables normal screen DMA, the one at the bottom sets Antic DMA such that DList instructions will be read but screen DMA won't be attempted. Advantage: low CPU usage, simple programming with just the 2 DLIs required. Disadvantage: at minimum, you will lose at least one scanline at the top of the display, which in a way defeats the purpose of the whole process. The problem with using the DLI at the top is that the DLI itself doesn't get executed until the screen display has already started. Getting late here and the other examples I have planned aren't ready, but I can give the overview. Method 2 uses a DLI at the bottom of the screen as per 1, but instead of a DLI at the top of screen, we can utilise the VBlank NMI. Then all we do is loop around waiting for just before the active display, and re-enable DMA before it starts. Advantage: we can use the entire 240 scanlines unimpeded. Disadvantage: somewhat large waste of CPU in the wait loop, although of course most of that time could be dedicated to doing other stuff. Alternatively of course, a Pokey Timer could be used, but that brings problems of its own. AtAsm Source Listing of Method 1: ; ; Defeat the Scanline 240 bug ; sdslst = $230 sdmctl = $22f wsync = $d40a nmien = $d40e dmactl = $d400 ; *=$4000 ; ldx 20 inx wait1 cpx 20 bne wait1 lda #<dlist ldx #>dlist sta sdslst stx sdslst+1 lda #<dli1 ldx #>dli1 sta $200 stx $201 lda #<vbi ldx #>vbi sta $222 stx $223 lda #$20 sta sdmctl lda #$c0 sta nmien ldx #3 setcols lda colour_table,x sta $2c5,x dex bpl setcols wait2 jmp wait2 vbi lda #<dli1 ldx #>dli1 sta $200 stx $201 jmp $e45f ; dli1 pha lda sdmctl ora #2 sta dmactl lda #<dli2 sta $200 lda #>dli2 sta $201 pla rti dli2 pha lda sdmctl and #$fc sta wsync sta dmactl pla rti colour_table .byte $ca,$82,$48,$32 ; dlist .byte $f0 .byte $42 .word screen1 .byte 2,2,2,2,2 .byte 2,2,2,2,2 .byte 2,2,2,2,2 .byte 2,2,2,2,2 .byte 2,2,2,2,2 .byte 2 .byte 2,$82,$41 .word dlist screen1 .sbyte " " ; 1 .sbyte " " ; 2 .sbyte " How to defeat the Scanline 240 bug " ; 3 .sbyte " Method 1 " ; 4 .sbyte " " ; 5 .sbyte " This method uses a DLI at the top of " ; 6 .sbyte " screen and bottom of screen. " ; 7 .sbyte " The advantage is we use less CPU. " ; 8 .sbyte " But the disadvantage is that we lose " ; 9 .sbyte " The top scanline of the display, which " ; 10 .sbyte " sort of defeats the purpose. " ; 11 .sbyte " " ; 12 .sbyte " Note that the blank 8 lines above " ; 13 .sbyte " are just filler in this example. ANTIC" ; 14 .sbyte " won't run a DLI on a text line that is " ; 15 .sbyte " truncated by the last scanline, but " ; 16 .sbyte " that problem could be overcome by " ; 17 .sbyte " generating a shortened character line " ; 18 .sbyte " by using V-Scrolling. " ; 19 .sbyte " " ; 20 .sbyte " " ; 21 .sbyte " " ; 22 .sbyte " " ; 23 .sbyte " " ; 24 .sbyte " " ; 25 .sbyte " " ; 26 .sbyte " " ; 27 .sbyte " " ; 28 .sbyte " Last visible line of the display here. " ; 29 Doesn't OS VBI already copy shadow register 559 to 54272 to re-enable normal display dma? Quote Link to comment Share on other sites More sharing options...
Rybags Posted July 5, 2010 Author Share Posted July 5, 2010 Yep, but we can't use "normal DMA" until the normal screen display starts, otherwise the bug kicks in. So therefore, we set SDMCTL to $20 which allows normal DList processing, and have the DLIs turn the normal screen DMA on and off at the appropriate times. Quote Link to comment Share on other sites More sharing options...
bugbiter Posted July 7, 2015 Share Posted July 7, 2015 (edited) Thanks for explaining! I managed to get my APAC viewer from 239i to 240 interlaced lines now! Edited July 7, 2015 by bugbiter 2 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.