Jump to content
IGNORED

Multiple DLIs


Recommended Posts

Hi All.

 

I'm trying to create a simple(?) screen from Atari Basic. I'm aiming for 24 lines of Antic mode 4, but with each line having a choice of a different value for colour1, colour 2 and the character set (to make my life easier when wrting the game, or so I thought).

 

Here's what I want to attempt with my DLI (it's a modification of the example in De Re Atari...)

 

ORIGINAL DE RE:

PHA

TXA

PHA

INC COUNTR

LDX COUNTR

LDA COLTAB,X Use page two for color table

STA WSYNC Wait

STA COLBAK

CPX #$4F Last line?

BNE ENDDLI No, exit

LDA #$00 Yes, reset counter

STA COUNTR

ENDDLI PLA

TAX

PLA Restore accumulator

RTI

 

 

MINE PHA

TXA

PHA

INC COUNTR

LDX COUNTR

LDA COLTAB1,X Use end of page 6 for color table

STA WSYNC Wait

STA COLPF1

LDA COLTAB2, X A Second table for PF2

STA COLPF2

LDA CHARTAB, X A Third table for Character set

STA CHBASE

CPX #$23 Last line? (23 because I'm useing a 24 line screen all with interrupts)

BNE ENDDLI No, exit

LDA #$00 Yes, reset counter

STA COUNTR

ENDDLI PLA

TAX

PLA Restore accumulator

RTI

 

Can i get away with all the code after the wsync or will I get a flicker? I can't think of any other way to change three registers per DLI. :(

 

Cheers,

-Peter.

Link to comment
Share on other sites

Should be OK.

 

The trick with multiple stores is to preload 2 or more registers before the WSync.

 

But if you're pushing 2 or 3 registers to the stack, it leaves less time.

 

Also, it's not always a good idea to rely on the DLIs alone to reset your counter. Best to have a VBlank routine that does that.

 

Using Altirra in debug/single step mode is a good way to guage what's happening where. Enable full-width screen then use F11 to step through.

 

Set a memory access trap to stop the machine when your DLI occurs.

 

BA R 200

is a good way.

Press F8 if the trap hits too early, once execution gets to where you want to single-step just press F11 to go 1 instruction at a time, there should be a yellow/black line overlayed on the screen that shows where in the scanline you are.

Link to comment
Share on other sites

The other option is to have different DLI routines for each line and then you can skip the indexed addressing etc e.g.

 

IGDLI1			PHA
			STX RESTDLIX1+1
			LDX CHBASTAB
			LDA PF3COLORTAB
			STA WSYNC			
               		STA COLPF3
			STX CHBAS
IGDLICHL1		LDA #<IGDLI2
			STA VDSLSTL				
IGDLICHH1		LDA #>IGDLI2
			STA VDSLSTH				
RESTDLIX1		LDX #$FF		
			PLA
			RTI

IGDLI2			PHA
			STX RESTDLIX2+1
			LDX CHBASTAB+1
			LDA PF3COLORTAB+1
			STA WSYNC			
			STX CHBAS
               		STA COLPF3
IGDLICHL2		LDA #<IGDLI3
			STA VDSLSTL				
IGDLICHH2		LDA #>IGDLI3
			STA VDSLSTH
RESTDLIX2		LDX #$FF		
			PLA
			RTI


; etc.

 

and so on, or even use immediate mode:

 

IGDLI1			PHA
			STX RESTDLIX1+1
CHTAB1			LDX #$FF
PF3COL1		LDA #$FF
			STA WSYNC			
               		STA COLPF3
			STX CHBAS
IGDLICHL1		LDA #<IGDLI2
			STA VDSLSTL				
IGDLICHH1		LDA #>IGDLI2
			STA VDSLSTH				
RESTDLIX1		LDX #$FF		
			PLA
			RTI

IGDLI2			PHA
			STX RESTDLIX2+1
CHTAB2			LDX #$FF
PF3COL2		LDA #$FF
			STA WSYNC			
			STX CHBAS
               		STA COLPF3
IGDLICHL2		LDA #<IGDLI3
			STA VDSLSTL				
IGDLICHH2		LDA #>IGDLI3
			STA VDSLSTH
RESTDLIX2		LDX #$FF		
			PLA
			RTI
; etc.

 

 

and in VBI store to CHTAB1+1, CHTAB2+1, PF3COL1+1, PF3COL2+1 and so on

Link to comment
Share on other sites

Should be OK.

 

The trick with multiple stores is to preload 2 or more registers before the WSync.

 

But if you're pushing 2 or 3 registers to the stack, it leaves less time.

 

Also, it's not always a good idea to rely on the DLIs alone to reset your counter. Best to have a VBlank routine that does that.

 

Using Altirra in debug/single step mode is a good way to guage what's happening where. Enable full-width screen then use F11 to step through.

 

Set a memory access trap to stop the machine when your DLI occurs.

 

BA R 200

is a good way.

Press F8 if the trap hits too early, once execution gets to where you want to single-step just press F11 to go 1 instruction at a time, there should be a yellow/black line overlayed on the screen that shows where in the scanline you are.

Man - I really have to RTFM on Altirra, and learn the debugger!!!

Link to comment
Share on other sites

Altirra knows most of the public OS symbols, so you can just type: ba r vdslst

 

I profiled the execution of the DLI routine, and I'm not sure that the De Re Atari DLI handler is a good starting point. It's intended for a Gr.7 screen (IR mode D) screen, but the timing constraints are tighter for an IR mode 4 screen, for which it is dangerously close to missing a scanline. This is what the timing looks like on one run:

 

- NMI interrupt (DLI)
   1: 63: 19 | A=00 X=05 Y=FD S=EA P=3C | C018: 2C 0F D4  LC018  BIT NMIST
   1: 63: 28 | A=00 X=05 Y=FD S=EA P=BE | C01B: 10 03            BPL $C020
   1: 63: 36 | A=00 X=05 Y=FD S=EA P=BE | C01D: 6C 00 02         JMP (VDSLST)
   1: 63: 56 | A=00 X=05 Y=FD S=EA P=BE | 0600: 48               PHA
   1: 63: 64 | A=00 X=05 Y=FD S=E9 P=BE | 0601: 8A               TXA
   1: 63: 68 | A=05 X=05 Y=FD S=E9 P=3C | 0602: 48               PHA
   1: 63: 74 | A=05 X=05 Y=FD S=E8 P=3C | 0603: E6 00            INC COUNTR
   1: 63: 84 | A=05 X=05 Y=FD S=E8 P=BC | 0605: A6 00            LDX COUNTR
   1: 63: 90 | A=05 X=DD Y=FD S=E8 P=BC | 0607: BD 00 04         LDA $0400,X ;$04DD
   1: 63: 98 | A=00 X=DD Y=FD S=E8 P=3E | 060A: 8D 0A D4         STA WSYNC
   1: 63:103 | A=00 X=DD Y=FD S=E8 P=3E | 060D: 8D 17 D0         STA COLPF1
   1: 63:108 | A=00 X=DD Y=FD S=E8 P=3E | 0610: BD 01 04         LDA $0401,X ;$04DE
   1: 63:112 | A=00 X=DD Y=FD S=E8 P=3E | 0613: 8D 18 D0         STA COLPF2
   1: 64:  3 | A=00 X=DD Y=FD S=E8 P=3E | 0616: BD 00 04         LDA $0400,X ;$04DD
   1: 64:  7 | A=00 X=DD Y=FD S=E8 P=3E | 0619: 8D 09 D4         STA CHBASE
   1: 64: 11 | A=00 X=DD Y=FD S=E8 P=3E | 061C: E0 23            CPX #$23
   1: 64: 13 | A=00 X=DD Y=FD S=E8 P=BD | 061E: D0 04            BNE $0624
   1: 64: 16 | A=00 X=DD Y=FD S=E8 P=BD | 0624: 68        L0624  PLA
   1: 64:101 | A=05 X=DD Y=FD S=E9 P=3D | 0625: AA               TAX
   1: 64:103 | A=05 X=05 Y=FD S=E9 P=3D | 0626: 68               PLA

 

...and this is what the DMA timing diagram looks like for the scanline where the DLI starts:

 

Altirra> .dma
                                                                                                   1         1   
         1         2         3         4         5         6         7         8         9         0         1   
012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123
.D...................C.C.CRC.CRC.CRC.CRC.CRC.CRC.CRC.CRC.CRC.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C.C..............

Legend: (M)issile (P)layer (D)isplayList (R)efresh Play(F)ield (C)haracter (V)irtual

 

In the debugger, DLIs fire at cycle 10 or later, and STA WSYNC resumes execution at 105 with possibly one cycle already executed on the next instruction. The last cycle of STA WSYNC needs to execute by cycle 103, so that's 90 cycles available up to that point, with 40 cycles taken by playfield DMA and 9 cycles by refresh DMA, leaving 41 cycles. The accounting looks like this:

 

Finish current instruction: 0-7 cycles

Interrupt sequence: 7 cycles

OS dispatch (BIT abs / Bcc not taken / JMP (abs)): 11 cycles

User DLI routine: 20 cycles

 

This adds up to 45 cycles, which means this routine will occasionally miss a scan line. In De Re Atari's terms, Phase One is too long. Here's an trace of this occurring, due to a seven cycle instruction running in mainline:

 

Altirra> bx "pc=$0610 and vpos > 63"
Breakpoint 0 set at PC=$0610 with condition: vpos>63
Altirra> g
Breakpoint 0 hit
(12891: 64,108) PC=0610 A=01 X=01 Y=98 S=E2 P=34 (   I  )  0610: BD 01 04         LDA $0401,X [$0402] = $02
Altirra> h 15
    14) T=00603| 63,  0 A=42 X=00 Y=98 S=e6 P=76 ( V1B IZ ) 0686: 68               PLA
    13) T=00603| 63,  4 A=42 X=00 Y=98 S=e7 P=74 ( V1B I  ) 0687: 4C 80 06         JMP $0680   [$0680] = $A2
    12) T=00603| 63,  7 A=42 X=00 Y=98 S=e7 P=74 ( V1B I  ) 0680: A2 00            LDX #$00
    11) T=00603| 63,  9 A=42 X=00 Y=98 S=e7 P=76 ( V1B IZ ) 0682: 3E FF 06         ROL $06FF,X [$06FF] = $00
    10) T=00603| 63, 28 A=42 X=00 Y=98 S=e4 P=76 ( V1B IZ ) C018: 2C 0F D4  LC018  BIT NMIST   [$D40F] = $9F
     9) T=00603| 63, 44 A=42 X=00 Y=98 S=e4 P=b4 (N 1B I  ) C01B: 10 03            BPL $C020
      T=00603| 63, 52 A=42 X=00 Y=98 S=e4 P=b4 (N 1B I  ) C01D: 6C 00 02         JMP (VDSLST) [$0600] = $48
     7) T=00603| 63, 66 A=42 X=00 Y=98 S=e4 P=b4 (N 1B I  ) 0600: 48               PHA
     6) T=00603| 63, 72 A=42 X=00 Y=98 S=e3 P=b4 (N 1B I  ) 0601: 8A               TXA
     5) T=00603| 63, 76 A=00 X=00 Y=98 S=e3 P=36 (  1B IZ ) 0602: 48               PHA
     4) T=00603| 63, 82 A=00 X=00 Y=98 S=e2 P=36 (  1B IZ ) 0603: E6 00            INC COUNTR  [$00] = $01
     3) T=00603| 63, 92 A=00 X=00 Y=98 S=e2 P=34 (  1B I  ) 0605: A6 00            LDX COUNTR  [$00] = $01
     2) T=00603| 63, 98 A=00 X=01 Y=98 S=e2 P=34 (  1B I  ) 0607: BD 00 04         LDA $0400,X [$0401] = $01
     1) T=00603| 63,103 A=01 X=01 Y=98 S=e2 P=34 (  1B I  ) 060A: 8D 0A D4         STA WSYNC   [$D40A] = $FF
     0) T=00603| 63,107 A=01 X=01 Y=98 S=e2 P=34 (  1B I  ) 060D: 8D 17 D0         STA COLPF1  [$D017] = $0F

 

One way to fix this would be to move the INC COUNTR statement to the end of the DLI (Phase Three) and rotate the tables to match.

 

The other critical part of the DLI is Phase Two, which has to execute before a wall of DMA on the next scanline:

         1         2         3         4         5         6         7         8         9         0         1   
012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123
.D................F.FCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCFCRC..............

Legend: (M)issile (P)layer (D)isplayList (R)efresh Play(F)ield (C)haracter (V)irtual

 

Starting after the STA WSYNC, there are 31 cycles available, plus one bonus cycle. This is pretty relaxed and you've got 20 cycles assuming no page crossings, so that should be fine.

Link to comment
Share on other sites

Wow, that looks complex.

 

It may be that the "DeRe" way of doing things will be "Good enough" for what I want. I've got a busy workload for the rest of the week - No Atari time :*(

 

Thanks for your help, guys. Will post what I settle on sometime this weekend.

 

Cheers!

Link to comment
Share on other sites

  • 2 weeks later...
CPX #$23 Last line? (23 because I'm useing a 24 line screen all with interrupts)

 

$23 is not 24 lines, it's 36 lines. Hexadecimal FTW!

 

Doh!

 

I made the mistake of thinking $0000-$01ff was 2k the other day.

 

Here's the code I eventually came up with. Not pretty but is (seems) to work...

 

I was worried that the interrupt may turn "on" in the middle of drawing a frame, but it seems to work from the top, by luck or by Judgement...

 

1000 REM INITIALISE MULTI DLI SCREEN
1010 CHBASE=152*256
1020 OPEN #1,4,0,"H:A4ALIAS.SET"
1030 FOR I=0 TO 1023:GET #1,L
1040 POKE CHBASE+I,L
1050 NEXT I:POKE 756,152
1060 GRAPHICS 0:POKE 752,1
1070 DL=PEEK(560)+PEEK(561)
1080 PAGE6=1536
1090 REM READ IN DLI ROUTINE TO PAGE6
1100 RESTORE 1120
1110 FOR I=0 TO 40:READ J
1120 POKE PAGE6+I,J:NEXT I
1130 DATA 72,138,72,238,40,6
1140 DATA 174,40,6,189,64,6
1150 DATA 141,23,208,189,96,6
1160 DATA 141,24,208,189,128,6
1170 DATA 141,9,212,224
1180 DATA 24
1190 DATA 208,5,169,0,141,40,6
1200 DATA 104,170,104,64
1210 DATA 0
1220 REM INITISE TABLE FOR COL1
1230 RESTORE 1260
1240 FOR I=0 TO 23:READ J
1250 POKE PAGE6+64+I,J:NEXT I
1260 DATA 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14
1270 REM TABLE FOR COL2
1280 RESTORE 1310
1290 FOR I=0 TO 23:READ J
1300 POKE PAGE6+96+I,J:NEXT I
1310 DATA 16,32,48,64,80,96,112,128
1320 DATA 16,32,48,64,80,96,112,128
1330 DATA 16,32,48,64,80,96,112,128
1340 REM TABLE FOR VCSET
1350 RESTORE 1380
1360 FOR I=0 TO 23:READ J
1370 POKE PAGE6+128+I,J:NEXT I
1380 DATA 152,152,152,152,152,152,152,152
1390 DATA 152,152,152,152,152,152,152,152
1400 DATA 152,152,152,152,152,152,152,152
1410 DL=PEEK(560)+PEEK(561)*256
1420 POKE DL+3,128+64+4
1430 FOR I=6 TO 28:POKE DL+I,128+4
1440 NEXT I
1460 POKE 512,0:POKE 513,6
1470 POKE 54286,192

Link to comment
Share on other sites

Hi,

Out of all the atari assembly language books I've read "Assembly Language Programming for the Atari Computers" has been particularly good; checkout chapter 8 for some good info and example DLI code :)

 

Cheers trbb,

 

Just had a quick peek at that (am at work so couldn't linger.. :) ) Looks just the ticket. Scrolling was my next project as well!

Link to comment
Share on other sites

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