Jump to content
IGNORED

Terminal Emulation


Recommended Posts

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

Link to comment
Share on other sites

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 :)

Link to comment
Share on other sites

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.

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

Link to comment
Share on other sites

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

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