Some simple extensions to a Pascal to 8051 Cross Compiler

Derek Kennedy (Sherwood Intl. now SunGard), April 1998
Last Update 6th May 2002
e-mail: minerva9@hotmail.com

Who might be interested in this stuff?

1. If you experiment with the Intel 8051 series of microcontrollers and want to avoid having to write all of your code in 8051 assembly language, this may be of interest.

2. If point 1. applies and you prefer writing Pascal to writing C, this really should be of interest.

This page describes some enhancements which I made to an existing Pascal to 8051 cross-compiler.
The compiler supports bit, byte, word, integer and real variables. Enumeration types, records, functions and procedures are catered for.
Variables may be declared as residing at a user defined address. All of the standard Pascal flow control structures are supported (repeat..until, while do, case, if then else, labels). Sadly, char & strings were not supported.

This freeware Pascal to 8051 cross compiler is called the ElProg Pascal51 compiler .... elprog51.zip ... (some folk have had trouble with downloading this - it's almost 500Kb. Drop me an email if you can't download & I'll email it to you).

If you want to download my compiler enhancer right now, use this link .... prepro.zip

As there appears to be no source code available for the Pascal51 compiler, it is difficult to add new features to the system (if anybody knows where the source can be downloaded pls. let me know!). Overall, the code generated by this compiler is not very �tight�. However, for those of us who don�t like to work with C, it is a worthwhile tool.

I missed being able to work with strings and also wanted to be able to mix 8051 assembler with Pascal51 code, so decided to look at how these features might be added.

The approach taken was to write a pre-processor program which takes a '.p80' textual source program (which supports some new features) and outputs a .p51 source file which will compile with the existing Pascal51 compiler. A post-processor was also needed to modify the generated .a51 assembler source file, the modified assembler file is given a '.a80' file extension.

The new features described here are :

String support

A new type of global declaration block is supported.

e.g.

Strings
Start at $4000;
mystring := 'abcde';
mystring2 := 'eric';

This block must appear just after the program global var declarations.
Only one such block is allowed (so strings are �global�).
The block ends with a blank line.

Note that the start address should be chosen to place the generated strings in a free area of ROM.
When the pre-compiler finds a string, two actions are taken.

First, a declaration is generated -

e.g.
mystring at $4000 : string; {�abcde�}
mystring at $4006 : string; {�eric�}

then a .asi (ASsembler Include) file is written to hold the necessary definitions for the strings.
This file is merged with the .a51 file (to produce a .a80 file) later on.

e.g.
org $4000
db 5
ds �abcde�
db 4
ds �eric�

Notice that the strings are of type �string�, which needs to be declared thus :

type
string =
 record
   len : byte;
   chars : array[1..2] of byte;
 end;

As you can see, each string starts with a byte which holds the length of the whole string (like Borland Turbo Pascal), strings have a maximum length of 255 bytes. The actual string is held in the array of chars. Since the upper bound of the chars array is not checked by the compiler, it does not really matter which upper bound value you use.When using strings as parametes to procedures & functions you will almost always want to declare these as 'var' parameters.

If you want to have RAM based strings which can be manipulated at runtime,
just declare your RAM based string :

var
  ramstr at $2000 : string;
 

and if necessary, initialise it using a procedure such as :

procedure InitString(var ramStr : string; var romStr : string);
{note the use of var parameters to ensure the passing of addresses}
var
  ii : byte;
begin
  ramStr.len := romStr.len;
  for ii := 1 to romStr.len do ramStr.chars[ii] := romStr.chars[ii];
end;

 

Some sample procedures which use these strings are :

procedure Wait_TX_Ready;
begin Repeat Until TI=1; end; procedure WriteCh(ch:byte); {write a character to the serial port} begin TI := 0; SBUF := ch; Wait_TX_Ready; end; procedure WriteString(var astring : string); {write out a string to the serial port} var ii: byte; {Note : Using a global �internal byte� as a loop index is much more efficient}
begin
  with astring do
   for ii := 1 to len do WriteCh(chars[ii]);
end;
function Pos(var aString:string; TargetChar:byte):byte;
{returns the index at which a character is located within a string
   or 0 if the char is not found in the string}
var
   ii : byte;
   found : boolean;
begin
  Pos := 0;
  found := false;
  ii := 1;
while (ii <= aString.len) and (not found) do begin if aString.chars[ii] = TargetChar then begin Pos := ii; found := true; end;
ii := ii + 1; end; end;
procedure LeftString(var aRamString : string; var aString : string; CharCount:byte);
{set aRamString to the leftmost CharCount characters of aString}
var
  ii, jj : byte;
begin
  jj := CharCount;
  if jj > aString.len then jj := aString.len;
  aRamString.len := jj;
  for ii := 1 to jj do aRamString.chars[ii] := aString.chars[ii];
end; 
procedure RightString(var aRamString : string, var aString : string, CharCount:byte);
{set aRamString to the rightmost CharCount characters of aString}
var
  ii, jj : integer;
begin
  jj := CharCount;
  if jj > aString.len then jj := aString.len;
ii := aString.len; aRamString.len := jj; while jj > 0 do begin aRamString.chars[jj] := aString.chars[ii]; jj := jj-1; ii := ii-1; end;
end;

 

Single Character support

This is basically a way of avoiding having to calculate the hex value of single characters which are held as byte values.

Instead of writing

case ch of
   $41: WriteString(messageA);
   $42: WriteString(messageB);

�..

you can write

case ch of
   'A' : WriteString(messageA);
   'B' : WriteString(messageB);

�..

You can use this technique anywhere a single byte constant value is expected.
The pre-compiler simply performs a string replacement.

 

Inline Assembler Functions

This allows you to write asm code directly into your Pascal source file.
The flag {*Assembler} is required.

The procedure implemented in asm code is visible to the Pascal compiler.
Note that it is the responsibility of the user to ensure that any registers used are suitably restored.

Procedure mystore; {*Assembler};
begin
   mov a,#$66
   mov dpl,#$45
   mov dph,#$60
   movex @dptr,a
   ret
end;

Ensure that instructions don�t start in column 1 of the source line (or they will look like labels to the assembler).
Note that labels can be used - just ensure that the label name is unique and that the label starts in column 1.

External assembler functions

This feature is handy when you have an existing assembler routine which you wish to call from Pascal, but don�t want to include the assembler code inline.

procedure ExtTest; {*External}
begin
end;

The pre-compiler builds a list of all of the procedures which are implemented as �External�.
This list is used to scan the generated .a51 file and remove the stubs of assembler which the compiler produces. The modified output is written to the .a80 file.

 

How to use the pre-preprocessor program

First, get a copy of the Pascal51 compiler (see above) & experiment with it. It actually works very well without any of the extensions which are discussed here.

Next, download my program & sample files for the pre-processor. prepro.zip

When you run the pre-processor program for the 1st time, you should double-click on the compiler and assembler label text to setup your environment & let my program know where to find the Pascal51 compiler & your asm51 assembler.

Next, create a new directory for your new project. Write your Pascal project source file & save it with a .p80 file extension. e.g. test.p80

Run the Pascal51_preprocess.exe, double click on the Project label & select the test.p80 file.

Press the �Pre-Process� button. This should scan the test.p80 file & produce a test.p51 file.

Now Press the �Compile� button. This should run the Pascal51 compiler and generate test.a51.

Now click on the �Post-process� button to generate a �test.a80� file.

Then click on the 'Assemble' button to assemble the test.a80 file.

The 'Link etc.' button runs a batch file (<projectname>.bat) which should reside in the project directory.
This is handy for running a linker & hex to binary program and anything else which you use. You need to create the .bat file yourself.

The 'View Listing' buttons allow you to view the listing files & find any errors � you can use Windows file association to associate your favourite code editor with the .a51 and .lst file extensions.

Pressing the �Edit Project� button allows you to edit the project (.p80) source file.

The pre/post processor tool is written in Borland�s Delphi. It should run OK on Windows �95 or NT 4. It takes a very simplistic approach to parsing the input files - if you don�t get the syntax correct, the program might hangup without warning (so, keep backups of your source files). If you want the Delphi source code, use this link ... delphisrc.zip

 

(Interesting) things to note about the ElProg Pascal51 compiler - plus some bugs

The compiler always seems to use the accumulator to hold the return value of functions whose return type is �byte�.

The compiler was written before 'long' filenames were supported. It's best to avoid using long filenames for your working files.

Watch out! The compiler generates incorrect code for functions whose return type is 'word' or 'integer'. Thanks to Mike Conboy for bringing this to my attention. I might eventually fix up my assembler post procesor to sort this problem. Meanwhile use this link for more details of this, and other bugs - mostly spotted & reported by Laurie Tunnicliffe ... various bugs.

�For� loops can use bytes, words and enumerated types as loop counters, but can�t use integers.

Functions can�t return a user defined �type�.

Variables of type 'bit' can be set to 1 or 0 by assigning the variable to 'true' or 'false' respectively.
Variables of type 'boolean' are held as a single byte and can be set to 1 or 0 by assigning the variable to 'true' or 'false' respectively. Note however, that bit and boolean variables are not assignment compatible.

There is an undocumented 'xor' operator.

If you would like to review some sample Pascal51 source code, use this link ... demo51.zip
Thanks to Laurie Tunnicliffe for this sample code.

Sadly, the 8051 code generated by Pascal51 is not very efficient. However, it is free!

Futures

I hope to made a (very simplistic) attempt to optimise some of the code generated by the compiler. Certain jump and call codes could be optimised. (e.g. where possible, some LJMPs could be converted to SJMPs or AJMPs).

If you use this package, please drop me an e-mail & let me know how you get on.

 

Other Stuff

The original documentation for the Pascal51 compiler mentions a Mr. Vladimir Gladyshev, working out of Moscow, Russia. I reckon that he deserves a mention here. Update!! Today, 10th March 2000, I received an email from Vladimir Gladyshev! He is now working as a computer systems architect in Russia. The good news is that he still has the source code for the Pascal51 compiler. Vladimir seems pleased that some folk are still using Pascal51. I've asked if he might consider posting the source code, but suspect that he is not keen to reveal his sources.

Highly recommended! An excellent, low cost, Pascal to 805x development system. This features an integrated development environment, compiler, assembler and simulator. Code can be developed to be compatible with Borland Delphi. Code generation is very tight and in a different league from ElProg Pascal - the demo system now allows code sizes up to 1Kb - yes, this compiler can pack a non-trivial program into this small space! Another (longer established) version supports Z80/Z180. I use this compiler for all my 8051 work. Recently added is an AVR compiler. More details (and demo 8052 & Z80 system downloads) at http://users.iafrica.com/r/ra/rainier

If you are looking for a good 8051 simulator, try http://www.vaultbbs.com/sim8052. there are also good 8051 tutorials at this site.

I've recently found a long-standing (since 1984) Pascal cross-compiler which targets to 680x0, Z80 and 8051. Known as the MXPascal Multi-Target X-Compiler, details and a download can be found at http://www.pds.com.au/mxpascal/. I hope to have a closer look at this. If I do, I will report on my findings here. If this link is broken, email me for more info.

If you have lots of money to spend & want to try yet another Pascal to 8051 family toolset, look at http://www.ksc-softsys.com.

The NoICE tool is a superb remote debugger for the 8051 (and various other 8-bit micros). It supports source level debugging and assembly/disassembly as well as memory editing and breakpoints (without any hardware support) & loads of other features. There is now a Windows version of this product. I use it with the NoROM EPROM emulator & it works very well (Note @ Feb 2002: sorry to say that the NoROM unit is no longer commercially available). More details and a demo version available at http://www.noicedebugger.com

A good site for 8051, PIC and AVR parts and projects can be found at http://www.dontronics.com
There are also details of many software development tools and simmstick based solutions.

Not much to do with Pascal ... but I spent ages trying to find datasheets for an Epson LCD module. A kind guy (Jan Eric) in Germany scanned his set of datasheets & emailed me approx 9Mb of JPEG files. The device is an EA-20017AR - I bought a few of these from my favourite surplus electronics supplier Greenweld Electronics http://www.greenweld.co.uk. You can download the (756Kb) .pdf which I created with this link ... lcdinfo.pdf

Did some work on a handheld terminal unit. This was made by (the now defunct) Victor Micronic company. Writeup of the work can be read at http://www.oocities.org/micronic99.geo/

Had a lot of good fun experimenting with a small AVR development board. Details online here.

Spent some time trying to find details of a 6502 compatible microcontroller, the Mitsubishi M50747. Eventually found a guy who had a databook. Will put some scans at http:/www.oocities.org/dk6502/

Some fine, inexpensive, electronics parts can be found at UK based supplier N. R. Bardwell http://www.bardwells.co.uk

A comprehensive list of free compilers can be found at http://www.thefreecountry.com/developercity/index.html

A great Wiki that documents many cool things to do with a Cybiko http://www.dbzoo.com/wiki/cybiko/cybiko

Cool photos, refreshed daily http://anthonyfelton.com/photodiary2/

 


This page hosted by Get your own Free Home Page