Hans23 Posted December 20, 2020 Share Posted December 20, 2020 Hi, is there a way to synchronize to VBLANK in TurboForth? A counter would be useful, or maybe an efficient way to wait for the vertical blanking interrupt to occur. Any hints would be greatly appreciated. Thanks! -Hans Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/ Share on other sites More sharing options...
+TheBF Posted December 20, 2020 Share Posted December 20, 2020 Well... I don't know what VBLANK does but based on the name I suspect it fills a section of VDP RAM with "blank" chars. (>20) I read this online: Bit 0 (weight >80). This bit is set to 1 at the end of the raster scan of the last line of the display area (i.e. before drawing the bottom margin). So we can do this to wait for that bit. I used @ instead C@ because it's faster. It just means we get the data in the other byte of the Forth data stack. No biggy. Then we mask the bit out of the rest of the data with 8000 AND. UNTIL will loop until that bit is not zero. HEX : WAITVDP BEGIN 8802 @ 8000 AND UNTIL ; You could then redefine VBLANK like this: : VBLANK ( addr len --) WAITVDP VBLANK ; If you don't want the extra name in the dictionary you could put WAITVDP code inline. But having it named means you can use it anywhere you need it later There a small amount of time used to call it by name but Forth does that pretty quickly. If absolute speed was needed it would not be much more code to write WAITVDP in Forth Assembler. People with more hardware knowledge here can chime in to see if this is correct usage, but it's Forth. Try it and see what happens. 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704070 Share on other sites More sharing options...
Tursi Posted December 20, 2020 Share Posted December 20, 2020 It's worth noting that direct polling of the status bit has some caveats. If the console interrupt routine is on (I think it is in TurboForth), then you will interfere with it triggering (every read of the status register also clears the blank bit). This means you will sometimes miss it (if the console gets it first), and you will make the console miss sometimes too, which may cause sounds or sprites to be slowed down. There's even a race in the 9918 itself that might cause neither of you to get it, but this is pretty rare. Since the console interrupt is on in TurboForth (I believe), you can monitor the mirror of the status register at >837B (byte, copied by the console interrupt), or the screen blank counter at >83D6 (word, counts by two every frame that a key is not pressed). If you want to track it directly in the hardware, bit 2 on the CRU has fewer issues than reading the status byte directly, but there is still a chance of missing it if the console gets it first. (However, there is no chance of stealing it from the console). VBLANK is just one of the many terms for the end of frame indicator, it's not a separate action itself. 4 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704173 Share on other sites More sharing options...
+Lee Stewart Posted December 20, 2020 Share Posted December 20, 2020 31 minutes ago, Tursi said: If the console interrupt routine is on (I think it is in TurboForth), . . . Interrupts are normally ON in TI Forth and fbForth, but OFF in TurboForth. ...lee 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704209 Share on other sites More sharing options...
+Lee Stewart Posted December 20, 2020 Share Posted December 20, 2020 (edited) 14 hours ago, Hans23 said: Hi, is there a way to synchronize to VBLANK in TurboForth? A counter would be useful, or maybe an efficient way to wait for the vertical blanking interrupt to occur. Any hints would be greatly appreciated. Thanks! -Hans Here is the ALC [corrected] to poll for the next VDP interrupt in TurboForth (WI , say), which must have the TMS9900 Assembler (block 9) loaded: \ Wait for VDP Interrupt ASM: WI ( -- ) R1 $8000 LI, \ VDP interrupt mask $8802 @@ R2 MOVB, \ reset VDP status byte BEGIN, $8802 @@ R2 MOVB, \ get VDP status byte R1 R2 COC, \ VDP interrupt? EQ UNTIL, \ loop if not ;ASM and, without the TMS9900 Assembler [corrected]: \ Wait for VDP Interrupt HEX CODE: WI ( -- ) 0201 8000 D0A0 8802 D0A0 8802 2081 16FC ;CODE ...lee Edited December 20, 2020 by Lee Stewart corrections 3 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704241 Share on other sites More sharing options...
Hans23 Posted December 20, 2020 Author Share Posted December 20, 2020 Thanks, @TheBF @Tursi @Lee Stewart! This gives me a bunch of things to experiment with, which is what I'm going to do 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704254 Share on other sites More sharing options...
+TheBF Posted December 20, 2020 Share Posted December 20, 2020 I just tried polling 837B and I never see a change on bit 0 in TF or Camel Forth (interrupts mostly on). I am missing something from Tursi's post clearly. I tried do Lee's code in Forth just for fun and the loops are too slow to reliably catch the vertical blanking interrupt every time. I did this little test in Camel99 Forth and it seems to look cleaner when I wait "NE UNTIL". I think because I am masking out the bit versus using the COC instruction. NEEDS .S FROM DSK1.LOWTOOLS MARKER /REMOVE CODE WAITVDP ( -- ) 8802 @@ R0 MOVB, BEGIN, 8802 @@ R0 MOVB, R0 8000 ANDI, NE UNTIL, NEXT, ENDCODE : FILLA 0 3C0 41 VFILL ; : TEST BEGIN WAITVDP FILLA WAITVDP PAGE ?TERMINAL UNTIL ; 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704278 Share on other sites More sharing options...
+Lee Stewart Posted December 20, 2020 Share Posted December 20, 2020 Oh, dear! My code has a serious error! See corrections in my last post. ...lee 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704326 Share on other sites More sharing options...
Hans23 Posted December 21, 2020 Author Share Posted December 21, 2020 I had some unexpected behavior when calling WI and COINC in a loop - Sometimes, things seem to work fine, but if I changed the invocation order in the loop, COINC failed to detect overlaps. It seems like TurboForth is somehow dealing with interrupts, after all: ; COINC ( tolerance spr1 spr2 -- flag ) _coinc mov @bank1_,@retbnk ; return to bank 1 if taking interrupt limi 2 ; let interrupts run limi 0 mov *stack+,r2 ; get spr2 mov *stack+,r1 ; get spr1 movb @>837b,r0 ; get vdp status register (ed/as pg. 405) andi r0,>2000 ; check collision bits jeq miss ; if NO sprites are in collision then ; don't do the rest of the test. If I understand correctly, the LIMI 2/LIMI 0 sequence unmasks interrupts for the duration of one instruction, is that correct? Does this cause queued (VDP) interrupts to be processed? In that case, would WI interfere in clearing the VDP status word, which would then make COINC not detect the overlap? I dug a little deeper into the TurboForth code and there seems to be an interrupt service routine. I guess this would be a good place to hook in to, which would also allow me to maintain an incrementing frame counter. Thank you for your help! -Hans Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704636 Share on other sites More sharing options...
+TheBF Posted December 21, 2020 Share Posted December 21, 2020 I am not an expert but I cannot think of a way that TI-99 can "queue" interrupts beyond a count of one. I think it is more the case of if an Interrupt is pending when the LIMI 2 runs the interrupt code will run. Then when it completes the LIMI 0 prevents another interrupt. The problem I see with this method is that it turns the interrupt service code into a kind of polled activity that only runs when you allow it to run, versus something that runs on a digital timer with precision. So to my mind it defeats the purpose of using an interrupt routine. I you wanted a polled service it is very simple to make a Forth word POLL for example and put in your code whenever you are looping and before low level I/O routines. This will accomplish the same thing but you have complete control of when your "background" code runs. This is in fact how the traditional Forth multi-tasker works. The word PAUSE is used. So hooking into the systems interrupt may not be ideal when TF is preventing the interrupt from happening. You will have to try it to see how frequently it runs. I did a little video on hooking the console interrupt in Camel99 Forth that may be of use. Most of the words should work in TF except for CODE ENDCODE which are ASM: ;ASM in TF. 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704850 Share on other sites More sharing options...
+Lee Stewart Posted December 21, 2020 Share Posted December 21, 2020 8 hours ago, Hans23 said: It seems like TurboForth is somehow dealing with interrupts, after all: I never said TurboForth did not deal with interrupts because, indeed, it does—as you discovered. What I said was that interrupts are normally off. The “LIMI 2” instruction is only ever executed when followed immediately by “LIMI 0”. There are only 11 instances of this pair of instructions in the ALC of the TurboForth cartridge (I did not analyze utilities in blocks files). That said, these get called with virtually all keyboard/joystick activity and most accesses to the VDP so @Tursi’s comments are still germane. ...lee Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704875 Share on other sites More sharing options...
+mizapf Posted December 21, 2020 Share Posted December 21, 2020 The TMS9900 has no interrupt queue. Interrupts are level-driven, not edge-driven. When there is a VDP interrupt, the VDP raises the interrupt line, this passes through the 9901 and then to the INTREQ input of the 9900. The VDPINT stays asserted until you read the video status register. This is normally done in the interrupt handler in ROM. So if you mask away the interrupts with LIMI 0, and an interrupt occurs, nothing happens until you do a LIMI 2, in which case the still pending interrupt is sensed. However, if during the LIMI 0 phase the video status register is read, the interrupt is gone. The 9995 is a bit different in that respect, as it latches incoming interrupts in the internal CRU space. 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4704908 Share on other sites More sharing options...
Hans23 Posted December 21, 2020 Author Share Posted December 21, 2020 What I'm really after is a real-time counter. I had, not knowing a lot about the TI-99/4A, assumed that the vertical blanking event would be a good way to get a 50/60Hz interrupt source. From what I read, it seems that with TurboForth, it would be best to rely on the LIMI 2 LIMI 0 sequence for handling the interrupts, and make sure that one of the words that has this sequence is called often enough. I would think that installing a user-defined ISR handler in the USRISR hook would be the appropriate place to interface to the "polled interrupts" scheme. Does that make sense? Is vertical blanking the only interrupt source, or are there any other interrupts that could cause the USRISR to be invoked? Sorry for the naive questions, I'm still new to the TI-99/4A and to Forth and I appreciate your patience! Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705039 Share on other sites More sharing options...
Hans23 Posted December 21, 2020 Author Share Posted December 21, 2020 4 hours ago, TheBF said: I did a little video on hooking the console interrupt in Camel99 Forth that may be of use. Most of the words should work in TF except for CODE ENDCODE which are ASM: ;ASM in TF. This is useful, thanks! 2 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705059 Share on other sites More sharing options...
+Lee Stewart Posted December 21, 2020 Share Posted December 21, 2020 25 minutes ago, Hans23 said: What I'm really after is a real-time counter. I had, not knowing a lot about the TI-99/4A, assumed that the vertical blanking event would be a good way to get a 50/60Hz interrupt source. From what I read, it seems that with TurboForth, it would be best to rely on the LIMI 2 LIMI 0 sequence for handling the interrupts, and make sure that one of the words that has this sequence is called often enough. I would think that installing a user-defined ISR handler in the USRISR hook would be the appropriate place to interface to the "polled interrupts" scheme. Does that make sense? Is vertical blanking the only interrupt source, or are there any other interrupts that could cause the USRISR to be invoked? Sorry for the naive questions, I'm still new to the TI-99/4A and to Forth and I appreciate your patience! The TurboForth ISR is called through >83C4 every time the console ISR runs and the user’s ISR is called through USRISR (>A008) every time the TurboForth ISR runs. Others here can give you better details, but other interrupts can occur in addition to the VDP interrupt—notably, peripheral ROMs, etc., are polled for interrupts. You can use the VDP interrupt timer at >8379, which is ticked every time the VDP interrupt is serviced. As a one-byte timer, it rolls over to 0 every 256 ticks (60ths of a second). ...lee 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705071 Share on other sites More sharing options...
Hans23 Posted December 21, 2020 Author Share Posted December 21, 2020 3 minutes ago, Lee Stewart said: You can use the VDP interrupt timer at >8379, which is ticked every time the VDP interrupt is serviced. As a one-byte timer, it rolls over to 0 every 256 ticks (60ths of a second). Lee, this looks quite appropriate, thanks! 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705075 Share on other sites More sharing options...
+TheBF Posted December 21, 2020 Share Posted December 21, 2020 9 minutes ago, Lee Stewart said: The TurboForth ISR is called through >83C4 every time the console ISR runs and the user’s ISR is called through USRISR (>A008) every time the TurboForth ISR runs. Others here can give you better details, but other interrupts can occur in addition to the VDP interrupt—notably, peripheral ROMs, etc., are polled for interrupts. You can use the VDP interrupt timer at >8379, which is ticked every time the VDP interrupt is serviced. As a one-byte timer, it rolls over to 0 every 256 ticks (60ths of a second). ...lee Is the accuracy affected with interrupts disabled most of the time? 1 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705081 Share on other sites More sharing options...
+mizapf Posted December 21, 2020 Share Posted December 21, 2020 You can also set up a timer with the 9901 (timer mode). 2 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705089 Share on other sites More sharing options...
+Lee Stewart Posted December 21, 2020 Share Posted December 21, 2020 15 minutes ago, TheBF said: Is the accuracy affected with interrupts disabled most of the time? All keyboard/joystick accesses and almost all accesses to the VDP start with LIMI 2 LIMI 0 I say, “almost all” because there are instances where that is not the case—notably, the word VMBR does not enable interrupts whereas V@ V! and VMBW all do. Other than that, I cannot say. Hopefully, @Willsy gets in here ere long. ...lee 3 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705097 Share on other sites More sharing options...
+TheBF Posted December 21, 2020 Share Posted December 21, 2020 3 minutes ago, mizapf said: You can also set up a timer with the 9901 (timer mode). Excellent point. I use it for the ISO Forth word MS which delays n milli-seconds. My code is not TurboForth compatible because I keep top of stack cached in R4 but here it is to give you some ideas. This is in cross-compiler Forth so it has some magic words included that you won't need. Happy to answer questions. Spoiler \ TICKTOCK.HSF TMS9901 hardware timer interface for Camel 99 Forth \ credit to: http://www.unige.ch/medecine/nouspikel/ti99/tms9901.htm#Timer \ timer resolution: 64 clock periods, thus 64*333 = 21.3 microseconds \ Max Duration : ($3FFF) 16383 *64*333 ns = 349.2 milliseconds CROSS-ASSEMBLING CODE: TMR! ( -- ) \ load TMS9901 timer to max value 3FFF W 3FFF LI, \ load scratch register W with MAXIMUM timer value R12 CLR, \ CRU addr of TMS9901 = 0 0 LIMI, 0 SBO, \ SET bit 0 to 1, Enter timer mode R12 INCT, \ CRU Address of bit 1 = 2 , I'm not kidding W 0E LDCR, \ Load 14 BITs from R1 into timer R12 DECT, \ go back to address 0 0 SBZ, \ reset bit 0, Exits clock mode, starts decrementer 2 LIMI, NEXT, \ 16 bytes END-CODE CODE: TMR@ ( -- n) \ read the TMS9901 timer TOS PUSH, R12 CLR, 0 LIMI, 0 SBO, \ SET bit 0 TO 1, ie: Enter timer mode TOS 0F STCR, \ READ TIMER (14 bits plus mode bit) into W TOS 1 SRL, \ Get rid of mode bit 0 SBZ, \ SET bit 1 to zero 2 LIMI, NEXT, END-CODE CODE: |-| ( x y -- x n ) \ : |-| OVER - ABS ; *SP TOS SUB, TOS ABS, \ get ABS of subtraction NEXT, END-CODE TARGET-COMPILING [CC] DECIMAL [TC] \ 1 JIFF = 1/60 second. (16.6666 mS) \ 650 is tested number using Classic99 emulator. \ Real IRON might need tweeking : JIFF ( -- ) TMR@ BEGIN PAUSE TMR@ |-| 650 > UNTIL DROP ; \ Because JIFFS are 1/60 seconds, there is a lot of time while PAUSE \ switches to all the tasks. So JIFFS are the preferred way to delay \ in a multi-tasking program. : JIFFS ( n -- ) 0 ?DO JIFF LOOP ; : MS ( n -- ) 4 RSHIFT JIFFS ; \ MS/16= JIFFS [CC] HEX [TC] Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705099 Share on other sites More sharing options...
Tursi Posted December 22, 2020 Share Posted December 22, 2020 (edited) On 12/20/2020 at 12:45 PM, Lee Stewart said: Interrupts are normally ON in TI Forth and fbForth, but OFF in TurboForth. ...lee Are you sure? I booted Turboforth when I wrote that email and it breakpointed in the interrupt routine while just sitting at the command prompt... (Edit: ah, I see your explanation in post 11 -- I guess we now have system that try to leave interrupts on all the time, but 99% of the time LIMI 2/LIMI 0 is the very TI definition of interrupts being enabled ) Edited December 22, 2020 by Tursi 2 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705407 Share on other sites More sharing options...
Willsy Posted December 22, 2020 Share Posted December 22, 2020 Interrupts are off most of the time in TurboForth. I legacy of a naive design decision by yours truly. At the time though, I was going for speed. I seem to remember experimenting with getting TF with interrupts enabled but couldn't get it to work. At least not easily, so I gave up! It's fairly easy to install a user ISR in TF. Poke in some machine code, either using the assembler or using CODE: load the ISR vector at >A008 with the address of the machine code. Caveats: The ISR vector must point to the machine code, not the CFA of the machine code as built by the Forth assembler or by CODE: This amounts to ticking the machine code word and adding 2 to move past the CFA The ISR must use RT/B *R11 instruction to return to the TF (TF does a regular BL to your ISR) Since TF does a regular BL to your ISR, you are in TF's register workspace, so be careful! Don't change R3, R4, R5 and R12 - or, if you change them, restore them before you return. Example to create a 'frame counter' ISR: variable fcount ASM: ISR fcount @@ inc, r11 ** b, ;ASM ' ISR 2+ $A008 ! (at this point the ISR is loaded and running) FCOUNT @ . FCOUNT @ . Here's a video I did last night showing the process for those that are interested ? 3 2 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705639 Share on other sites More sharing options...
GDMike Posted December 22, 2020 Share Posted December 22, 2020 Lol, I didn't see that B**** word entered. Hmm..I've watched twice.... But kiddn' aside, interesting. Merry Christmas Mark 1 2 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705682 Share on other sites More sharing options...
RXB Posted December 22, 2020 Share Posted December 22, 2020 On 12/21/2020 at 6:26 AM, TheBF said: I am not an expert but I cannot think of a way that TI-99 can "queue" interrupts beyond a count of one. I think it is more the case of if an Interrupt is pending when the LIMI 2 runs the interrupt code will run. Then when it completes the LIMI 0 prevents another interrupt. The problem I see with this method is that it turns the interrupt service code into a kind of polled activity that only runs when you allow it to run, versus something that runs on a digital timer with precision. So to my mind it defeats the purpose of using an interrupt routine. I you wanted a polled service it is very simple to make a Forth word POLL for example and put in your code whenever you are looping and before low level I/O routines. This will accomplish the same thing but you have complete control of when your "background" code runs. This is in fact how the traditional Forth multi-tasker works. The word PAUSE is used. So hooking into the systems interrupt may not be ideal when TF is preventing the interrupt from happening. You will have to try it to see how frequently it runs. I did a little video on hooking the console interrupt in Camel99 Forth that may be of use. Most of the words should work in TF except for CODE ENDCODE which are ASM: ;ASM in TF. Hmm since RXB even before 2001 versions had CALL ISRON(variable) or CALL ISROFF(variable) CALL ISROFF(variable) put the ISR hook value into that variable and stopped any ISR interrupts like Assembly ISR hooks. CALL ISRON(variable) put the Assembly ISR hook into variable and turned ISR interrupts like Assembly back on. Reason for this in RXB was so you could stop programs that had a interrupt and save or load them then restart them. This was demoed to show 23 Assembly programs all run from DISK from same XB program in Demo. Later did that same demo using SAMS memory. Always cool how I see rediscoveries of this stuff later. 2 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705819 Share on other sites More sharing options...
+TheBF Posted December 22, 2020 Share Posted December 22, 2020 I am rediscovering everything. I have a listing here in a binder where I hooked the ISR in TI-Forth dated Sept 17, 1987. Did I remember any of it after 30 years. Not really. 2 Quote Link to comment https://forums.atariage.com/topic/314825-vblank-in-turboforth/#findComment-4705834 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.