Search This Blog

Sunday, 19 January 2025

 Recreating OPL

 


 

The Psion Organiser II came with an on-board programming language called OPL. I had an organiser in the 80s and used it for quite a few things, some of which used small OPl programs that I wrote. It's been described as being like BASIC, and at the time I would have agreed. After heading into a project to recreate the language from scratch, I'd now disagree with that statement. OPL is not BASIC. It's a very different beast, and has feature that BASIC doesn't. It is also missing some features that BASIC has, but if we recreate it, then we can add whatever we need.


Why recreate OPL? 

If you look at the image of an organiser above, you may notice that although it looks like a Psion Organiser 2, the display is a bit odd. That's because it is actually an organiser case with recreated electronics inside. there's details here:



The hardware uses a RP Pico to handle the processiong, and has circuitry to scan the keyboard and drive an OLED display with about the same resolution as the original. the power is switched in a similar way to the original, with a hardware on and soft-off.

The two PCB arrangement is also carried over and the new PCBs fit into the original cases. the first iteration of the new hardware and code used an emulator of the 6303 processor used in the original organiser and had hardware that attempted to provide the same features of the original, including datapacks. This worked well, really, the emulator could run the LZ ROM at about the same speed as the original, maybe a tiny bit faster. The Psion was a very low power device, holding data in static RAM and powering that during the off periods. The Pico isn't a low power device and so the internal storage (A: drive) is stored in some serial flash chips in the recreation. That allows it ot turn off fully when powered down, which the original never did (it actually wakes up every 30 minutes or so and check alarms and so on).


This is all well and good, but there were problems. Due to the hardware used, the datapack support never managed to provide writing to EPROM datapack. I never got the emulator to drive the programming hardware appropriately. The display is a dot matrix graphics capable unit, bu tthe emulated code couldn't do graphics as the original LCD was character based. After some input from the community I decided that it was fine to drop the emulator and run native C code on the recreation, as that is faster and can easily support things like a graphical display and SD cards. So, phase 2 of the recreated organiser started. This led to things like this:



These graphics are coded in C, and demonstrate the OLED capabilites. I have added a Psion datapack filesystem in the internal flash of the Pico and a menu system that is very simuilar to the original. I then thought that it would be interesting to code some or all of the UI of the recreated code in OPL, as that has quite good screen handling commands. that led to an examinatuion of OPL in more detail than I had done in the 80s.

OPL

 Here's some OPL:

expr:

local A,B,C

X% = 1
X% = 1 + 3
X% = ABS(2)
X% = ABS(1+400)

PRINT X%

At a quick glance it does look like BASIC, but there's the LOCAL statement and the first line is a bit odd. the basic unit of OPL is the procedure, one procedure per file (later versions of OPL for the Series 3 and later have an expanded syntax and capabilities, I'm talking about the Organiser 2 variant here). The first line defines a procedure called 'expr'. The LOCAL statement, unsurprisingly, declares some local variables. That's staring to get quite un-BASICy.

Variables in OPL are either integers, floating point or strings. You can have arrays of any of thoise (one dimensional). A % indictes an integer, a $ indicates a string and there is no suffix on floating point variables. We have integers and floating point variables in the snippet above.

 you may notice that X% isn't a local. It also isn't a global as there's a keyword that declares them, so X% is actually an external variable, one which is used in this procedure but declared in another procedure (as a global). This is moving quite a way from BASIC, and it gets further, so it's probably not worth considering BASIC from here on.

  OPL is not an interpreted language, source code has to be translated before it can be run. This can be done on-board by the organiser, there's no need to use another computer to do that (Psion did provide a suite of PC based tools that could, and there is at least one third party tool that could translate OPL as well). Translation, as it turns out, is maybe better described as compilation, albeit a simple version.

QCode

The translation turn OPL source into a byte code called QCode. QCode is stack based and has a more or less one to one correspondence between commands and functions and QCodes. Expressions in the OPL are turned into postfix expressions for evaluation. Integers and floating point numbers are automatically converted, so this is valid:

 

A = 1000

A% = 123.4 

QCode also has floating point primitives, as well as the sin, cos, etc functions. It also has codes for file system operations, so it's a higher level code than, say, 6303 machine code.

The Stack

Almost everything OPL is held on the stack. The variables are on the stack as is the QCode. The offsets used by QCode are 16 bits in size so the stack is limited to 64K. On the original organisers it was limited to about 32K as the rest of the RAM was used for storing other data.  The stack is used when evaluating the postfix expressions. Parameters for procedures are also on the stack. Procedures may call other procedures (or themselves: recursion is supported) and each procedure has a frame pointer which is used as a base when accessing the variables of that procedure, for example when searching for an external variable all the frame pointers are traversed until the variable is found or an error raised.


Files

OPL can access the file system of the Organiser, which has been designed to work on EPROM storage. The key aspect of this storage that poses problems is the impossibility of (useful) erasure. The media has to be formatted before use (all bytes are 0xFF) and the only writing allowed is to turn ones into zeroes. This is exactly the same as modern flash devices, so the organiser file system is well suited to storing data on flash devices. 

Machine Code

OPL has good support for machine code. You can put machine code in variables and then execute it, it supports values being returned from machine code routines and there is a lot of detailed documentation both from Psion and others that makes machine code useful and accessible. 

Modern usage

As mentioned, the file system scheme is well suited to flash devices as it was designed for EPROMs. Psion managed to fit the translator, the QCode runtime, a calculator, file system and several utilities into a 32K ROM (The LZ had a larger ROM). This was coded in 6303 assembly language. It shouldn't be too difficult to get a similar feature set to fit oin a modern microcontroller. If you drop the translator and have just a QCode runtime and translate on a PC then you could maybe fit onto a smaller microcontroller.#

The procedure architecture allows for code to be paged in from a larger storage device (such as an SD card) and run in RAM. Very large amounts of code can be paged into modest RAM, allowing for complex programs to be run.

With a recreation of the language, new keywords, data types and features can be added. This does require a completed recreated OPL, though.

For these reasons I decided to recreate OPL so that there is an on-board progrmming language for the recreated organiser hardware and also for use in future projects.

Github:

https://github.com/blackjetrock/newopl