Last visit was: Fri Jul 19, 2024 5:57 am
It is currently Fri Jul 19, 2024 5:57 am

 [ 5 posts ] 
 BCPL (and Enigma) on OPC6 
Author Message

Joined: Tue Apr 25, 2017 7:33 pm
Posts: 32
I've been meaning to do something with BCPL for a long time now. Once upon a time, when I was a student, I bought the book intending to use it with the Arnor BCPL system on the Amstrad CPC computer. That idea was quickly shelved however as I moved onto C instead on the ST and PCs. I still have the book though and I see that I scribbled my name and a date inside the front cover: 1988. Ouch. That's nearly 30 years ago now. Surely some kind of a record for 'getting around to it', but I will happily cede that record to any challengers.

Well, the important thing is that I have finally got around to it. I've just pushed some new code into the OPC6 GitHub repo which allows a subset of BCPL code to be compiled and run on OPC6 directly. It's a work in progress (of course) and there are many limitations, but there's enough there to run a number of the BCPL demo programs including a couple of Enigma machine emulators.

You probably already know that BCPL is the forerunner to C. It's a block structured language with integer arithmetic and a fixed single size data type: everything is a word. OK, that's not quite true as you can have arrays of words and the ability to pack text data into byte strings was added later but that is the essence of things. BCPL compiles first into an intermediate bytecode which is then either translated into native assembly language or, more usually, run directly using an interpreter (so BCPL is also a forerunner of things like the UCSD p-system and Java. And PLASMA!). In this way BCPL has always been highly portable with only the final translation or runtime interpreter needing to be rewritten for new target systems. Over the years BCPL has been provided with the ability to compile to a few intermediate bytecodes with OCODE and CINTCODE being the longstanding formats. More recent distributions have provided yet another type: SIAL - pronounced like 'seal' apparently, so in the unlikely event that you should ever need to pronounce it now you know.

Sial Specification

Sial is a machine independent target code for BCPL. It consists
of a stream of directives and instructions each starting with an opcode
and operands. Both opcodes and operands are encoded by integers. Each
integer is prefixed by a letter specifying what kind of value it
represents. The prefixes are as follows:

F An opcode or directive
P A stack offset, 0 to #xFFFFFF
G A global variable number, 0 to 65535
K A 24 bit unsigned constant, often small in value
W A 32 bit signed integer, used for static data and large constants
C A string character in range 0..255
L A label generated by TRN
M A label generated by CG

The instructions are for an abstract machine with internal registers

a The main accumulator, function first arg and result register
b The second accumulator used in dyadic operations
c Register used by pbyt and xpbyt, possibly currupted by
some other instructions, eg mul, div, rem, xdiv and xrem.
P Pointer to the base of the current stack frame
G Pointer to the base of the Global Vector
PC Set by jump and call instructions

There's a good description of SIAL in the PDF document: (and beware that the textfile documentation in the distribution is not completely in sync with the actual bytecodes which are implemented in the SIAL generator.) SIAL looks a lot more accessible to me than the previous codes, so getting BCPL to run on OPC6 then is a question of using the BCPL system to compile into SIAL and then remapping that to OPC6 assembler. Some low level hardware specific routines need to be created but many of the BCPL standard library routines can be compiled directly from their BCPL source into SIAL and ported too, including the trendsetting writef() family of functions.

Here's the BCPL code for the obligatory Hello World program (another tradition established by BCPL)

GET "libhdr"

LET start() = VALOF
{ writef("Hello World!*n*c")

And here's the OPC6 translation with the SIAL opcodes in the in-line comments. (No library code included here for brevity)

        # Module start                                   # F104
                                                         # Module Entry - start
_F0_L1:                                                  #
        sto r11,r3                                       #
        mov r11,r3                                       #
        sto r13,r11,1                                    #
        sto r4,r11,2                                     #
        sto r1,r11,3                                     #
        mov r1,r0,_F0_M9001                              # F112 _F0_M9001
        mov r3,r11,3                                     # F32 P3 G94
        ld r4,r12,94                                     #
        jsr r13,r4                                       # ** Call to global function number 94 **
        mov r1,r0,0                                      # F11 K0
        ld r4,r11,1                                      # F77
        ld r11,r11                                       #
        mov pc,r4                                        #
_F0_M9001:                                               # F107 _F0_M9001 K14 C72 C101 C108 C108 C111 C32 C87 C111 C114 C108 C100 C33 C10 C13
        WORD 14                                          #
        STRING "Hello World!\012\015"                    #
        WORD 0x00                                        #
                                                         # # Global Resources: F106 K1 G1 _F0_L1 G94
                                                         # Module End - start

The translator and libraries are by no means complete, but already I have got a lot further than just running hello world. I've put some demo programs taken from Martin Richards' BCPL distribution in the opc6/bcpltests/ directory. I had to make a few trivial modifications to most of these demos - for example, BCPL uses LF as line endings, but running on the BBC system I needed to make these into LFCR pairs and I might have tidied up some other text formatting to fit the screen layout of the Beeb a little better - but essentially they are pretty much as supplied. There are demos of recursive programming (fact.b), and the n-queens (queens.b) problem running on different sizes of chessboards and even a program that plots Mandelbrot sets in ASCII characters! More fun though are the two Enigma machine emulators. The first, enig.b is a very basic implementation which encodes and decodes an message embedded in the code itself. The second, enigma-m3.b is an interactive program with an ASCII text display showing the state of the rotors and the electrical wiring path updating for each letter of the message. Here are a couple of screenshots from the code running on Hoglet's most excellent PiTubeDirect implementation of the OPC6 connected to a BBC Master computer.

Enigma Machine Emulation

Various Small BCPL Tests

Apfel Mandelbrot Set

The BCPL compiler is provided in 32 and 64 bit versions but of course OPC6 is a lowly 16bit machine. For this first version of the sial2opc6 translation I have stuck with that 16 bit word size and truncated all data to fit. This actually works pretty well, but it means that some of the maths benchmarks and demos have to be restricted a little to avoid running of range causing numeric overflows. And speaking of maths benchmarks, the only BCPL code I've written myself is yet another implementation of the pi digit generating spigot algorithm (pi-spigot-bcpl.b) which we used to compare different OPC machines here. At some point I will update that thread to compare the histograms and cycle counts of our previous hand coded assembler versions against the compiled BCPL.

If you want to try it out then you need to setup BCPL as described in the distribution. Make sure that the various BCPL environment variables are all set (BCPLROOT, BCPLHDRS etc) and that you can run some of the demos using the cintcode system first. Once that's done, here's a simple listing of commands to compile and run a BCPL program on OPC6 using the emulator assuming that you have the fact.b BCPL source, the bcpllib.sial, rom.s and the syslib.s files all in the current dir (they are all provided in git in opc6/bcpltests)

cd opc6/bcpltests
cintsys -c bcpl2sial  fact.b to fact.sial
python3 ../  -f fact.sial -f bcpllib.sial -s syslib.s > tmp.s
cat tmp.s rom.s > fact.s

# Assemble the source and run
python3 ../ fact.s fact.hex | tee fact.lst
python3 ../ fact.hex fact.dump | grep OUT | ../../utils/

...and you should get this output from the emulator.

Factorial of 1 = 1
Factorial of 2 = 2
Factorial of 3 = 6
Factorial of 4 = 24
Factorial of 5 = 120
Factorial of 6 = 720
Factorial of 7 = 5040

(NB using pypy3 rather than python3 provides a useful speedup for running larger tests on the emulator.)

There are a number of things to improve and extend in this first prototype but I'm not really intending to roll out a complete 16bit BCPL system. This has been more of a proof of concept and a learning exercise for me. For one thing I'd like to get the same level of functionality from BCPL up and running for my other, rather neglected, 16 bit project. And in OPC world it's clear that a 32 bit implementation would run many more of the BCPL demos much better, being able to handle the floating and fixed point libraries in the distribution directly. Now of course it would be possible to do a 32 bit implementation to run on OPC6 (effectively a different emulation of the SIAL machine), but would be so much more straightforward to do for a full 32bit OPC. And I think that at some point very soon that's what I'll do.


You do not have the required permissions to view the files attached to this post.

Wed Sep 20, 2017 7:54 pm

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1789
Retrotastic! Great work, and perhaps an encouraging and useful story for bringing BCPL up on any other homebrew CPU.

Wed Sep 20, 2017 8:07 pm

Joined: Sat Aug 05, 2017 6:57 pm
Posts: 26
Very cool stuff! I played around porting BCPL to the BBC Micro [1] a good many years ago, but never got past the stage of writing an INTCODE interpreter - I started trying to write an OCODE->6502 pass and got bogged down in the complexity. It's nice that this SIAL-based approach generates native code at the end, rather than requiring a VM.

[1] I know there was already an official port, but I think this was a combination of not being able to get hold of that easily - the retro scene wasn't quite as well-developed back in the mid 90s IIRC - and it seeming a cool project to try doing myself.

Sat Sep 23, 2017 2:37 pm

Joined: Wed Jan 09, 2013 6:54 pm
Posts: 1789
I've just managed to get my BlackIce board connected up and loaded with an OPC6 image.

By way of celebration, I ran the 'apfel.b' program and it completed in 5.5s:
MMMMMMMMMMMMMMMMMMMMMMMMMMMM""         ""                            mMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMM"MM"                                          mMMMMMMMMMM
MMMMMMMMMMMMMMmmmmmmmm mm                                         ""MMMMMMMMMMM
MMMMMMMMMMMMMMMMMMMMMMMMMMmm                                         MMMMMMMMMM


Mon Sep 25, 2017 6:15 am

Joined: Tue Apr 25, 2017 7:33 pm
Posts: 32
That's great. Just for comparison the Apfel.b program takes about 9s when running on the PiTubeDirect OPC6 implementation.

The ASCII output of this and the enigma-m3.b is nice, but there are some graphical demos in Martin Richard's distribution which would probably work on the BBC co-processor versions, if we were to port parts of his graphics library to use the BBC MOS calls.

Mon Sep 25, 2017 7:42 am
 [ 5 posts ] 

Who is online

Users browsing this forum: CCBot and 0 guests

You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software