+InsaneMultitasker Posted March 5, 2011 Share Posted March 5, 2011 I was down in the dungeon repairing someone's HFDC. In the process I got the itch to call Richard's BBS and was quickly reminded how slow the TI terminal emulators respond. So then I got to thinking... Most terminal emulators make use of the Interrupt routine and the Circular Interrupt Buffer. The CIB is stored in VDP RAM and manipulated by the RS232 DSR based on interrupts. As you all know, the interrupt routine itself is a nasty beast - add RS232 into the mix and bugs associated with it, and the CIB is overrun quickly. I sketched up a general process flow and am thinking that maybe.. just maybe... a different approach might work. Instead of relying on the interrupt routines and DSR, what if I mimicked the game loops/timers/schedulers? In simplified form here is what I concocted: MAIN LOOP dedicated to: Task scheduler RS232 character receipt Circular input buffer within CPU RAM for received chars (up to 8k) SCHEDULED EVENTS keyboard input (stand-along, NOT ROM based) display routine utilizing method described by Matthew (use VDP as output only) menu functions (testing for which key was depressed) Where this concept may fail is during the scheduled events. I probably would need to call the RS232 character receipt code periodically within the events (non-interruptible, non-reentrant). I haven't done any timing calculations. Figured I'd toss my idea out for people to poke at, especially those who inspired turning the usual solution upside down. Tim Quote Link to comment Share on other sites More sharing options...
+retroclouds Posted March 5, 2011 Share Posted March 5, 2011 Hi, I think the changes done to the thread scheduler in spectra2 might be just what you need for doing some quick tests. I now have the possibility to run a user-hook real fast and let other threads run 50/60 times a second (e.g. screen updates, etc.) I'm close to a release now. Documentation and source code is finished, just need to release it which I probably do this weekend. If I don't manage to release this weekend then I'll send you the spectra2 package via email Quote Link to comment Share on other sites More sharing options...
matthew180 Posted March 5, 2011 Share Posted March 5, 2011 I think it sounds pretty good. Remember, "game loop" is just another name for Finite State Machine (FSM), and using and the concept of the FSM can be applied to many problems. The whole idea of a "task" or "thread" is also artificial on systems with only 1 CPU. Even 2 to 4 CPUs or "cores" does not really come close to the number of threads or processes that may be running on a modern OS, so there is always going to be time-slicing of the CPU going on. IMO, when you need performance, manage the time slicing yourself instead of letting an OS or generic scheduler do it. In this case, it seems that the communication channel is the most critical, so you want to make sure you don't delay in checking for incoming data, or sending data out. I have not done any communications on the 99/4A, but it seems you would always want to poll for new data every time through your loop, and see if data needs to go out. But that depends on how the RS232 card indicates incoming / outgoing data. The other non-critical tasks should probably be staggered so no one routine takes too much time away from 1 pass through the current loop. For the keyboard, checking for input 30 times a second is plenty. Humans are not that fast anyway. For the screen, only update it when something changes (no need to redraw a screen that has not changed.) Use the VDP interrupt to track timing events on a 60th of a second scale, like polling the keyboard, or maybe displaying a clock or something. Some pseudo code might be: int1sec int30 div2 div60 div2 := 0 div60 := 0 clock := 00:00:00 loop: // these are only active for a single loop int1sec := 0 int30 := 0 render := 0 if VDP interrupt int60 := 1 div2 += 1 div60 += 1 if div2 == 2 int30 := 1 div2 := 0 endif if div60 == 60 int1sec := 1 div60 := 0 endif endif if received data process incoming data // Incoming data probably needs to be displayed. render := 1 endif if outgoing data process outdoing data endif if int1sec // Update the "time connected" clock. process clock render := 1 endif if int30 if poll keyboard process input // A key press will probably always trigger something on-screen to // change, so register that a screen update is needed. render := 1 endif else if render // Only render when not polling the keyboard redraw display endif endloop I'm making a lot of assumptions here, but that's the basic idea anyway. I hope it helps somehow. Quote Link to comment Share on other sites More sharing options...
Mad Hatter Posted March 5, 2011 Share Posted March 5, 2011 Tim, Speaking of terminal emulators, I just used PORT on the Geneve the other day! (This is Kyle, BTW) Quote Link to comment Share on other sites More sharing options...
Tursi Posted March 5, 2011 Share Posted March 5, 2011 Heh.. I thought everyone polled the RS232 card. You won't have much trouble at the usual TI speeds, anyway. My old BBS code was simpler than that.. it polled both the keyboard and the RS232 receive character bit, and when either was received, it would pass that character to the input routine which would store it and display it on the screen. When you hit enter it would process away. Of course, the advantage I had there was that the BBS was in control of the conversation, a terminal emulator doesn't know when it's expecting characters. Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted March 5, 2011 Author Share Posted March 5, 2011 Tim, Speaking of terminal emulators, I just used PORT on the Geneve the other day! (This is Kyle, BTW) Hey Kyle Glad you had a chance to try it out. For those reading, PORT is a Geneve term emulator I wrote but didn't quite finish back in '95. In that program, there is no OS dependent code. It can handle 38.4k just fine via interrupt-driven polling or hardware handshaking. Supplanting the OS's interrupt handler with my own was simple - the Geneve has no ROM. Quote Link to comment Share on other sites More sharing options...
+InsaneMultitasker Posted March 5, 2011 Author Share Posted March 5, 2011 I think it sounds pretty good. Remember, "game loop" is just another name for Finite State Machine (FSM), and using and the concept of the FSM can be applied to many problems. The whole idea of a "task" or "thread" is also artificial on systems with only 1 CPU. Even 2 to 4 CPUs or "cores" does not really come close to the number of threads or processes that may be running on a modern OS, so there is always going to be time-slicing of the CPU going on. IMO, when you need performance, manage the time slicing yourself instead of letting an OS or generic scheduler do it. In this case, it seems that the communication channel is the most critical, so you want to make sure you don't delay in checking for incoming data, or sending data out. I have not done any communications on the 99/4A, but it seems you would always want to poll for new data every time through your loop, and see if data needs to go out. But that depends on how the RS232 card indicates incoming / outgoing data. The other non-critical tasks should probably be staggered so no one routine takes too much time away from 1 pass through the current loop. For the keyboard, checking for input 30 times a second is plenty. Humans are not that fast anyway. For the screen, only update it when something changes (no need to redraw a screen that has not changed.) Use the VDP interrupt to track timing events on a 60th of a second scale, like polling the keyboard, or maybe displaying a clock or something. Some pseudo code might be: [snip] I'm making a lot of assumptions here, but that's the basic idea anyway. I hope it helps somehow. Good points. In most of my programs, I never considered a FSM. I used interrupts for timers, countdowns, or periodic polling but not in the manners described in the forum. Guess I'd attribute that to the fact most of my program routines flow sequentially. This helps to explain why my game attepmts never amounted to much unless they were turn-driven (grin) Polling for characters is relatively simple. You can allow receive and/or transmit interrupts and you can test for completion of a received/sent character. I envision testing the RS232 interrupt CRU line and if set, handle accordingly. Bypassing the CIB and ROM interrupt handler keeps the system's paws off the VDP leaving the terminal in charge. RS232 interrupt polling could then occur during VDP/keyboard operations based on RS232 speed, similar to how your timer handles the interrupt itself. So... at 19,200bps you're looking at roughly 2,000 characters/second. The poll and store routine must be called at least this often to avoid missing characters. An 8K buffer allows 4 seconds of sustained data before overflow. Most sending programs will never crank out this much data unless you are viewing a large file or using a streaming transfer protocol (ie Ymodem-g, which assumes hardware handshaking anyway). Thanks guys for giving me some more to 'chew' on... 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.