Jump to content
IGNORED

Overcoming the Scanline 240 "bug"


Rybags

Recommended Posts

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

 

 

 

  • Like 2
Link to comment
Share on other sites

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?

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

  • 5 years later...

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