BBC Micro: Compiling and Running Pascal Programs
A few posts back I mentioned that I'd like to write a working Pascal unit file for the P65Pas 6502 Pascal Compiler which can allow someone, including my self to write and compile Pascal programs for the BBC Micro. Here is the first part of that work which I will present to you here today. I am starting with the most minimal of Pascal components to get a simple Hello World program compiled, but will also have the basics of keyboard input also working. The following Pascal statements are currently implemented and have been tested to work, and simple Hello World program will be at the end which can be used with this new unit file to demonstrate how it works. I will be continuing and developing some other very common Pascal units from the Turbo Pascal era, which actually still work on modern FreePascal compilers, namely the crt unit, which will allow some old MS-DOS Pascal programs be ported over to the BBC Micro. So, let's begin.
bbc.pas unit
This is the main unit file which will define all the basic stuff for the BBC Micro, including some common Pascal routines like Write, WriteLn, ReadKey, and ReadLn. Here is the listing of the unit file which contains these:
////////////////////////////////////////////
// New unit created in 04-12-26}
////////////////////////////////////////////
unit bbc;
{$BOOTLOADER JMP}
{$STRING NULL_TERMINATED}
{$ORG $2000}
{$SET_DATA_ADDR '3000-30FF'}
interface
type
pointer = word;
string = array[] of char;
var
ReadError: byte;
procedure Write(s: pointer);
procedure WriteLn(s: pointer);
procedure ReadKey: char;
procedure ReadLn(s: pointer);
implementation
const
OSRDCH = $FFE0;
OSASCI = $FFE3;
procedure Write(s: pointer);
begin
asm
LDA s
STA $70
LDA s+1
STA $71
LDY #0
wloop:
LDA ($70), Y
BEQ wdone
JSR OSASCI
INY
BNE wloop
wdone:
end;
end;
procedure WriteLn(s: pointer);
begin
Write(s);
asm
LDA #$0D
JMP OSASCI
end;
end;
procedure ReadKey: char;
begin
asm
JSR OSRDCH
BCS nochar
RTS
nochar:
STA ReadError
LDA #0
end;
end;
procedure ReadLn(s: pointer);
begin
asm
LDA s
STA $70
LDA s+1
STA $71
LDY #0
rloop:
JSR OSRDCH
BCS rloop
JSR OSASCI
CMP #$0D
BEQ rdone
STA ($70),Y
INY
BNE rloop
rdone:
LDA #0
STA ($70),Y
end;
end;
end.
I used the official BBC Micro user guide to determine all the memory addresses for the various API calls seen above, and to determine that I can use $70-$71 in the zero page for my programs use, and in this case, it will use this was a way to store the pointer to the input and output buffers as LDA (ZZ), Y is used here to read and write data from this pointer. The program is also set to load in address $2000 which is just a wee bit above where BASIC code starts, so it would be wise to either run your program from a fresh boot, or after running the BASIC NEW command to ensure that BASIC memory doesn't become corrupted. Of course, if you needed to use BASIC alongside your Pascal code, you may need to adjust these memory locations, and/or set the BASIC HIMEM value appropriately.
Hello BBC from Pascal! Program Listing
Below is a simple Hello World program which uses all of these new statements except for ReadKey:
////////////////////////////////////////////
// New program created in 12-4-26}
////////////////////////////////////////////
program bbchello;
{$OUTPUTHEX 'HELLO,2000-2000'}
uses bbc;
var
na: array[40] of char;
begin
WriteLn(@'Hello World BBC Micro from Pascal!');
Write(@'What is your name? ');
ReadLn(@na);
Write(@'That is a very lovely name, ');
Write(@na);
WriteLn(@'! ');
Exit;
end.
The OUTPUTHEX at the top of this file will be the output file, and since we are creating a raw binary which will load at address $2000, this is how the file should be formatted before copying it over to a RISC-OS system with the BeebIt emulator using BeebItFS. If you are using a local BBC Micro emulator, then load it however that emulator would work, and ensure that it has a Load Address of $2000.
To run this program after getting it placed onto your BBC Micro, just run *RUN HELLO, and it should run. Use the *EX command if you run into problems to check what the Load Address is.
I will be making future posts as the unit file becomes more complete, and once it is far enough along I will also be creating a GitHub repository for it.
I should also note, that the default P65Pas compiler will automatically add a Commodore 64 style PRG file header, this is a Load Address meant for that system. I have modified and recompiled my version of P65Pas to not place this header if the file extension does not end with .prg, and you may wish to do the same. However, if you do keep this header, then you'll need to adjust both the Load Address and the Execute Address accordingly. For example:
>*LOAD MYPRG 1FFE
>*SAVE MYPRG 2000+size
This will strip the PRG header right on the BBC Micro, you could place this into an EXEC file format example. Another way is to save your program on RISC-OS, if you use BeebIt as such: MYPRG,1FFE,2000 I believe it is. This will load the binary at $1FFE, and begin execution at $2000, while retaining the PRG header.
Happy RISCing!