Jump to content
IGNORED

Smooth scrolling


Asmusr

Recommended Posts

The above code does not work reliably on a real console. The check is virtually continuous and you will run into a situation where you ate trying to read the status reg while the vdp is trying to write to it. There. Is no way to prevent this but it can be minimized by placing a series of nop's between reads. My experience indicates about 25 works best.

 

Oh. Thanks.

 

I read the keyboard or joystick, or at least the lines (CRU) I need once a frame. Don’t know if it works on real hardware. Never understood the need for the incredible long time delay loop with SCAN/KSCAN.

 

delayloop.png

Link to comment
Share on other sites

No intention to debate, but I can't fix the problems with Classic99 if I don't understand them! :) In this case, the fix here is already scheduled, it just led you to a bad conclusion about the behavior of those bits. This just helps bump priorities in my mind, so thanks for answering the questions!

 

Thanks for you help. I love Classic99 and I use it every day, so I'm bound to run into some problems, but I seem to fall into every trap when it comes to the difference between emulation and hardware!

 

Did you see my reply in the 'Classic99 Updates' thread about the sprites being visible when the screen is blanked? If you still can't reproduce it I will write some test code.

Link to comment
Share on other sites

Never understood the need for the incredible long time delay loop with SCAN/KSCAN.

delayloop.png

 

It is a software debounce for the keyboard, and a really bad way to do it IMO. Instead of a delay loop, poll the keyboard and record the hits, then on the next ISR poll the keyboard and compare the current hits to the previous hits. That is the same as a delay loop without holding up the whole system, which is why the console keyboard routine is so freaking slow. Or, TI could have just spent a few pennies to add a resistor and capacitor to keyboard lines and make a real hardware debounce. They opted for the cheap and easy way in both circumstances.

 

  • Like 2
Link to comment
Share on other sites

This one is actually pretty easy to catch in practice (unfortunately none of us testers tried the easy test on the F18A)... just use sprites and collision in XB. XB positions unused sprites off the bottom of the screen but NOT disabled with 0xD0, so if you use CALL COINC(ALL) and have any sprites still uninitialized, then it triggers if you listen to that bit of the datasheet. :)

 

That is actually the condition code in a game that caught the bug. A game was using COINC(ALL) and with the F18A you would die immediately three times in a row and the game would be over.

 

Hello.. Soon enough? Really? :)

 

I sent the visual6502 project a few 9918A VDPs among other hardware they had on their wish list. Hopefully they will get through their backlog. I need to start to learn how to polygon-push though.

 

  • Like 1
Link to comment
Share on other sites

I must be missing something basic about sprite coincidence! Time delays do not work. The only time I get useful information from the coincidence bit (20h) in the VDPSTA (8802h) status byte is when I wait for the VDP interrupt status bit (80h) to be set. This only seems to work in my hands when I manually move the sprites and then wait for the interrupt status bit to be set. It does not work at all after I set the sprites in automotion. I am out of ideas.

 

...lee

Link to comment
Share on other sites

I must be missing something basic about sprite coincidence! Time delays do not work. The only time I get useful information from the coincidence bit (20h) in the VDPSTA (8802h) status byte is when I wait for the VDP interrupt status bit (80h) to be set. This only seems to work in my hands when I manually move the sprites and then wait for the interrupt status bit to be set. It does not work at all after I set the sprites in automotion. I am out of ideas.

 

...lee

 

I think I figured it out—sort of. TI Forth and, by extension, fbForth sample the VDP status register (8802h) directly in COINCALL to get the coincidence bit instead of the copy at 837Bh, which works fine. Coincidence is properly captured during automotion and manual motion. Phew! :-o

 

...lee

Link to comment
Share on other sites

It is a software debounce for the keyboard, and a really bad way to do it IMO. Instead of a delay loop, poll the keyboard and record the hits, then on the next ISR poll the keyboard and compare the current hits to the previous hits. That is the same as a delay loop without holding up the whole system, which is why the console keyboard routine is so freaking slow.

 

Is there any need to debounce the keyboard in a game where you just want the keyboard to work as an alternative to the joystick?

 

Reading the keyboard (or anything else involving CRU) is still a mystery to me. I have found the following code on Thierry Nouspikel's site <http://nouspikel.gro...99/keyboard.htm>. I would appreciate if someone would write a few words about how it works and how to change it to read other keys, e.g. S,D,E,X. Thanks. [Edit] Never mind, I found a really good tutorial here <http://nouspikel.group.shef.ac.uk/ti99/tutor1.htm#CRU>.

 

*--------------------------------------------
* Routine to detect a key combination (in this case Fctn-=),
* returns with Eq bit set if this is the case.
* This routine alters R12 and R1
*--------------------------------------------
ISQUIT CLR R1 Test column 0
LI R12,>0024 Address for column selection
LDCR R1,3 Select column
LI R12,>0006 Address to read rows
STCR R1,8
ANDI R1,>1100 Mask all irrelevant bits
B *R11 Else return

*--------------------------------------------
* Routine to detect a specific key (in this case <enter>),
* it returns with Eq bit set if <enter> was NOT pressed.
* Alters R12 only
*--------------------------------------------
ISENTR CLR R1 Test column 0
LI R12,>0024 Address for column selection
LDCR R12,3 Select column
TB -13 Test R12-address >000A, i.e <enter>
B *R11 <enter> was not pressed: return

Link to comment
Share on other sites

Well, I've done my tests! 8)

 

This program is a simple one for Colecovision (NTSC version) that polls the VDP status register and puts the hexadecimal value in the screen starting at top corner left. When it receives a byte that includes bit 7 set (VDP interrupt) it puts an asterisk and reinits position at top left.

 

No interrupts activated, mode 2 ($0000-$17FF character set, $1800-$1fff sprites, $2000-$37ff color table, $3800-$3aff screen, $3f80-$3fff sprite table reset to $D0)

 

I've made it as fast as possible and then inserted some delays so each hexadecimal value corresponds to (more or less) one screen line, so I have around 259 values in screen.

 

Beside I've included an option to erase all sprites from screen or put up to five sprites that can be displaced with the joystick to test for collision and 5th sprite.

 

I've seen following:

 

1. bits 4-0 shows LAST sprite processed or number of 5th sprite (the last sprite processed can be the sprite containing the Y-coordinate set to $D0). I've seen variations when there are various sprites on screen (like a ramp over my status screen,) probably because VDP updates it as it process sprites.

2. bit 5 (collision bit) is exact and there is no failure, besides it is not affected by offscreen sprites (matthew180 right on this)

3. bit 6 (5th sprite) also is exact and there is no failure.

4. bit 7 (interrupt bit), THERE IS A RACE CONDITION (marc.hull is right about this,) each second or two seconds, with continuous polling (and including generous delay to write status to screen) at least one VDP interrupt is lost, so my status screen overflows.

 

I hope this information is useful for everyone.

Edited by nanochess
  • Like 2
Link to comment
Share on other sites

By the way, here is the small ROM for Colecovision I've developed for the test.

 

With controller 1 press * (asterisk) to erase all sprites (it starts in this state)

 

Press 1 to display sprite 1.

 

Press 2 to display sprite 2.

 

Press 3 to display sprite 3.

 

Press 4 to display sprite 4.

 

Press 5 to display sprite 5.

 

Use joystick to move last displayed sprite.

cv_vdp_status_test.rom

Edited by nanochess
Link to comment
Share on other sites

4. bit 7 (interrupt bit), THERE IS A RACE CONDITION (marc.hull is right about this,) each second or two seconds, with continuous polling (and including generous delay to write status to screen) at least one VDP interrupt is lost, so my status screen overflows.

 

Very nice, and on a different machine, too, excellent confirmation! I was going to try something similar tonight myself... I think I still will, just for double confirmation, but it's great to see it confirmed.

Link to comment
Share on other sites

Is there any need to debounce the keyboard in a game where you just want the keyboard to work as an alternative to the joystick?

 

Not in my experience, unless you want very clean edges. I have a very small keyboard read function that I wrote for TI MOTIF that doesn't do any debounce, and didn't have any problem playing the game. But bounces will happen and be worse on some keyboards than others. It really only depends on whether you need to be sure the key is down or up or can handle a little bouncing.

  • Like 1
Link to comment
Share on other sites

I think I figured it out—sort of. TI Forth and, by extension, fbForth sample the VDP status register (8802h) directly in COINCALL to get the coincidence bit instead of the copy at 837Bh, which works fine. Coincidence is properly captured during automotion and manual motion. Phew! :-o

...lee

 

Excellent! It's interesting (maybe?) to note that Extended BASIC directly tests as well, which means excessive CALL COINC(ALL) can cause issues with the vblank and can occasionally miss due to same. At XB speeds this is pretty rare though.

Link to comment
Share on other sites

Excellent! It's interesting (maybe?) to note that Extended BASIC directly tests as well, which means excessive CALL COINC(ALL) can cause issues with the vblank and can occasionally miss due to same. At XB speeds this is pretty rare though.

 

I got the idea to test the copy at 837Bh instead of the actual status byte (8802h) from Craig Miller's Smart Programming Guide for Sprites. He claimed that it was "equivalent" to XB's CALL COINC(ALL,C), but that cannot be quite true because testing the copy will not reset any bits. The only time I've found it important to actually test 8802h was with TI Forth's (and, now, fbForth's :D) RANDOMIZE . There must be other reasons, but I don't know what they might be.

 

...lee

Link to comment
Share on other sites

Very nice, and on a different machine, too, excellent confirmation! I was going to try something similar tonight myself... I think I still will, just for double confirmation, but it's great to see it confirmed.

 

I got my test up and running, too. My goal was to hit the status register as hard as possible and see what came up, so I settled on a simple dual bit test. My code sets up two colliding sprites near the middle of the screen (only one pixel overlapping to avoid multi-scanline races), and then two loops poll the status register. The first waits for a sprite collision, the second waits for end of frame. If either sees the other bit set, then a 'miss' counter is incremented and displayed. Within just a few seconds both the sprite collision and end of frame missed counters were incrementing slowly. I'm going to let it run overnight and see, but right now it looks like both of these bits are susceptible to race, which contrasts Nanochess's results (anyone else want to try their own test program and see what results they get?)

 

My test code was compiled with the GCC compiler for the 9900 and run on a QI2.2 ROM machine. The assembly code was examined for errors and tested on the emulator before running on hardware. (Naturally it's running on a real 9918A).

 

My test code is attached - C source, compiled assembly, and PROGRAM image file.

 

testVDPS.zip

  • Like 1
Link to comment
Share on other sites

 

 

I got my test up and running, too. My goal was to hit the status register as hard as possible and see what came up, so I settled on a simple dual bit test. My code sets up two colliding sprites near the middle of the screen (only one pixel overlapping to avoid multi-scanline races), and then two loops poll the status register. The first waits for a sprite collision, the second waits for end of frame. If either sees the other bit set, then a 'miss' counter is incremented and displayed. Within just a few seconds both the sprite collision and end of frame missed counters were incrementing slowly. I'm going to let it run overnight and see, but right now it looks like both of these bits are susceptible to race, which contrasts Nanochess's results (anyone else want to try their own test program and see what results they get?)

 

My test code was compiled with the GCC compiler for the 9900 and run on a QI2.2 ROM machine. The assembly code was examined for errors and tested on the emulator before running on hardware. (Naturally it's running on a real 9918A).

 

My test code is attached - C source, compiled assembly, and PROGRAM image file.

 

testVDPS.zip

That's interesting, I should do something similar for Colecovision in order to settle matters.

 

I don't have a TI99 but from your source code I understand that you allow only one bit to overlap for collision test.

 

In my test I'm using only my eyes and I don't see variations in collision bit and 5th sprite (remember the screen is updating constantly)

Link to comment
Share on other sites

In my test I'm using only my eyes and I don't see variations in collision bit and 5th sprite (remember the screen is updating constantly)

 

Yeah.. I wanted the computer to do the measurement and I wanted to run it overnight. I guess we got different results, so we need a third confirmation. :)

 

Link to comment
Share on other sites

Ok, Tursi. I've done same in Colecovision.

 

And same race condition in bit 6 (5th sprite, very surprisingly,) although bit 5 (collision) looks like being stable under my test conditions (two sprites only)

 

This is the core of my code:

 

    ;
    ; Sprite initialization table
    ;
.16:    db $70,$40,$00,$0f
    db $61,$40,$00,$09	  ; Collision only in one scanline
.17:    db $70,$40,$00,$0f
    db $70,$50,$00,$07
    db $70,$60,$00,$09
    db $70,$70,$00,$0b
    db $61,$80,$00,$03	  ; 5th sprite only in one scanline
    ;
    ; Key 1 - Collision bit
    ;
.14:    ld hl,.16
    ld de,$3f80
    ld bc,8
    call LDIRVM
    in a,(VDP+1)
    bit 7,a
    jr z,$-4
    ld c,$20	    ; Bit collision
    jp .0
    ;
    ; Key 2 - 5th sprite
    ;
.15:    ld hl,.17
    ld de,$3f80
    ld bc,20
    call LDIRVM
    in a,(VDP+1)
    bit 7,a
    jr z,$-4
    ld c,$40	    ; Bit 5th sprite
    jp .0
    ;
    ; Polling loop
    ;
.0:	 call .18
.1:	 in a,(VDP+1)
    ld b,a
    and c
    jr nz,.2
    bit 7,b
    jr z,.1
    ld a,(lost_bit)
    inc a
    ld (lost_bit),a
    call .18	    ; Update lost count
    jr .1
.2:	 in a,(VDP+1)
    ld b,a
    bit 7,b
    jr nz,.1
    and c
    jr z,.2
    ld a,(lost_int)
    inc a
    ld (lost_int),a
    call .18	    ; Update lost count
    jr .2

 

And this is the ROM for testing it on Colecovision, at start it will show a black screen, press key 1 to test coliision bit or press key 2 to test 5th sprite.

 

First number in top left shows how many lost collision/5th sprite bits and second number shows how many interrupt bits lost (amazingly it loses slightly more than one per second with my code)

 

Anyway not a great deal to lose a frame at 60 frames per second, it would be barely noticeable in games.

cv_vdp_status_test2.rom

  • Like 1
Link to comment
Share on other sites

Sorry for the double post. I am on my phone.

 

The above code does not work reliably on a real console. The check is virtually continuous and you will run into a situation where you ate trying to read the status reg while the vdp is trying to write to it. There. Is no way to prevent this but it can be minimized by placing a series of nop's between reads. My experience indicates about 25 works best.

What is the reason for reading the status register? Seems that polling the interrupt line itself (CLR R12, TB 2) would be more appropriate here. If the interrupt is pending, then (and only then) read the status register. Would that eliminate the race condition and all that extra NOPping?

Link to comment
Share on other sites

What is the reason for reading the status register? Seems that polling the interrupt line itself (CLR R12, TB 2) would be more appropriate here. If the interrupt is pending, then (and only then) read the status register. Would that eliminate the race condition and all that extra NOPping?

It's that possible? (I don't have a TI99) surely it would solve the race conditions of polling.

 

At least in Colecovision I never have missed an interrupt.

Link to comment
Share on other sites

 

What is the reason for reading the status register? Seems that polling the interrupt line itself (CLR R12, TB 2) would be more appropriate here. If the interrupt is pending, then (and only then) read the status register. Would that eliminate the race condition and all that extra NOPping?

 

Uh.... cause we are ignorant of that.

 

So with interrups disabled in the CPU the vdp will pass it's. Interrupt signal to the 9901 at CRU 2?

 

Does the 9901 maintain this output until it's read?

 

Thanks T.

Here's salt water I'm your eye ;-).

Link to comment
Share on other sites

Nobody commented on my posts above about it, but on the TI, testing the copy of the status byte at 837Bh for the coincidence bit was right on the money every time I tested it successfully with automotion and manual motion—and, it does not reset anything.

 

...lee

Link to comment
Share on other sites

Further news:

 

I played Lock&Chase on my Colecovision for one hour, then before putting again in its place I tried again the test 2, incredibly the VDP changed its behavior.

 

1. bit 5 = collision bit starts to lose collisions at same rate that interrupt bit.

2. bit 6 = 5th bit starts to lose collisions at double rate that interrupt bit.

 

Because the chip is now hot or somehow voltage drop slightly? I cannot explain it :-o .

 

Anyway, this finally settles matters for me about why my poor little game failed so many years ago.

 

Recipe: No polling, use interrupt if you want to use collisions. Better, handle collision with your own code and stop worrying about possible VDP misbehavior.

Edited by nanochess
Link to comment
Share on other sites

Nobody commented on my posts above about it, but on the TI, testing the copy of the status byte at 837Bh for the coincidence bit was right on the money every time I tested it successfully with automotion and manual motion—and, it does not reset anything.

 

...lee

 

The discussion was about running without the ISR and subsequently with out the copy....

Edited by marc.hull
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...