📄 mc.doc
字号:
(# bytes pushed at entry of function to preserve registers etc.)
+
(Size of return address on stack (usually 2))
-- OR --
(accumulator contents) * 2
+
"stack pointer"
+
(# bytes pushed during function execution)
+
(size of all local variables in bytes)
+
(# bytes pushed at entry of function to preserve registers etc.)
+
(Size of return address on stack (usually 2))
Global variables exist at absolute addresses and may be
referenced directly by name from within assembler programs. Keep
in mind however, that MICRO-C uses only the first 15 characters of
a symbol's name. Also, many code generators will reduce the size
of names even further, often using an algorithm to compress the
name rather than simply truncating it. For this reason, it is a
good idea to avoid using global symbol names which are longer than
6 or 8 characters if they are to be referenced from within
assembly language programs.
MICRO-C Page: 24
3.3 Compiling for ROM
Assuming the code generator does not use such "nasty" things as
self modifying code, the output from the compiler is entirely
"clean", and may be placed in Read Only Memory (ROM).
The compiler places all initialized global variables in the
output file as part of the code image. When the program is stored
in ROM, those variables are also stored in ROM, and will not be
modifiable.
When the program is to be placed in ROM, you may not initialize
any variables which you intend to modify later. Those variables
must be explicitly initialized by code executed at the beginning
of the program.
Initialized variables which you do not intend to modify (such
as tables etc.) may be initialized in the declaration, and will be
permanently saved in the ROM as part of the static code image.
The processor stack pointer must be set up before any
expressions are evaluated, or any function calls are performed.
This may be performed via '#asm' statements.
All non-initialized global variables must be located in RAM.
The compiler usually outputs all such variables at the very end of
the compilation, just after dumping the literal pool. The global
variables may be moved to RAM by editing the output file, and
placing an appropriate "ORG" statement at the beginning of the
globals.
If extensive compilation for ROM is being performed, you may
want to use a version of the compiler which uses an intermediate
output file (see "PORTING THE COMPILER"). This allows a separate
code generator to be customized for ROM applications, which will
output the appropriate stack setup instructions (this can be done
in "def_module()"), and locate the global variables in RAM (this
can be done at the end of "def_literal()").
MICRO-C Page: 25
4. PORTING THE COMPILER
There are two major goals to accomplish when porting the MICRO-C
compiler to a new machine. The first is to make the compiler run in
the new environment, and the second is to make it produce code for
that environment.
These two goals do not always go hand in hand. For example, it may
be desirable to implement a CROSS COMPILER which generates code for a
different system from that on which it runs.
The usual method of porting a compiler to system A when a version
of the compiler is already running on system B, is to first create a
compiler which runs on system B, producing code for system A. This
"new" compiler may then be used to create a compiler which runs on
system A.
The compiler consists of a module "compile" which contains, the
main compiler, input scanner, regular expression parser, and symbol
table management routines. This is the "static" portion of the
compiler which does not change in different implementations.
To create a working compiler, the above module must be compiled
and linked with an "io" module and "code" module. The "io" module
performs the necessary initialization and I/O to allow the compiler
to run in a particular environment (goal #1). The "code" module
generates the assembly language output code for a particular
environment (goal #2).
The compiler uses NO system library functions, and relies on NO
system services (other than those used by the "io" and "code"
modules). This allows the compiler to be ported to virtually any
system.
All fixed compiler parameters (such as table sizes etc) are
contained in the header file "compile.h". When porting to systems
with very limited RAM (less than 64k), you may have to reduce some of
these sizes in order to get it to fit.
Two additional modules are provided with the compiler. The file
"intercg.c", may be linked into the compiler in place of the code
generator, and writes a "generic" intermediate file which contains
the pseudo operation and type tokens (See Code Generator). The file
"genasm.c", may be linked with the regular "io" and "code" routines
to produce a utility program which reads the intermediate file and
produces the assembly language code for a specific processor.
NOTE: If your system makes a distinction between TEXT and BINARY
files, the "io.c" routines must be modified for each program so that
the intermediate file will be accessed in BINARY mode. All other
files are accessed as TEXT.
MICRO-C Page: 26
Although this "split" compiling approach is slower than the usual
mode of direct assembly language production, it provides several
useful capabilities:
1) The amount of ram required to run the "separate" compiler and
genasm programs can be considerably less than required to run the
"stand alone" compiler.
2) A single parser may be used to generate code for several target
systems, by simply running a different version of the "genasm"
utility, which is customized for each target.
3) Use of the intermediate file allows distribution of "portable"
programs which may be processed by "genasm" for different targets
WITHOUT distribution of the source code.
4) A program may be written which processes this intermediate file,
and "optimizes" the code. Additional "pseudo operation" codes may
be added to the output file if the target processor is capable of
operations which the more "generic" MICRO-C output does not
utilize.
4.1 The "io" module
The "io" module required by the compiler must contain the
following function definitions:
The function "main()" is called by the operating system when
the MICRO-C compiler is executed. It is responsable for parsing
any parmeters and command qualifiers, opening the input and output
files, performing any other initializations that might be
required, and then invoking the function "compile()" with no
arguments. The "compile" function is internal to the "compile.c"
module, and will never return. For UNIX and other systems which
support I/O redirection, "stdin" and "stdout" are often used for
the input and output files.
The function "exit(rc)" is called when the compiler has
finished all processing and wishes to terminate. The value "rc" is
a return code: 0 = Success, program compiled without error, -1 =
Compile was aborted due to severe errors, n = Compile finished,
but had 'n' errors.
The function "put_chr(chr, flag)" is passed a character to
output, as well as a flag. The flag will always be zero when the
character is being sent to the console terminal, or non-zero when
the character is to be written to the output file.
The function "put_str(*ptr, flag)" is passed a pointer to a
zero terminated string, which is to be written to the console or
output file as determined by "flag".
The function "put_num(number, flag)" is passed a 16 bit number,
which is to be written in printable form to the console or output
file as determined by "flag".
MICRO-C Page: 27
4.1.1 Compiler only routines
The following I/O routines are required by the compiler, but
not by the "genasm" program.
The function "get_lin(*ptr)" is passed a pointer to a
character array, and should read a single line from the
currently open input file into that array. The manifest
definition "LINE_SIZE", found in "compile.h" may be used to
determine the maximum line length acceptable to the compiler.
Return of a non-zero value indicates the end of file condition.
The function "f_open(*ptr)" is passed a pointer to a
filename. The new file should be opened, and if successful, the
old input file should remain open and be "stacked", so that it
can be later returned to. If the file was opened successfully,
a non-zero value should be returned. A zero value indicates to
the compiler that the file could not be opened.
The function "f_close()" is responsible for closing the
currently open input file, and returning to the "stacked"
previously open one. It receives no parameters. Note: multiple
"opens" may be stacked - see the manifest definition of
"INCL_DEPTH" in the "compile.h" file.
4.1.2 Genasm only routines
The following I/O routine is required by the "genasm"
program, but not by the compiler.
The function "get_char()" must return a single character
from the input file as a 16 bit number with a positive value
between 0 and 255. A '-1' is returned for the end of file
condition.
4.1.3 Notes on I/O module
1) It is the responsibility of the "put" routines to translate
the NEWLINE '\n' (0x0a) character into whatever line
termination character(s) are required by the target
operating system.
2) If unix "stdin" and "stdout" are not used, it is the
responsibility of "main" to display appropriate error
messages if the input or output files could not be opened.
Refer to the sample "io" modules distributed with the
compiler.
MICRO-C Page: 28
4.2 The "code" module
In order to insure that MICRO-C is portable to virtually any
environment, the compiler makes few assumptions about the
processor or system software of the target system. The "code"
module is relied on to produce all machine instruction and
assembler directives written to the output file.
The only two real "assumptions" made about the target processor
are:
1) It is assumed that the target processor has an "accumulator"
register in which all math operations are performed, and that
the lower 8 bits of this register may be accessed
independantly.
2) It is assumed that the target processor has one "index"
register which may be loaded with a 16 bit value, and that
memory references may be made indirectly through this register.
If the target processor does not support the above features, it
may be possible to write a code generator for it using some other
features of the processor.
For example, if an "index" register does not exist, it may
often be implemented using two bytes of reserved memory.
The code generation module required by the compiler must
contain the following function definitions:
The function "do_asm(*ptr)" is passed a pointer to a character
string, which it should write to the output file EXACTLY as
passed, followed by a '\n' NEWLINE character. This function is
used by the "#asm" directive to write directly to the output file.
The function "def_module()" is called at the beginning of
compilation, before any other code generator functions are called.
It is used to output any pre-amble needed by the assembler.
The function "end_module()" is called at the very end of
compilation, and is the last code generator function called. It is
used to output any post-amble needed by the assembler.
The function "def_static(symbol)" is passed am index into the
compiler symbol tables for a global variable, which is about to be
initialized as static storage. The call to this function will be
immediately followed by a call to "init_static" or "end_static".
The "init_static(token, value, word)" function is passed a
token and value, with which it should initialize a single element
of static storag
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -