This appendix contains the following sections:
Introduction
Why Converting to C-51
Points of Attention
Using PL/M-51 together with C-51
This appendix describes some reasons why you should rewrite your PL/M-51 program within C-51. Then it describes how to convert an existing application written in PL/M-51 to C-51. It is noted what the difficulties are when converting to C-51. This appendix is not meant to learn the C language to a PL/M programmer.
There has to be at least one good reason to rewrite a program into another language. This section contains a number of reasons why an existing application written in the PL/M-51 language should be rewritten in C-51.
From here we will note a number of things you should take care of, when converting your PL/M-51 source to C-51. Constructions not noted here are really straightforward to convert between the two languages. You only need to have little knowledge of the PL/M-51 language and the C language to be able to convert those constructions.
Within C, the '$' character is a real character within an identifier. In PL/M-51 this character is ignored when comparing names of identifiers.
Basic data types of PL/M-51 do also exist within C-51. Note that all data types within PL/M-51 are unsigned types. Within C-51, you have to specify a variable to be unsigned, while default types are signed.
C-51 does not have a notation for binary numbers. Instead you have to use decimal, octal or hexadecimal notation.
A variable cannot be 'AT'ed at another variable within C-51. Instead you should use union variable types. Declaring a struct of eight bits on the same address as a character can be done with use of the _bitbyte type variable.
Placing a variable on an absolute address is done with the _at() attribute.
Special function registers are NOT declared using the register keyword. You can place your own special function registers using the _sfrbit and _sfrbyte data types.
'BASED' variables is in fact the same as using pointers from within C-51. Pointers to bit variables do not exist.
Procedures cannot be declared as nested procedures. Hiding the occurrence of a procedure to another source module can be done using the 'static' attribute.
Type conversions within C-51 are different than in PL/M-51. In C-51, whenever an expression contains an integer and a character, the character is always converted to an integer. I.e. an unsigned character has a high byte value of 0, a signed character will get sign extension in its high byte.
Expressions containing bit variables, together with other types of variables are allowed within C-51. The bit variable will be converted to the type required, the result of the conversion is the value 0 or 1.
The 'DO WHILE' of PL/M-51 is the same as the 'while' within C-51. Do NOT use the 'do while' construction within C-51 for this, because the test is done afterwards, the loop will always be executed at least once.
You cannot program a GOTO from one procedure to another.
Like in PL/M-51, within C-51 you cannot transfer parameters to a procedure called indirectly. The one exception is when programming in the reentrant model of C-51. Also like PL/M-51, the linker will not notice indirectly called procedures, therefore you have to specify to the linker which procedures do call each other indirectly, otherwise the linker will overlay the parameter and local space of these procedures. This results in incorrect execution behavior of the program.
It is not possible to specify a procedure to be called indirectly.
C-51 does not have the built-in procedures like PL/M-51. However, most of the procedures can easily be simulated using some macro definitions. Here the macro definitions follow, which you can use within the C-program.
#define LENGTH(x) (sizeof(x)/sizeof(x[0])) #define LAST(x) (LENGTH(x)-1) #define SIZE(x) (sizeof(x)) #define LOW(x) ((unsigned char)(x)) #define HIGH(x) ((unsigned char)((x) >> 8)) #define DOUBLE(x) ((unsigned int)(x)) #define BOOLEAN(x) ((x) & 0x01) #define EXPAND(x) ((unsigned char)(x)) #define PROPAGATE(x) ((unsigned char)(0-(x))) #define SHL(x,y) ((x) << (y)) #define SHR(x,y) ((x) >> (y)) #define DEC(x) (_da((x) -= 1))
For 'ROL' and 'ROR' you can use the built-in C-51 procedures '_rol' and '_ror'. However these can only be used on character type variables. There is no such procedure for integer type variables.
Instead of 'TESTCLEAR' you should use the built-in procedure '_testclear' within C-51.
C-51 has no alternative to the 'TIME' procedure. Also no alternatives are present to the 'SCL' and 'SCR' procedures. Because these procedures are not easily programmed within C (or they will need a lot of code), these procedures can best be written within assembly (or inline assembly within the C-program).
Note the 'DEC' macro as written above uses the inline procedure '_da()' to do the decimal adjust.
It is possible to mix C-51 code with PL/M-51 code. Thus you are able to rewrite parts of the program within C-51, while other parts remain written within PL/M-51.
One restriction has to be noticed. When linking your PL/M-51 application, normally the option OVERLAY is used. This option will overlay data of modules which do not call each other. You have to specify to the linker which modules do call each other indirectly.
When creating an application within C-51, normally the option FUNCTIONOVERLAY is used to the linker. This option will overlay data of procedures which do not call each other. Now you have to specify which procedures call each other indirectly.
Because these two overlaying mechanisms are incompatible. When mixing PL/M-51 with C-51 code you have to choose one of the overlaying mechanisms. This results in less optimal data overlaying, because data of C-51 modules will never be overlayed with data of PL/M-51 modules. Thus probably more data space will be necessary in relation to the application being completely written in one language.