Dmitry Posted May 23, 2016 Share Posted May 23, 2016 ABBUC software contest rules state "Before changing the display list (DLISTL/H) a vertical blank should take place (wait for it). " What does that mean? I'm pretty sure a vertical blank takes place 50 or 60 times per second, you can automatically assume one has already taken place. So they must mean something else...I do not know what they mean. What do they want? And second, if its a bog standard thing, could someone share some assembler? thanks Quote Link to comment Share on other sites More sharing options...
MaPa Posted May 23, 2016 Share Posted May 23, 2016 Probably just advice to waiting for vertical blank before you change DLIST pointer, so the VBL will not happen in between writing low and high byte of the pointer (in that case the DLIST will point to some "random" place and it would produce glitches for one frame or it can even crash AFAIK if DLIs are enabled). 1 Quote Link to comment Share on other sites More sharing options...
Rybags Posted May 23, 2016 Share Posted May 23, 2016 Not sure why they'd word it as such. It is possible though highly unlikely in assembler that if you change the display list pointers you can get a half-baked value if a VBlank takes place between stores. If doing a disk load and you want a title screen it's highly advisable to change the DList pointer then have a 1 frame wait so it gets enstated. The problem with doing disk operations is that Stage 2 VBlank will be disabled for a good deal of the time so screen relevant changes like DLists and colours can have an unwanted delay. Quote Link to comment Share on other sites More sharing options...
Dmitry Posted May 23, 2016 Author Share Posted May 23, 2016 I have a routine that delays until a jiffy register changes. Interestingly enough, that absolutely makes sure the atari DOES crash. ; wait 1 to make sure dlist is picked up lda #1 jsr _delay_asm kablooey Quote Link to comment Share on other sites More sharing options...
Dmitry Posted May 23, 2016 Author Share Posted May 23, 2016 My above post is worded poorly. First, my atari is in the shop, so I am talking about an emulated atari. Second the whole atari doesn't crash, but I get massive corruption on the screen. ; turn off antic lda #0 sta $022F ; poke dlist into os ldy #<DL1 sty $0230 ldy #>DL1 sty $0231 ; poke screen memory into os ldy #$00 sty $58 ldy #$40 sty $59 ; wait 1 to make sure dlist is picked up - adding these lines causes the first screen to become garbage characters lda #1 jsr _delay_asm ; turn on antic lda #$22 sta $022F Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted May 23, 2016 Share Posted May 23, 2016 What's your delay routine look like? Note also your display list is in the banked RAM area so if you use a RAMdisk or SDX the display will frequently blow up. Quote Link to comment Share on other sites More sharing options...
Dmitry Posted May 23, 2016 Author Share Posted May 23, 2016 I assume you mean my screen memory is in the banked area, my display list isn't revealed in that code just referenced as DL1. I put the DL in page 6. On putting screen memory in $4000 - for now that is still hard coded. That's from early in the programming effort where I hadn't gotten used to labels yet, so some of my maze drawing routines have some hard coded, expecting memory to start at $4000 values. I had things spread out everywhere at first. Laughably creating a 32k executable out of minimal amount of code, lol. now most everything is handled by the linker, and the org=$2000.... but I have some screen memory stuff that is still hard coded. I do have plans to change it. Imho, you really have only a small slice of memory in the atari that you can safely use - regrettably the early documentation let me down a little bit. My current goal is to start at $2000 and have everything run in the range $2000 - $4000, with some small page 6 use, and some small page zero use - and to be frank, right now I'm vastly overusing page 0, and have plans to reduce that, to make it safe for basic, so users don't have to unplug their cart, if they have it in. I don't have the code with me, but the delay routine is to read the jiffy register and loop until it changes. It's more complicated than that, because it accepts a parameter for the number of jiffies in the A register. And it has to account for the jiffy register possibly having cycled back to zero. So it does some branching logic back and forth, but the end result it waits the specified number of jiffies, by rereading the jiffy register until it changes, enough. this delay routine is called by the music playing and the game loop - and works everywhere else. When I get home I can share the code. I could put in a far simpler delay loop and try that....I just can't imagine what's causing this. Although, to be frank, I don't need to know. I don't have any need to use my delay loop here, I just did, as a convenience. so I should just remove it and everything goes back to working. I just need to figure out what ABBUC wants... any ideas? How do you all meet this requirement? Quote Link to comment Share on other sites More sharing options...
Dmitry Posted May 23, 2016 Author Share Posted May 23, 2016 I should have brought my laptop - argh. I just started using the monitor. I should have checked that. OK, it's morning here, I'll pick this up again in the evening Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted May 23, 2016 Share Posted May 23, 2016 Of course you're quite correct about the DL - I meant the frame buffer. A simple way to wait for vertical sync is this: .proc WaitForSync lda VCount rne lda VCount req rts .endp It has the advantage of working even with all interrupts disabled. Really it's only the screen RAM position you need to worry about regarding the banked region, and then only if you're running alongside DOS or planning to bank memory yourself. To be DOS and cart safe, you can put Antic data at $2000-$3FFF or $8000-$9FFF. As long as code doesn't directly manipulate PORTB, it can safely be placed in the banking window, although it's sometimes prudent to keep interrupt service routines out of that area too. 1 Quote Link to comment Share on other sites More sharing options...
Dmitry Posted May 23, 2016 Author Share Posted May 23, 2016 Thanks. So at first I am thinking, those aren't 6502 instructions. However, I get it, they are mads macro for repeat not equal and repeat equal.... And you are branching on vcount which is vertical line counter at d40b I am just talking aloud for anyone else learning assembly. Other than making it work in my ca65 environment, I will deinately try this tonight. I suspect it won't be a fix for whatever nonsense I have going on but will improve my delay routine to use vcount. Although the game loop won't use any delay on upcoming revision... Still might need it for this Quote Link to comment Share on other sites More sharing options...
drac030 Posted May 23, 2016 Share Posted May 23, 2016 (edited) They mean this: lda 20 lp cmp 20 beq lp lda #<xx sta $0230 lda #>yy sta $0231 As said above, one has to guarantee (this way or another) that no VBL occurs between setting the low byte of a vector and setting its high byte. Edited May 23, 2016 by drac030 Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted May 23, 2016 Share Posted May 23, 2016 So at first I am thinking, those aren't 6502 instructions. However, I get it, they are mads macro for repeat not equal and repeat equal.... And you are branching on vcount which is vertical line counter at d40b. Yes - my apologies: I just pasted this straight out of existing source code. RNE is equivalent to BNE LABEL where LABEL points to the previous instruction, and REQ is the same but using BEQ. VCOUNT is indeed the vertical line counter at $D40B. Quote Link to comment Share on other sites More sharing options...
sanny Posted May 23, 2016 Share Posted May 23, 2016 Isn't it sufficient, to just check that the line counter isn't near the bottom of the screen? Like in ; wait until we aren't at the bottom of the screen wait: lda $d40b ; VCOUNT cmp #120 bcs wait ; set new display list address lda #<new_displist sta $230 lda #>new_displist sta $231 Quote Link to comment Share on other sites More sharing options...
Rybags Posted May 23, 2016 Share Posted May 23, 2016 Actually, for just the DList pointer none of that is necessary. Just use the same method the OS does with it's SETVBV routine. ldx #<new_dlist ldy #>new_dlist sta wsync stx sdslstl sty sdslsth Since NMIs will only occur at cycle 7 (?) of a scanline the write to WSync ensures both parts of the pointer will be written before an NMI can start. I assume this should still work fine in the worst case DMA situation (wide screen, 40 character mode badline, 3 byte DList instruction, PMG DMA enabled) 1 Quote Link to comment Share on other sites More sharing options...
Dmitry Posted May 23, 2016 Author Share Posted May 23, 2016 Well I'm home now and quickly discovered the silly reason for my screen corruption. I have my code organized into 'transition' screens and part of the code uses Absolute,X addressing to load in the screen. It starts at 0. But it never really set the X register to 0 - it was just coincidentally starting at 0. Up until that time I added code that touched the X register, as my original delay routine did. Anyway, this is good, I added STA WSYNC, and thus now guarantee that a vblank won't occur between the setting of the upper and lower byte of the dl. I kind of hoped in the far reaches of my imagination that this might also be a fix for why Altirra won't display my program correctly, but it's not. Oh well. 1 Quote Link to comment Share on other sites More sharing options...
Rybags Posted May 24, 2016 Share Posted May 24, 2016 Actually there is the chance a VBlank could occur with that method I mentioned. If an IRQ occurred after the STX then the VBlank during servicing of that. But it wouldn't matter as Stage 2 would be skipped anyway. 1 Quote Link to comment Share on other sites More sharing options...
phaeron Posted May 24, 2016 Share Posted May 24, 2016 Actually there is the chance a VBlank could occur with that method I mentioned. If an IRQ occurred after the STX then the VBlank during servicing of that. But it wouldn't matter as Stage 2 would be skipped anyway. I'm pretty sure it's possible for the NMI to fire immediately after the IRQ exits with RTI. Unlike CLI, RTI doesn't hold off IRQs for an additional instruction. There's also the problem that the 6502 often begins executing the next instruction before it is suspended by WSYNC. That means that if the WSYNC wait runs across the VBI, the VBI can't fire before STX because that instruction has already begun executing, and is delayed until before STY -- boom. SETVBV is a challenging function to write, especially since it is not allowed to touch NMIEN. Fortunately, for SDLSTL/SDLSTH, it's simpler and faster just to change them with IRQs disabled by wrapping the write with SEI/CLI. If you want to know when stage 2 VBI has run to actually push the new values to the hardware and swap in the new screen, overwrite one of the input shadows with an invalid value -- e.g. PTRIG7=$FF -- and wait for it to change back to a legal value again ($00/$01). Polling RTCLOK ($14) is not reliable as it updates in stage 1 VBI. It's good that ABBUC has this rule, because it's a common failure mode for programs to crash because they have a dirty screen swap on startup. That's inconvenient for people creating compilation disks because whether the crash happens can vary based on the loader that's used to load the program. You can't think "the timing windows too small, it won't happen" -- it will. 5 Quote Link to comment Share on other sites More sharing options...
Dmitry Posted May 24, 2016 Author Share Posted May 24, 2016 Something like this then? ; poke dlist into os ldy #<DL2 ldx #>DL2 LDA #$FF STA PTRIG7 REPEAT: LDA PTRIG7 CMP #$02 BCS REPEAT sty $0230 stx $0231 Quote Link to comment Share on other sites More sharing options...
Rybags Posted May 24, 2016 Share Posted May 24, 2016 You could get it even more compact. repeat bit ptrig7 bmi repeat Also, it's often the case your DList will be somewhere fairly high in memory. If it's fixed location above $8000 just put the high byte in PTRIG. Alternate to my method - two STA WSYNC instructions in a row should guarantee that VBlank doesn't occur between the DList stores. 1 Quote Link to comment Share on other sites More sharing options...
phaeron Posted May 24, 2016 Share Posted May 24, 2016 Something like this then? More like this: ; poke dlist into os ldy #<DL2 ldx #>DL2 sei sty sdlstl stx sdlsth cli ; wait for change to actually take effect LDA #$FF STA PTRIG7 REPEAT: LDA PTRIG7 CMP #$02 BCS REPEAT (As Rybags points out, you can also use BMI for >=$80 instead CMP #$02 to check for when the display change occurs.) 1 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.