CaptMatteus Posted January 29, 2021 Share Posted January 29, 2021 (edited) I had been looking for a complete example of how to do double buffering on the Atari 800, but although there are some extracts from very sophisticated programs, the basics were not represented. I decided to create my own example to build upon. My example creates two graphics mode 0 display lists, and plants a couple of words to show that the screens are being swapped. I use a deferred mode vertical blank interrupt routine to switch between the two. Enjoy! *= $3000 Counter = $A2 ListInUse = $A3 .include "hardware.s" init ; load display list 0 LDA #<dlist_0 STA sdlstl LDA #>dlist_0 STA sdlstl+1 ; for graphics mode 0, we can set the background color and a foreground luminance ; wheich here will be the text color LDA #$0 ; Mode 0 background color STA COLOR2 LDA #$0E ; Mode 0 foreground luminance STA COLOR1 ; set up counter and current disply list in use variable LDA #0 STA Counter STA ListInUse ; set up registers to insert our vertical blank interrupt routine LDY #<vbi_isr ; Y gets low address byte of ISR LDX #>vbi_isr ; X gets high byte of ISR LDA #7 ; use deferred routine JSR SETVBV ; execute call forever JMP forever * = $3500 vbi_isr PHA ; save accumulator INC Counter ; increment timer by 1/60 sec LDA Counter CMP #$30 ; has half a second gone by? BCS SwapDL ; Yes -> so go swap the display lists JMP vbidone ; no -> do nothing and return SwapDL LDA #0 ; before swapping... STA Counter ; reset counter LDA ListInUse ; get current display list in use BEQ ToDL1 ; LDX sets Z flag; if 0 -> switch to DL1 LDA #0 ; Currently using DL1 -> switch to DL0 STA ListInUse LDA #<dlist_0 ; point OS to DL0 STA sdlstl LDA #>dlist_0 STA sdlstl+1 JMP vbidone ToDL1 LDA #1 ; Currently using DL0 -> switch to DL1 STA ListInUse LDA #<dlist_1 ; Point OS to DL1 STA sdlstl LDA #>dlist_1 STA sdlstl+1 vbidone PLA ; before exiting ISR, reset former accumulator state JMP XITVBV ; mode 0 display lists * = $7800 dlist_0 .byte $70,$70,$70 ; 24 blank scan lines .byte $42,$00,$90 ; Line of mode 0, LMS @ $9000 .byte $2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2, ; 11 lines of mode 0 .byte $2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2, ; 12 lines of mode 0 .byte $41,<dlist_0,>dlist_0 * = $7900 dlist_1 .byte $70,$70,$70 ; 24 blank scan lines .byte $42,$00,$95 ; Line of mode 0, LMS @ $9500 .byte $2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2, ; 11 lines of mode 0 .byte $2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2, ; 12 lines of mode 0 .byte $41,<dlist_1,>dlist_1 * = $91F2 .sbyte "Tick" * = $971A .sbyte "Tock" ; tell DOS where to run the program when loaded * = $2e0 .word init Bufferx2mode0.s Edited January 29, 2021 by CaptMatteus 1 Quote Link to comment Share on other sites More sharing options...
TGB1718 Posted January 29, 2021 Share Posted January 29, 2021 Not so much double buffering, but I'm currently writing a utility that uses 2 different screen modes Graphics 0 and graphics 3. I'm writing in cc65 and what I do is use keyboard input to switch between screens. First reserve memory for the screens and save each screens details // make both screens and reserve space void makescreens(void) { _graphics(0); textdl=PEEKW(560); textscn=PEEKW(88); textmode=PEEK(87); textlines=PEEK(703); OS.ramtop=OS.ramtop-8; _graphics(3); spritedl=PEEKW(560); spritescn=PEEKW(88); spritemode=PEEK(87); spritelines=PEEK(703); OS.ramtop=OS.ramtop-4; POKE(752,1); } then when menu key pressed // open text screen POKEW(560,textdl); POKEW(88,textscn); POKE(87,textmode); POKE(703,textlines); POKE(752,1); POKE(HPOSP0,0); // hide players POKE(HPOSP1,0); POKE(HPOSP2,0); ********* CODE GOES HERE // restore PM screen POKEW(560,spritedl); POKEW(88,spritescn); POKE(87,spritemode); POKE(703,spritelines); OS.sdmctl=46; POKE(GRACTL,3); POKE(752,1); POKE(HPOSP0,HP0); // hide players POKE(HPOSP1,HP1); POKE(HPOSP2,HP2); Quote Link to comment Share on other sites More sharing options...
Rybags Posted January 30, 2021 Share Posted January 30, 2021 With deferred mode - the actual swap will be a frame behind since the VBD vector is called after the DList pointer and other shadow registers are copied. Also, you have the real risk of missing interrupts since VBD is skipped if IRQs are masked - which is a common thing when there's keyboard activity. Quote Link to comment Share on other sites More sharing options...
CaptMatteus Posted January 30, 2021 Author Share Posted January 30, 2021 12 hours ago, Rybags said: With deferred mode - the actual swap will be a frame behind since the VBD vector is called after the DList pointer and other shadow registers are copied. Also, you have the real risk of missing interrupts since VBD is skipped if IRQs are masked - which is a common thing when there's keyboard activity. Thanks for the feedback. I had not considered the update of the shadow registers. After reviewing De Re Atari I see that I need to place my ISR in the VBI immediate slot so that I update the DLIST pointer prior to the update of the shadow registers. Quote Link to comment Share on other sites More sharing options...
CaptMatteus Posted January 30, 2021 Author Share Posted January 30, 2021 So with that change the code looks like this: *= $3000 Counter = $A2 ListInUse = $A3 .include "hardware.s" init ; load display list 0 LDA #<dlist_0 STA sdlstl LDA #>dlist_0 STA sdlstl+1 ; for graphics mode 0, we can set the background color and a foreground luminance ; wheich here will be the text color LDA #$0 ; Mode 0 background color STA COLOR2 LDA #$0E ; Mode 0 foreground luminance STA COLOR1 ; set up counter and current disply list in use variable LDA #0 STA Counter STA ListInUse ; set up registers to insert our vertical blank interrupt routine LDY #<vbi_isr ; Y gets low address byte of ISR LDX #>vbi_isr ; X gets high byte of ISR LDA #6 ; use immediate routine JSR SETVBV ; execute call forever JMP forever * = $3500 vbi_isr INC Counter ; increment timer by 1/60 sec LDA Counter CMP #$30 ; has half a second gone by? BCS SwapDL ; Yes -> so go swap the display lists JMP SYSVBV ; no -> do nothing and return SwapDL LDA #0 ; before swapping... STA Counter ; reset counter LDA ListInUse ; get current display list in use BEQ ToDL1 ; LDX sets Z flag; if 0 -> switch to DL1 LDA #0 ; Currently using DL1 -> switch to DL0 STA ListInUse LDA #<dlist_0 ; point OS to DL0 STA sdlstl LDA #>dlist_0 STA sdlstl+1 JMP SYSVBV ToDL1 LDA #1 ; Currently using DL0 -> switch to DL1 STA ListInUse LDA #<dlist_1 ; Point OS to DL1 STA sdlstl LDA #>dlist_1 STA sdlstl+1 JMP SYSVBV ; mode 0 display lists * = $7800 dlist_0 .byte $70,$70,$70 ; 24 blank scan lines .byte $42,$00,$90 ; Line of mode 0, LMS @ $9000 .byte $2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2, ; 11 lines of mode 0 .byte $2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2, ; 12 lines of mode 0 .byte $41,<dlist_0,>dlist_0 * = $7900 dlist_1 .byte $70,$70,$70 ; 24 blank scan lines .byte $42,$00,$95 ; Line of mode 0, LMS @ $9500 .byte $2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2, ; 11 lines of mode 0 .byte $2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2,$2, ; 12 lines of mode 0 .byte $41,<dlist_1,>dlist_1 * = $91F2 .sbyte "Tick" * = $971A .sbyte "Tock" ; tell DOS where to run the program when loaded * = $2e0 .word init Quote Link to comment Share on other sites More sharing options...
Qwe Posted January 29 Share Posted January 29 Hi CaptMatteus, could you share the included file "hardware.s" ? Thank you Quote Link to comment Share on other sites More sharing options...
Mariano DM Posted January 30 Share Posted January 30 Not sure if it is useful. But I implemented double buffer in my 3d cube demo in c https://github.com/marianodominguez/8bit-samples/blob/master/cc65/simple_graph/src/cube_opt.c#L142-L160 the issues were mostly to align the jump instructions when you cross the 4k border it is gr.8 it looks decent enough Quote Link to comment Share on other sites More sharing options...
thank you Posted January 31 Share Posted January 31 On 1/29/2024 at 3:59 AM, Qwe said: Hi CaptMatteus, could you share the included file "hardware.s" ? Thank you hello, this file just defines some equates for memory locations. it looks like only five are used in the code... i think you can find a similar 'include' in the CC65/CA65 sources. sdlstl =$0240 setvbv = $E45C sysvbv = $E45F color0 = $02C4 color1 = $02C5 https://www.atariarchives.org/mapping/memorymap.php good luck! 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.