Friday, June 28, 2019

RSX11 program to display time on PDP11/PiDP11 front panel displays


  I mentioned in a previous post that I have a PiDP11 - a device that lets you simulate a PDP-11/70, with front panel. It still works great. I treat it just like an 11/70, and often forget that it's run by SIMH and a Raspberry PI.

  I have it set up on my desk,  running all the time. Lately, though. I've been thinking that the front panel  can do a lot more than just display the RSX11 idle loop (as amusing as that is). I got to wondering, what can I do with 16 bits worth of display register? Almost immediately, I decided on the tiredest, tritest, most over done hardware hacker's project - a clock!

  I figured, I can display the hours (1-12) in the highest 4 bits, and the minutes and seconds (0-59) in the next 12 bits, 6 bits each. It will be easy for any RSX system programmer to read, and really annoying for anyone else not used to constantly reading bits as octal numbers and converting them to decimal in their head.

  In 30 minutes or so I'd whomped up a program that did just that. But - it was too simple - all it had to do was look up the time, derive some bits for it, and then write it to the display register's address, then pause a second and loop around and do it again. Where's the fun in that? Plus, there ain't much interesting going on in it, and I like to illuminate some interesting aspect of RSX with each of these posts.

  So I decided, to rewrite it to be AST driven. ASTs (stands for Asynchronous Software Trap) are a mechanism where you can have subroutines that get called not in line with your main program, but that interrupt your main program and execute whenever certain things occur - asynchronously (thus the name).

  I'm aware, in this modern cybernetic rocket powered nuclear day and age, where most platforms have the ability to do that, and more, with threads, this sounds like pretty small potatoes. But, this "thread and a half" sort of implementation of ASTs give you a powerful  tool for dealing with things that don't occur on a predictable linear basis.

  ASTs can be triggered by lots of things - IO completion, a timer expiring, a key being typed, and the like. This lends itself to a style of programming where you set up the ASTs to run whenever the events you are interested in occur, and then just wait for them to happen. The main program can consist of just a few lines to set things up, and all the work occurs in the ASTs, when it needs to.

  So in this case, I want the clock to update once a second. RSX provides the MRKT$ directive to create marktime events. A marktime event specifies a span of time. After this time is elapsed, it can set an event flag, call an AST routine, or both. I set a marktime event to occur in 1 second. This event will set an event flag, and call  CLKAST, my clock AST routine, that does all the real work for this project.

  Setting a marktime event does not cause your code to pause and wait for it to occur - your program continues executing after the MRKT$ directive is executed. Since I don't have anything else I need done in the mainline code, I use WTSE$, Wait For Single Event Flag, to cause the mainline code to sleep until the event flag specified in the marktime event is set. When the marktime event comes due, the AST routine is called, and the event flag is set. When the AST routine completes, the WTSE$ wait is satisfied by the event flag being set, so the mainline code proceeds. I have a branch at that point, to have it go back to the beginning and arm everything again, for the second to pass.


  The AST routine, CLKAST, like I say, does all the real work. It reads the system time, formats it as bits into a register, and then writes it into the display register. Then it does an AST exit.

  OK, not the best explanation or example of ASTs in the world . Have a look at the code and it should become a lot clearer....

clock.mac


To use...

>mac clock=clock
>tkb clock/pr=clock
>run clock

  The task is built privileged (the tkb /PR switch above) so it maps the IO page and  can write to the display register.

  It's not going to prompt for any input, so you can just do a Control-C, get a new MCR prompt, and continue working with clock in the background. To stop it, do an ABO command. Or run it at boot time from the console, or from batch - you know, all the usual ways.

  To see the time in the LEDs, turn the lower console knob to "Display Register".

  In closing, I should mention that ASTs can interrupt the mainline code most any time (it's asynchronous, right?). That means, if the mainline code and the AST routine want to access the same variables, you have to give some thought to coordinating access to those variables. In a program more complicated than this example you may need to  disable and enable AST delivery in the mainline code, to create critical sections, if you need some operations to occur uninterrupted. If you start doing much of this, you'll learn all about multitasking, dining with philosophers, and deadlocks - it will be fun!