Manual PDF
Manual PDF
HI-TECH Software.
Copyright (C) 2007 HI-TECH Software.
All Rights Reserved. Printed in Australia.
Produced on: March 19, 2007
HI-TECH Software Pty. Ltd.
ACN 002 724 549
45 Colebard Street West
Acacia Ridge QLD 4110
Australia
email: [email protected]
web: http://www.htsoft.com
ftp: ftp://www.htsoft.com
iv
Contents
Table of Contents v
List of Tables xv
1 Introduction 1
1.1 Typographic conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
v
CONTENTS CONTENTS
vi
CONTENTS CONTENTS
2.4.52 --TIME: Report time taken for each phase of build process . . . . . . . . . . 26
2.4.53 --VER: Display The Compilers Version Information . . . . . . . . . . . . . 26
2.4.54 --WARN=level: Set Warning Level . . . . . . . . . . . . . . . . . . . . . . 27
2.4.55 --WARNFORMAT=format: Set Warning Message Format . . . . . . . . . . . 27
3 C Language Features 29
3.1 ANSI Standard Issues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.1.1 Implementation-defined behaviour . . . . . . . . . . . . . . . . . . . . . . . 29
3.2 Processor-related Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2.1 Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
3.2.2 Configuration Fuses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.2.3 ID Locations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.2.4 Bit Instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
3.2.5 EEPROM Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
3.2.5.1 The eeprom variable qualifier . . . . . . . . . . . . . . . . . . . . 31
3.2.5.2 The __EEPROM_DATA() macro . . . . . . . . . . . . . . . . . . 32
3.2.5.3 EEPROM Access Functions . . . . . . . . . . . . . . . . . . . . . 32
3.2.5.4 EEPROM Access Macros . . . . . . . . . . . . . . . . . . . . . . 33
3.2.6 Flash Runtime Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3.2.6.1 Flash Access Macros . . . . . . . . . . . . . . . . . . . . . . . . 34
3.2.6.2 Flash Access Functions . . . . . . . . . . . . . . . . . . . . . . . 34
3.2.7 Baseline PIC special instructions . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2.7.1 The OPTION instruction . . . . . . . . . . . . . . . . . . . . . . 35
3.2.7.2 The TRIS instructions . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2.7.3 Calibration Space . . . . . . . . . . . . . . . . . . . . . . . . . . 35
3.2.7.4 Oscillator calibration constants . . . . . . . . . . . . . . . . . . . 36
3.3 Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.3.1 Source Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
3.3.2 Symbol Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.3.3 Standard Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
3.3.4 Runtime startup Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
3.3.4.1 Initialization of Data psects . . . . . . . . . . . . . . . . . . . . . 38
3.3.4.2 Clearing the Bss Psects . . . . . . . . . . . . . . . . . . . . . . . 39
3.3.4.3 Linking in the C Libraries . . . . . . . . . . . . . . . . . . . . . . 40
3.3.4.4 The powerup Routine . . . . . . . . . . . . . . . . . . . . . . . . 40
3.4 Supported Data Types and Variables . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3.4.1 Radix Specifiers and Constants . . . . . . . . . . . . . . . . . . . . . . . . . 41
3.4.2 Bit Data Types and Variables . . . . . . . . . . . . . . . . . . . . . . . . . . 42
3.4.3 8-Bit Integer Data Types and Variables . . . . . . . . . . . . . . . . . . . . 43
vii
CONTENTS CONTENTS
viii
CONTENTS CONTENTS
4 Macro Assembler 79
4.1 Assembler Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
4.2 Assembler Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
4.3 HI-TECH C Assembly Language . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.3.1 Statement Formats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
4.3.2 Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.3.2.1 Delimiters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.3.2.2 Special Characters . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.3.3 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.3.3.1 Special Comment Strings . . . . . . . . . . . . . . . . . . . . . . 83
4.3.4 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
ix
CONTENTS CONTENTS
x
CONTENTS CONTENTS
xi
CONTENTS CONTENTS
xii
CONTENTS CONTENTS
Index 407
xiii
CONTENTS CONTENTS
xiv
List of Tables
xv
LIST OF TABLES LIST OF TABLES
xvi
Chapter 1
Introduction
1
Typographic conventions Introduction
2
Chapter 2
PICC is the driver invoked from the command line to compile and/or link C programs. PICC has the
following basic command format:
It is conventional to supply the options (identified by a leading dash - or double dash ) before
the filenames.
The options are discussed below. The files may be a mixture of source files (C or assembler)
and object files. The order of the files is not important, except that it will affect the order in which
code or data appears in memory. Libraries are a list of library names, or -L options, see Section
2.4.6. Source files, object files and library files are distinguished by PICC solely by the file type or
extension. Recognized file types are listed in Table 2.1. This means, for example, that an assembler
file must always have a .as extension (alphabetic case is not important).
PICC will check each file argument and perform appropriate actions. C files will be compiled;
assembler files will be assembled. At the end, unless suppressed by one of the options discussed later,
3
Long Command Lines PICC Command-line Driver
all object files resulting from compilation or assembly, or those listed explicitly on the command line,
will be linked together with the standard runtime code and libraries and any user-specified libraries.
Functions in libraries will be linked into the resulting output file only if referenced in the source
code.
Invoking PICC with only object files specified as the file arguments (i.e. no source files) will
mean only the link stage is performed. It is typical in Makefiles to use PICC with a -C option to
compile several source files to object files, then to create the final program by invoking PICC again
with only the generated object files and appropriate libraries (and appropriate options). If a .lib
output file type is selected, the object files will be stored in a library instead of going through to the
final link.
When a HEX file is given on the command line, PICC will invoke the HEXMATE utility and
will merge the named hex file with the hex file currently being generated. This feature can be useful
when, for example, a single hex file is desired which contains a bootloader and application program.
PICC @xyz.cmd
4
PICC Command-line Driver PICC Compiler Options
5
PICC Compiler Options PICC Command-line Driver
6
PICC Command-line Driver PICC Compiler Options
All single letter options are identified by a leading dash character, -, e.g. -C. Some single letter
options specify an additional data field which follows the option name immediately and without any
whitespace, e.g. -Ddebug.
Multi-letter, or word, options have two leading dash characters, e.g. --ASMLIST. (Because of
the double dash, you can determine that the option --ASMLIST, for example, is not a -A option
followed by the argument SMLIST.) Some of these options define suboptions which typically appear
as a comma-separated list following an equal character, =, e.g. --OUTPUT=intel,cof. The exact
format of the options varies and are described in detail in the following sections.
Some commonly used suboptions include default, which represent the default specification
that would be used if this option was absent altogether; all, which indicates that all the available
suboptions should be enabled as if they had each been listed; and none, which indicates that all
suboptions should be disabled. Some suboptions may be prefixed with a plus character, +, to indicate
that they are in addition to the other suboptions present, or a minus character -, to indicate that
they should be excluded. In the following sections, angle brackets, < >, are used to indicate optional
parts of the command.
The compiler will produce three object files main.obj, module1.obj and asmcode.obj which
could then be linked to produce an Intel HEX file using the command:
7
PICC Compiler Options PICC Command-line Driver
#define macro 1
placed at the top of each module compiled using this option, or -Dmacro=text which is equivalent
to:
will compile test.c with macros defined exactly as if the C source code had included the directives:
#define debug 1
#define buffers 10
The -E option also allows errors to be appended to an existing file by specifying an addition charac-
ter, +, at the start of the error filename, for example:
If you wish to compile several files and combine all of the errors generated into a single text file, use
the -E option to create the file then use -E+ when compiling all the other source files. For example,
to compile a number of files with all errors combined into a file called project.err, you could use
the -E option as follows:
8
PICC Command-line Driver PICC Compiler Options
Section 2.4.26.1 has more information regarding this option as well as an overview of the messaging
system and other related driver options.
The --IDE option, see Section 2.4.31 will typically enable the -G option.
will search the directories c:\include and d:\myapp\include for any header files included into
the source code, then search the default include directory (the include directory where the compiler
was installed).
This option has no effect for files that are included into assembly source using the INCLUDE
directive. See Section 4.3.9.3.
9
PICC Compiler Options PICC Command-line Driver
Take care with command-line options. The linker cannot interpret driver options; sim-
ilarly the command-line driver cannot interpret linker options. In most situations, it is
always the command-line driver, PICC, that is being executed. If you need to add al-
ternate settings in the linker tab in an MPLAB Build options... dialogue, these are
the driver options (not linker options), but which are used by the driver to generate the
appropriate linker options during the linking process.
The -L option is especially useful when linking code which contains non-standard program sections
(or psects), as may be the case if the program contains C code which makes use of the #pragma
psect directive or assembly code which contains user-defined psects. See Section 3.12.3.5 for more
information. Without this -L option, it would be necessary to invoke the linker manually to allow
the linker options to be adjusted.
10
PICC Command-line Driver PICC Compiler Options
One commonly used linker option is -N, which sorts the symbol table in the map file by address,
rather than by name. This would be passed to PICC as the option -L-N.
This option can also be used to replace default linker options: If the string starting from the first
character after the -L up to the first = character matches first part of a default linker option, then that
default linker option is replaced by the option specified by the -L.
T UTRIAL
If there are no characters following the first = character in the -L option, then any matching default
linker option will be deleted. For example: -L-pfirst= will remove any default linker option that
begins with the string -pfirst=. No warning is generated if such a default linker option cannot be
found.
T UTRIAL
A DDING AND DELETING DEFAULT LINKER OPTIONS The default linker options for
for a project links several psects in the following fashion.
-pone=600h,two,three
which links one at 600h, then follows this with two, then three. It has been decided
that the psects should be linked so that one follows two, which follows three, and
that the highest address of one should be located at 5FFh. This new arragement can be
specified issuing the following driver option:
-L-pthree=-600h,two,one
which creates passes the required linker options to the linker. The existing default option
11
PICC Compiler Options PICC Command-line Driver
The default option that you are deleting or replacing must contain an equal character.
12
PICC Command-line Driver PICC Compiler Options
13
PICC Compiler Options PICC Command-line Driver
14
PICC Command-line Driver PICC Compiler Options
15
PICC Compiler Options PICC Command-line Driver
indicating that the error number 192 occurred in file x.c at line 4, offset 9 characters into the state-
ment. The second numeric value - the column number - is relative to the left-most non-space charac-
ter on the source line. If an extra space or tab character were inserted at the start of the source line,
the compiler would still report an error at line 4, column 9.
16
PICC Command-line Driver PICC Compiler Options
ERROR: parser: file x.c; line 4; column 6; (192) undefined identifier: xFF
Remember that if these environment variables are set in a batch file, you must prepend the specifiers
with an additional percent character to stop the specifiers being interpreted immediately by DOS,
e.g. the filename specifier would become %%f.
17
PICC Compiler Options PICC Command-line Driver
byte order.
If the fill value is only to be applied to a restricted address range, the restriction can be specified by
using --FILL=opcode@start_address-end_address. This facility also makes it possible
to allow a fill value to be applied to address ranges outside of program memory (as addressed in
the hex file), for example EEPROM. If an address restriction is not specified, the fill value will be
applied to all of the devices program memory. Optionally the ,data flag can be added to this option
to specify to only use this fill value to pad out data records within this address range to the default
length.
PICC --help=warn
This will display more detailed information about the --WARN option.
18
PICC Command-line Driver PICC Compiler Options
19
PICC Compiler Options PICC Command-line Driver
20
PICC Command-line Driver PICC Compiler Options
specifying an output file format list containing, e.g. lib or all will over-ride the non-library output
types, and only the library file will be created.
#include <stdio.h>
add(arg1, arg2)
21
PICC Compiler Options PICC Command-line Driver
int * arg1;
int * arg2;
{
return *arg1 + *arg2;
}
22
PICC Command-line Driver PICC Compiler Options
--RAM=default,+100-1ff
for example. To only use an external range and ignore any on-chip memory, use:
--RAM=0-ff
This option may also be used to reserve memory ranges already defined as on-chip memory in the
chipinfo file. To do this supply a range prefixed with a minus character, -, for example:
--RAM=default,-100-103
will use all the defined on-chip memory, but not use the addresses in the range from 100h to 103h
for allocation of RAM objects.
--ROM=default,+100-2ff
for example. To only use an external range and ignore any on-chip memory, use:
--ROM=100-2ff
This option may also be used to reserve memory ranges already defined as on-chip memory in the
chip configuration file. To do this supply a range prefixed with a minus character, -, for example:
--ROM=default,-100-1ff
will use all the defined on-chip memory, but not use the addresses in the range from 100h to 1ffh for
allocation of ROM objects.
23
PICC Compiler Options PICC Command-line Driver
24
PICC Command-line Driver PICC Compiler Options
25
PICC Compiler Options PICC Command-line Driver
not desirable as almost all applications are critical to the success of the build process. Disabling a
critical application will result in catastrophic failure. However it is permissible to skip a non-critical
application such as clist or hexmate if the final results are not reliant on their function.
2.4.52 --TIME: Report time taken for each phase of build process
Adding --TIME when building generate a summary which shows how much time each stage of the
build process took to complete.
26
PICC Command-line Driver PICC Compiler Options
27
PICC Compiler Options PICC Command-line Driver
28
Chapter 3
C Language Features
HI-TECH PICC supports a number of special features and extensions to the C language which
are designed to ease the task of producing ROM-based applications. This chapter documents the
compiler options and special language features which are specific to these devices.
3.2.1 Stack
The stack on PIC processors is limited in depth and cannot be manipulated directly. It is left up to
the programmer to ensure that the maximum stack dept is not exceeded. A call graph is provided by
the linker when generating a MAP file. This will indicate the stack levels at each function call.
29
Processor-related Features C Language Features
3.2.3 ID Locations
Some PIC devices have location outside the addressable memory area that can be used for storing
program information, such as an ID number. The __IDLOC macro may be used to place data into
these locations. The macro is used in a manner similar to:
#include <htc.h>
__IDLOC(x);
where x is a list of nibbles which are to be positioned into the ID locations. Only the lower four
bits of each ID location is programmed, so the following:
__IDLOC(15F0);
will attempt to fill ID locations which the values: 1, 5, F, 0. The base address of the ID locations
is specified by the idloc psect which will be automatically assigned as appropriate address based on
the type of processor selected. Some devices will permit programming up to seven bits within each
ID location. To program the full seven bits, the regular __IDLOC macro is not suitable. For this
situation the __IDLOC7(a,b,c,d) macro is available. The parameters a to d are a comma separated
list of values. The values can be entered as either decimal or hexadecimal format such as:
__IDLOC7(0x7f,1,70,0x5a);
It is not appropriate to use the __IDLOC7 macro on a device that does not permit seven bit
programming of ID locations.
30
C Language Features Processor-related Features
This will create an eeprom variable which is predefined with the value 0x1234. This would be
equivalent to using the __EEPROM_DATA macro with 0x12 and 0x34 as two of its parameters.
This variable may be read or written to at runtime:
serial_number = 0xAA55;
The compiler will produce the appropriate code to access EEPROM and is particularly efficient
when accessing multi-byte variables. Unlike conventional RAM variables, if an initialized EEPROM
variable is modified during runtime, next time the processor is reset the variable will contain the
updated value, not the original initialization value. So in the above example, the first time the
processor starts up, serial_number will contain 0x1234, however after this is changed to 0xAA55,
serial_number will never revert back to the original 0x1234 value, even after reset, unless explicitly
programmed to do so.
Note the compiler only support basic assignment operations on eeprom qualified objects. If
a complex expression involving an eeprom qualified object is used, the compiler will generated a
31
Processor-related Features C Language Features
cant generate code error. In this case you should try and simplify the expression, perhaps by
using a temporary variable.
As the location of eeprom qualified variables is managed by the toolsuite, it is not nec-
essary to access EEPROM by specific address, in fact this should be avoided. For this
reason it is not recommended to combine the use of eeprom qualified variables with any
other EEPROM access method.
#include <htc.h>
__EEPROM_DATA(0, 1, 2, 3, 4, 5, 6, 7);
The macro accepts eight parameters, being eight data values. Each value should be a byte in size.
Unused values should be specified as a parameter of zero. The macro may be called multiple times
to define the required amount of EEPROM data. It is recommended that the macro be placed outside
any function definitions.
The macro defines, and places the data within, a psect called eeprom_data. This psect is posi-
tioned by a linker option in the usual way.
This macro is not used to write to EEPROM locations during run-time, it is to be used for pre-
loading EEPROM contents at program time only. Using eeprom qualified variables provides a more
flexible approach to pre-loading of EEPROM as they do not require initialization of eight bytes at a
time and they also come with built-in runtime access as discussed in section 3.2.5.1.
#include <htc.h>
void eetest(void){
unsigned char value = 1;
32
C Language Features Processor-related Features
These functions test and wait for any concurrent writes to EEPROM to conclude before performing
their required operation. The eeprom_write() function will initiate the process of writing to EEP-
ROM and this process will not have completed by the time that eeprom_write() returns. The new data
written to EEPROM will become valid approximately four milliseconds later. In the above example,
the new value will not yet be ready at the time when eeprom_read() is called, however because this
function waits for any concurrent writes to complete before initiating the read, the correct value will
be read.
It may also be convenient to use the preprocessor symbol, _EEPROMSIZE in conjunction
with some of these access methods. This symbol defines the number of EEPROM bytes
available for the selected chip.
You cannot afford the extra level of stack depth required to make a function call
You cannot afford the added code overhead to pass parameters and perform a call/return
You cannot afford the added processor cycles to execute the function call overhead
Be aware that if a program contains multiple instances of either macro, any code space saving will
be negated as the full content of the macro is now duplicated in code space.
In the case of EEPROM_READ(), there is another very important detail to note. Unlike eep-
rom_read(), this macro does not wait for any concurrent EEPROM writes to complete before pro-
ceeding to select and read EEPROM. Had the previous example used the EEPROM_READ() macro
in place of eeprom_read() the operation would have failed. If it cannot be guarenteed that all writes
to EEPROM have completed at the time of calling EEPROM_READ(), the appropriate flag should
be polled prior to executing EEPROM_READ(). For example:
33
Processor-related Features C Language Features
#include <htc.h>
void eetest(void){
unsigned char value = 1;
unsigned char address = 0;
EEPROM_WRITE(address,value); // Initiate writing value to address
while(WR) continue; // wait for end-of-write before EEPROM_READ
value = EEPROM_READ(address); // read from EEPROM at address
}
34
C Language Features Processor-related Features
35
Files C Language Features
Some PIC devices come with an oscillator calibration constant which is pre-programmed into the
devices program memory. This constant can be read and written to the OSCCAL register to calibrate
the internal RC oscillator. On some baseline PIC devices the calibration constant is stored as a movlw
instruction at the top of program memory, e.g. the 12C50X and 16C505 parts. On reset the program
counter is made to point to this instruction and it is executed first before the program counter wraps
around to 0x0000 which is the effective reset vector for the device. The PICC compiler default
startup routine will automatically include code to load the OSCCAL register with the value contained
in the W register after reset on such devices. No other code is required by the programmer.
For other chips, such as 12C67X chips, the oscillator constant is also stored at the top of program
memory, but as a retlw instruction. The compilers startup code will automatically generate code to
retrieve this value and do the configuration. This feature can be turned off via the RUNTIME
option.
At runtime this value may be read using the macro _READ_OSCCAL_DATA(). To be able to use this
macro, make sure that <htc.h> is included into the relevant modules of your program. This macro
returns the calibration constant which can then be stored into the OSCCAL register, as follows:
OSCCAL = _READ_OSCCAL_DATA();
The location which stores the calibration constant is never code protected and will be lost if you
reprogram the device. Thus, if you are using a windowed or flash device, the calibration constant
must be saved from the last ROM location before it is erased. The constant must then be repro-
grammed at the same location along with the new program and data.
If you are using an in-circuit emulator (ICE), the location used by the calibration retlw in-
struction may not be programmed and would be executed as some other instruction. Calling the
_READ_OSCCAL_DATA() macro will not work and will almost certainly not return correctly. If you
wish to test code that includes this macro on an ICE, you will have to program a retlw instruction at
the appropriate location in program memory. Remember to remove this instruction when program-
ming the actual part so you do not destroy the calibration value.
3.3 Files
3.3.1 Source Files
The extension used with source files is important as it is used by the compiler drivers to determine
their content. Source files containing C code should have the extension .c, assembler files should
have extensions of .as, relocatable object files require the .obj extension, and library files should
be named with a .lib extension.
36
C Language Features Files
37
Files C Language Features
One job of the runtime startup code is ensure that any initialized variables contain their initial value
before the program begins execution. Initialized variables are those which are not auto objects and
38
C Language Features Files
which are assigned an initial value in their definition, for example input in the following example.
int input = 88;
void main(void) { ...
Since auto objects are dynamically created, they require code to be positioned in the function
in which they are defined to perform their initialization. It is also possible that their initial value
changes on each instance of the function. As a result, initialized auto objects do not use the data
psects.
Such initialized objects have two components and are placed within the data psects.
The actual initial values are placed in a psect called idata. The other component is where the
variables will reside, and be accessed, at runtime. Space is reserved for the runtime location of
initialized variables in a psect called rdata. This psect does not contribute to the output file.
The runtime startup code performs a block copy of the values from the idata to the rdata psect
so that the RAM variables will contain their initial values before main() is executed. Each location
in the idata psect is copied to appropriate placed in the rdata psect.
The block copy of the data psects may be omitted by disabling the init suboption of --RUNTIME.
For example:
RUNTIME=default,-init
With this part of the runtime startup code absent, the contents of initialized variables will be
unpredictable when the program begins execution. Code relying on variables containing their initial
value will fail.
Variables whose contents should be preserved over a reset, or even power off, should be qualified
with persistent, see Section 3.4.9.1. Such variables are linked at a different area of memory and are
not altered by the runtime startup code in any way.
The ANSI standard dictates that those non-auto objects which are not initialized must be cleared
before execution of the program begins. The compiler does this by grouping all such uninitialized
objects into a bss psect. This psect is then cleared as a block by the runtime startup code.
The abbreviation "bss" stands for Block Started by Symbol and was an assembler pseudo-op
used in IBM systems back in the days when computers were coal-fired. The continued usage of this
term is still appropriate.
The name of the bss psect is rbss.
The block clear of the bss psect may be omitted by disabling the clear suboption of --RUNTIME.
For example:
RUNTIME=default,-clear
With this part of the runtime startup code absent, the contents of uninitialized variables will be
unpredictable when the program begins execution.
39
Supported Data Types and Variables C Language Features
Variables whose contents should be preserved over a reset, or even power off, should be qualified
with persistent, see Section 3.4.9.1. Such variables are linked at a different area of memory and are
not altered by the runtime startup code in anyway.
By default, a set of libraries are automatically passed to the linker to be linked in with users program.
The libraries can be omitted by disabling the clib suboption of --RUNTIME. For example:
RUNTIME=default,-clib
With this part of the runtime startup code absent, the user must provide alternative library or
source files to allow calls to library routines. This suboption may be useful if alternative library or
source files are available and you wish to ensure that no HI-TECH C library routines are present in
the final output.
Some C statements produce assembler code that call library routines even though no library
function was called by the C code. These calls perform such operations as division or floating-point
arithmetic. If the C libraries have been excluded from the code output, these implicit library calls
will also require substitutes.
Some hardware configurations require special initialization, often within the first few cycles of ex-
ecution after reset. To achieve this there is a hook to the reset vector provided via the powerup
routine. This is a user-supplied assembler module that will be executed immediately on reset. Often
this can be embedded in a C module as embedded assembler code. A dummy powerup routine is
included in the file powerup.as. The file can be copied, modified and included into your project.
No special linking options or jumps to the powerup routine are required, the compiler will detect if
you are using a powerup routine and will automatically generate code to jump to it after reset. If you
use a powerup routine, you will, however, need to add a jump to start after your initializations.
Refer to comments in the powerup source file for details about this. The powerup.as source file can
be found in the compilers SOURCES directory.
40
C Language Features Supported Data Types and Variables
41
Supported Data Types and Variables C Language Features
String constants or string literals are enclosed by double quote characters ", for example "hello
world". The type of string constants is const char * and the strings are stored in the program
memory. Assigning a string constant to a non-const char pointer will generate a warning from the
compiler. For example:
char * cp= "one"; // "one" in ROM, produces warning
const char * ccp= "two"; // "two" in ROM, correct
Defining and initializing a non-const array (i.e. not a pointer definition) with a string, for
example:
char ca[]= "two"; // "two" different to the above
produces an array in data space which is initialised at startup with the string "two" (copied from
program space), whereas a constant string used in other contexts represents an unnamed const-
qualified array, accessed directly in program space.
HI-TECH C will use the same storage location and label for strings that have identical character
sequences, except where the strings are used to initialise an array residing in the data space as shown
in the last statement in the previous example.
Two adjacent string constants (i.e. two strings separated only by white space) are concatenated
by the compiler. Thus:
const char * cp = "hello " "world";
assigned the pointer with the string "hello world".
42
C Language Features Supported Data Types and Variables
Note that when assigning a larger integral type to a bit variable, only the least-significant bit is
used. For example, if the bit variable bitvar was assigned as in the following:
int data = 0x54;
bit bitvar;
bitvar = data;
it will be cleared by the assignment since the least significant bit of data is zero. If you want to
set a bit variable to be 0 or 1 depending on whether the larger integral type is zero (false) or non-zero
(true), use the form:
bitvar = data != 0;
The psects in which bit objects are allocated storage are declared using the bit PSECT directive
flag. Eight bit objects will take up one byte of storage space which is indicated by the psects scale
value of 8 in the map file. The length given in the map file for bit psects is in units of bits, not bytes.
All addresses specified for bit objects are also bit addresses.
The bit psects are cleared on startup, but are not initialised. To create a bit object which has a
non-zero initial value, explicitly initialise it at the beginning of your code.
If the PICC flag --STRICT is used, the bit keyword becomes unavailable.
HI-TECH PICC supports both signed char and unsigned char 8-bit integral types. If the signed
or unsigned keyword is absent from the variables definition, the default type is unsigned char
unless the PICC --CHAR=signed option is used, in which case the default type is signed char. The
signed char type is an 8-bit twos complement signed integer type, representing integral values
from -128 to +127 inclusive. The unsigned char is an 8-bit unsigned integer type, representing
integral values from 0 to 255 inclusive. It is a common misconception that the C char types are
intended purely for ASCII character manipulation. This is not true, indeed the C language makes
no guarantee that the default character representation is even ASCII. The char types are simply the
smallest of up to four possible integer sizes, and behave in all respects like integers.
The reason for the name char is historical and does not mean that char can only be used to
represent characters. It is possible to freely mix char values with short, int and long values in C
expressions. With HI-TECH C the char types will commonly be used for a number of purposes, as
8-bit integers, as storage for ASCII characters, and for access to I/O locations.
Variables may be declared using the signed char and unsigned char keywords, respectively,
to hold values of these types. Where only char is used in the declaration, the type will be signed
char unless the option, mentioned above, to specify unsigned char as default is used.
43
Supported Data Types and Variables C Language Features
The exponent is 8-bits which is stored as excess 127 (i.e. an exponent of 0 is stored as 127).
44
C Language Features Supported Data Types and Variables
mantissa is the mantissa, which is to the right of the radix point. There is an implied bit to the
left of the radix point which is always 1 except for a zero value, where the implied bit is zero.
A zero value is indicated by a zero exponent.
45
Supported Data Types and Variables C Language Features
struct {
unsigned lo : 1;
unsigned dummy : 6;
unsigned hi : 1;
} foo;
will produce a structure occupying 1 bytes. If foo was ultimately linked at address 10H, the field lo
will be bit 0 of address 10H, hi will be bit 7 of address 10H. The least significant bit of dummy will
be bit 1 of address 10H and the most significant bit of dummy will be bit 6 of address 10h.
Unnamed bit-fields may be declared to pad out unused space between active bits in control
registers. For example, if dummy is never used the structure above could have been declared as:
struct {
unsigned lo : 1;
unsigned : 6;
unsigned hi : 1;
} foo;
If a bit-field is declared in a structure that is assigned an absolute address, no storage will be allocated
for the structure. Absolute structures would be used when mapping a structure over a register to allow
a portable method of accessing individual bits within the register.
A structure with bit-fields may be initialised by supplying a comma-separated list of initial values
for each field. For example:
46
C Language Features Supported Data Types and Variables
struct {
unsigned lo : 1;
unsigned mid : 6;
unsigned hi : 1;
} foo = {1, 8, 0};
47
Supported Data Types and Variables C Language Features
Obviously, a const object must be initialised when it is declared as it cannot be assigned a value at
any point at runtime. For example:
const int version = 3;
The volatile type qualifier is used to tell the compiler that an object cannot be guaranteed to
retain its value between successive accesses. This prevents the optimizer from eliminating apparently
redundant references to objects declared volatile because it may alter the behaviour of the program
to do so. All Input/Output ports and any variables which may be modified by interrupt routines
should be declared volatile, for example:
volatile static unsigned int TACTL @ 0x160;
Volatile objects may be accessed using different generated code to non-volatile objects.
By default, any C variables that are not explicitly initialised are cleared to zero on startup. This is
consistent with the definition of the C language. However, there are occasions where it is desired for
some data to be preserved across resets or even power cycles (on-off-on).
The persistent type qualifier is used to qualify variables that should not be cleared on startup.
In addition, any persistent variables will be stored in a different area of memory to other variables.
persistent objects are placed within the psect nvram.
This type qualifier may not be used on variables of class auto; if used on variables local to a
function they must be combined with the static keyword. For example, you may not write:
void test(void)
{
persistent int intvar; /* WRONG! */
.. other code ..
}
because intvar is of class auto. To declare intvar as a persistent variable local to function
test(), write:
static persistent int intvar;
If the PICC option, --STRICT is used, this type qualifier is changed to __persistent.
There are some library routines provided to check and initialise persistent data - see A for
more information, and for an example of using persistent data.
48
C Language Features Supported Data Types and Variables
49
Supported Data Types and Variables C Language Features
Function Pointers reference functions. A function is jumped to rather than called. A jump
table is used to return control to the calling function.
RAM pointers are 8-bits and therefore can only access 256 bytes. A pointer which is unqual-
ified or has a bank 1 qualifier can point to any object in bank 0 or bank 1. If the pointer is
qualified as bank 2 or bank 3, then it can access any object in banks 2 or 3. At present, there
is no general purpose pointer that can read and write to all four banks.
Const pointers are 16-bits wide. They can be used to access either ROM or RAM. If the upper
bit of the const pointer is non-zero, it is a pointer into RAM. A const pointer may be used to
read from any RAM location in any bank, but writing to such locations is not permitted. If
upper bit is zero, it is a pointer able to access the entire ROM space. The ability of this pointer
to access both ROM and RAM is very useful in string-related functions where a pointer passed
to the function may point to a string in ROM or RAM.
Function pointers reference functions. A function is called using the address assigned to the
pointer.
RAM banks in highend processors are 0xFF bytes long, so an 8-bit RAM pointer can only
access objects in one bank. Thus a bank 0 RAM pointer can only access bank 0; a bank 1
RAM pointer can only access bank 1, etc...
Const pointers for highend processors are 16-bits wide. Const pointers on highend processors
work in the same way as they do for midrange processors.
Far pointers are 16-bits wide and can be used to access objects in any available bank of RAM.
These pointers are similar to const pointers; they differ in that they may be used to indirectly
read from, or write to, RAM locations. Far pointers can also access ROM locations as per
const pointers. The far qualifier is used to specify the larger pointer size.
Function pointers reference function. A function is called using the address assigned to the
pointer.
50
C Language Features Storage Class and Object Placement
Pointers can be qualified like any other C objects, but care must be taken when doing so as there
are two quantities associated with pointers. The first is the actual pointer itself, which is treated like
any ordinary C variable and has memory reserved for it. The second is the object that the pointer
references, or to which the pointer points. The general form of an initialized pointer definition looks
like the following.
objects_type_&_qualifiers * pointers_qualifiers pointers_name = value;
The rule is as follows: if the modifier is to the left of the * in the pointer declaration, it applies to
the object which the pointer references. If the modifier is to the right of the *( next to the pointers
name), it applies to the pointer variable itself. Any data variable qualifier may be applied to pointers
in the above manner.
Here are three examples of pointers, initialized with the address of the variables:
const int ci = 0x55aa;
int i;
in which the definition fields are highlighted with spacing:
const int * cip = &ci ;
int * const icp = &i ;
const int * const cicp = &ci ;
The first example is a pointer called cip. It contains the address of an int object (in this case
ci) that is qualified const, however the pointer itself is not qualified. The pointer may be used to
read, but not write, the object to which it references. The contents of the pointer may be read and
written by the program.
The second example is a pointer called icp which contains the address of an int object (in this
case i). Since this object is not qualified, it is a data space object which is referenced by the pointer
and this object can be both read and written using the pointer. However, the pointer is qualified
const and so can only be read by the program it cannot be made to point to any other object
other than the object whose address initializes the pointer (in this case i).
The last example is of a pointer called cicp which is itself qualified const and which also holds
the address of an object that is also qualified const. Thus the pointer can only be used to read the
object to which it references and the pointer itself cannot be modified so it will always reference the
same object during the program (in this case ci).
51
Storage Class and Object Placement C Language Features
Auto (short for automatic) variables are the default type of local variable. Unless explicitly declared
to be static a local variable will be made auto, however the auto keyword may be used if desired.
Auto variables are allocated in the auto-variable block and referenced by indexing off the symbol
that represents that block. The variables will not necessarily be allocated in the order declared - in
contrast to parameters which are always in lexical order. Note that most type qualifiers cannot be
used with auto variables, since there is no control over the storage location. The exceptions are const
and volatile.
All auto variables are allocated memory in bank 0. The bank qualifiers cannot be used with
objects of type auto.
The auto-variable blocks for a number of functions are overlapped by the linker if those functions
are never called at the same time.
Auto objects are referenced with a symbol that consists of a question mark, ?, concatenated
with a_function plus some offset, where function is the name of the function in which the object is
defined. For example, if the int object test is the first object placed in mains auto-variable block it
will be accessed using the addresses ?a_main and ?a_main+1 since an int is two bytes long.
Uninitialized static variables are allocated in the rbss_n psect and occupy fixed memory location
which will not be overlapped by storage for other functions. Static variables are local in scope to
the function in which they are declared, but may be accessed by other functions via pointers since
they have permanent duration. Static variables are guaranteed to retain their value between calls to a
function, unless explicitly modified via a pointer. Static variables are not subject to any architectural
limitations on the PIC.
Static variables which are initialised are only done so once during the programs execution. Thus,
they may be preferable over initialised auto objects which are assigned a value every time the block
in which the definition is placed is executed.
52
C Language Features Functions
3.6 Functions
3.6.1 Function Argument Passing
The method used to pass function arguments depends on the size of the argument or arguments.
If there is only one argument, and it is one byte in size, it is passed in the W register.
If there is only one argument, and it is greater than one byte in size, it is passed in the argument
area of the called function. If there are subsequent arguments, these arguments are also passed in the
argument area of the called function. The argument area is referenced by an offset from the symbol
?_function, where function is the name of the function concerned.
If there is more than one argument, and the first argument is one byte in size, it is passed in the
W register, with subsequent arguments being passed in the argument area of the called function.
In the case of a variable argument list, which is defined by the ellipsis symbol ..., the calling
function builds up the variable argument list and passes a pointer to the variable part of the argument
list in btemp. Btemp is the label at the start of the temp psect (the psect used for temporary data).
Take, for example, the following ANSI-style function:
void test(char a, int b)
{
}
53
Functions C Language Features
The function test() will receive the parameter b in its function argument block and a in the W
register. A call:
test( a, 8);
would generate code similar to:
movlw 08h
movwf ?_test
clrf ?_test+1
movf _a,w
call (_test)
In this example, the parameter b is held in the memory locations ?_test and ?_test+1.
If you need to determine, for assembler code for example, the exact entry or exit code within a
function or the code used to call a function, it is often helpful to write a dummy C function with the
same argument types as your assembler function, and compile to assembler code with the PICC -S
option, allowing you to examine the assembler code.
54
C Language Features Function Calling Convention
55
Operators C Language Features
To disable the lookup-table mode of operation, a function definition can be qualified as fastcall,
so that calls to this function are performed using the usual call assembly instruction. Extreme care
must be used when functions are declared as fastcall, since the each nested fastcall will use one
word of available stack space. Check the call graph in the map file to ensure that the stack will not
overflow.
The function prototype for a baseline fastcall function might look something like:
fastcall void my_function(int a);
The midrange and high end PIC devices have larger stacks and are thus allow a higher degree of
function nesting. These devices do not use the lookup table method when calling functions.
The compiler assumes that bank zero will be selected after returning from any function call. The
compiler inserts the appropriate instructions to ensure this is true if required. Any functions callable
from C code that are written in assembler must also ensure that bank zero is selected before the
return.
3.8 Operators
HI-TECH C supports all the ANSI operators. The exact results of some of these are implementation
defined. The following sections illustrate code produced by the compiler.
56
C Language Features Operators
the subtraction with these data types is -50 (which is less than 10) and hence the body of the if()
statement is executed. If the result of the subtraction is to be an unsigned quantity, then apply a
cast. For example:
if((unsigned int)(a - b) < 10)
count++;
The comparison is then done using unsigned int, in this case, and the body of the if() would
not be executed.
Another problem that frequently occurs is with the bitwise compliment operator, ~. This
operator toggles each bit within a value. Consider the following code.
unsigned char count, c;
c = 0x55;
if( ~c == 0xAA)
count++;
If c contains the value 55h, it often assumed that ~c will produce AAh, however the result is
FFAAh and so the comparison in the above example would fail. The compiler may be able to issue
a mismatched comparison error to this effect in some circumstances. Again, a cast could be used to
change this behaviour.
The consequence of integral promotion as illustrated above is that operations are not performed
with char-type operands, but with int-type operands. However there are circumstances when the
result of an operation is identical regardless of whether the operands are of type char or int. In
these cases, HI-TECH C will not perform the integral promotion so as to increase the code efficiency.
Consider the following example.
unsigned char a, b, c;
a = b + c;
Strictly speaking, this statement requires that the values of b and c should be promoted to
unsigned int, the addition performed, the result of the addition cast to the type of a, and then
the assignment can take place. Even if the result of the unsigned int addition of the promoted
values of b and c was different to the result of the unsigned char addition of these values without
promotion, after the unsigned int result was converted back to unsigned char, the final result
would be the same. If an 8-bit addition is more efficient than a 16-bit addition, the compiler will
encode the former.
If, in the above example, the type of a was unsigned int, then integral promotion would have
to be performed to comply with the ANSI standard.
57
Psects C Language Features
bit of the result can either be zero, or a copy of the most significant bit before the shift took place.
The latter case amounts to a sign extension of the number.
HI-TECH PICC performs a sign extension of any signed integral type (for example signed
char, signed int or signed long). Thus an object with the signed int value 0x0124 shifted
right one bit will yield the value 0x0092 and the value 0x8024 shifted right one bit will yield the
value 0xC012.
Right shifts of unsigned integral values always clear the most significant bit of the result.
Left shifts (< < operator), signed or unsigned, always clear the least significant bit of the result.
3.9 Psects
The compiler splits code and data objects into a number of standard program sections referred to
as psects. The HI-TECH assembler allows an arbitrary number of named psects to be included in
assembler code. The linker will group all data for a particular psect into a single segment.
If you are using PICC to invoke the linker, you dont need to worry about the information doc-
umented here, except as background knowledge. If you want to run the linker manually (this is
not recommended), or write your own assembly language subroutines, you should read this section
carefully.
A psect can be created in assembler code by using the PSECT assembler directive (see Section
4.3.8.3). In C, user-defined psects can be created by using the #pragma psect preprocessor direc-
tive, see Section 3.12.3.5.
58
C Language Features Psects
clrtext Used by some startup routines for clearing the rbss_n psects.
checksum If a checksum has been requested, the result will be stored in this psect.
cstrings High-End processors use the cstrings psect to store const objects and string literals. ROM
on these devices is 16 bits wide so two characters can be stored in the one ROM word.
float_textn Used by some library routines, and in particular by arithmetic routines.It is possible
that this psect will have a non-zero length even if no floating point operations are included in
a program.
idata_n These psects (where n is the bank number) contain the ROM image of any initialised vari-
ables. These psects are copied into the rdata_n psects at startup.
intcode Is the psect which contains the executable code for the interrupt service routine.
intentry Contains the entry code for the interrupt service routine. This code saves the necessary
registers and parts of the temp psect.
intret Is the psect which contains the executable code responsible for restoring saved registers and
objects after an interrupt routine has completed executing.
jmp_tab Only for the Baseline processors, this is another strings psect used to store jump addresses
and function return values.
maintext This psect will contain the main() function. It is used so that main() can be directly linked.
59
Psects C Language Features
pstrings For processors that support string packing, this psect will contain the packed strings.
reset_wrap For baseline PICs, this psect contains code which appears after the reset vector has
wrapped around to address 0x0.
strings The strings psect is used for some const objects. Const objects whose size exceeds 256
bytes, for example const arrays, are positioned in this psect. It also includes all unnamed
string constants, such as string constants passed as arguments to routines like printf() and
puts(). This psect is linked into ROM, since it does not need to be modifiable.
stringtable The stringtable psect contains the string table which is used to access objects in the
strings psect. This psect will only be generated if there is a strings or baseline jmp_tab psect.
text Is a global psect used for executable code for some library functions.
textn These psects (where n is a number) contain all executable code for the Midrange and High-
end processors. They also contains any executable code after the first goto instruction which
can never be skipped for the Baseline processors.
The compiler-generated psects which are placed in the data space are:
intsave Holds the W register saved by the interrupt service routine. If necessary, the W register will
also be saved in the intsave_n psects.
intsave_n May also hold the W register saved by the interrupt service routine. (See the description
of the intsave psect.)
nvbit_n These psects are used to store persistent bit variables. They are not cleared or otherwise
modified at startup.
nvram_n These psects are used to store persistent variables. They are not cleared or otherwise
modified at startup.
rbit_n These psects are used to store all bit variables except those declared at absolute locations.
60
C Language Features Interrupt Handling in C
temp Is used to store scratch variables used by the compiler. These include function return values
larger than a char and values passed to and returned from library routines. If possible, this will
be positioned in the common area of the processor.
xtemp Is used to store scratch variables used by the compiler and to pass values to and from the
library routines.
61
Interrupt Handling in C C Language Features
62
C Language Features Interrupt Handling in C
the lower seven bits.When the interrupt occurs, W will be saved into one of these memory areas
depending on the bank in which the processor was in before the interrupt occurred.
If the STATUS register is to be saved, it is stored into memory reserved in the intsave psect which
resides in Bank 0.
Some C code, for example division, may call an assembly routine which used temporary RAM
locations. If these are used during the interrupt function, they too will be saved by separate routines
which are automatically linked.
63
Interrupt Handling in C C Language Features
An example of using the interrupt levels is given below. Note that the #pragma directive ap-
plies to only the immediately following function. Multiple #pragma interrupt_level directives may
precede a non-interrupt function to specify that it will be protected from multiple interrupt levels.
/* non-interrupt function called by interrupt and by main-line code */
#pragma interrupt_level 1
void bill(){
int i;
i = 23;
}
/* two interrupt functions calling the same non-interrupt function */
#pragma interrupt_level 1
void interrupt fred(void) {
bill();
}
#pragma interrupt_level 1
void interrupt joh() {
bill();
}
main() {
bill();
}
On High-End devices, the compiler allows a maximum of two interrupt routines to be active at any
given time. This is handled by the #pragma interrupt_level directive. The only available interrupt
levels are levels 0 and 1. Interrupts are level 0 by default.
All level 0 interrupts share the same memory for saving context when the interrupt occurs. Level
1 interrupts use a separate memory area. Thus only one interrupt of each level may be active at any
given time. It is up to the user to ensure that this is the case. Interrupts may be re-enabled during an
interrupt routine as long as the only possible interrupt will be of a different level.
Two macros are available in <htc.h> which control the masking of all available interrupts. These
macros are ei(), which enable or unmask all interrupts, and di(), which disable or mask all interrupts.
On High-End PIC devices, these macros affect the GLINTD bit in the CPUSTA register; in midrange
PIC devices, they affect the GIE bit in the INTCON register.
64
C Language Features Mixing C and Assembler Code
These macros should be used once the appropriate interrupt enable bits for the interrupts that are
required in a program have been enabled. For example:
ADIE = 1; // A/D interrupts will be used
PEIE = 1; // all peripheral interrupts are enabled
ei(); // enable all interrupts
di(); // disable all interrupts
select a name (label) for the routine so that its corresponding C identifier is valid
ensure that the routines label is globally accessible from other modules
select an appropriate equivalent C prototype for the routine on which argument passing can be
modelled
ensure any symbol used to hold arguments to the routine is globally accessible
optionally, use a signature value to enable type checking when the function is called
write the routine ensuring arguments are read from the correct location, the return value is
loaded to the correct storage location before returning
ensure any local variables required by the routine have space reserved by the appropriate
directive
65
Mixing C and Assembler Code C Language Features
A mapping is performed on the names of all C functions and non-static global variables. See
Section 3.11.3.1 for a complete description of mappings between C and assembly identifiers.
An assembly routine is required which can add two 16-bit values together. The routine must be
callable from C code. Both the values are passed in as arguments when the routine is called from the
C code. The assembly routine should return the result of the addition as a 16-bit quantity.
Most compiler-generated executable code is placed in a psect called textn (see Section 3.9.1).
As we do not need to have this assembly routine linked at any particular location, we can use this
psect so the code is bundled with other executable code and stored somewhere in the program space.
This way we do not need to use any additional linker options. So we use an ordinary looking psect
that you would see in assembly code produced by the compiler. The psects name is text0, will be
linked in the CODE class, which will reside in a memory space that has 2 bytes per addressable
location:
PSECT text0,local,class=CODE,delta=2
Now we would like to call this routine add. However in assembly we must choose the name
_add as this then maps to the C identifier add since the compiler prepends an underscore to all C
identifiers when it creates assembly labels. If the name add was chosen for the assembler routine
the it could never be called from C code. The name of the assembly routine is the label that we will
associate with the assembly code:
_add:
We need to be able to call this from other modules, some make this label globally accessible:
GLOBAL _add
By compiling a dummy C function with a similar prototype to how we will be calling this as-
sembly routine, we can determine the signature value. We add a assembler directive to make this
signature value known:
SIGNAT _add,8298
When writing the function, you can find that the parameters will be loaded into the functions
parameter area by the calling function, and the result should be placed in btemp.
To call an assembly routine from C code, a declaration for the routine must be provided. This
ensures that the compiler knows how to encode the function call in terms of parameters and return
values, however no other code is necessary.
If a signature value is present in the assembly code routine, its value will be checked by the linker
when the calling and called routines signatures can be compared.
To continue the previous example, here is a code snippet that declares the operation of the as-
sembler routine, then calls the routine.
extern unsigned int add(unsigned a, unsigned b);
void main(void)
{
int a, result;
a = read_port();
66
C Language Features Mixing C and Assembler Code
67
Preprocessing C Language Features
3.12 Preprocessing
All C source files are preprocessed before compilation. Assembler files can also be preprocessed if
the -P command-line option is issued.
68
C Language Features Preprocessing
#pragma inline(__va_start)
extern void * __va_start(void);
69
Preprocessing C Language Features
70
C Language Features Preprocessing
71
Preprocessing C Language Features
72
C Language Features Preprocessing
ment lists. The above example would cast any pointers to strings in RAM to be pointers of the type
(const char *)
Note that the warning level must be set to -1 or below for this option to have any visible effect.
See Section 2.4.54.
Normally the object code generated by the compiler is broken into the standard psects as described
in Section 3.9.1. This is fine for most applications, but sometimes it is necessary to redirect variables
or code into different psects when a special memory configuration is desired. Code and data for any
of the standard C psects may be redirected using a #pragma psect directive.
The general form of this pragma looks like:
#pragma psect default_psect=new_psect
and instructs the code generator that anything that would normally appear in the compiler-
generated psect default_psect, will now appear in a new psect called new_psect. This psect
will be identical to default_psect in terms of its options, however will have a different name.
Thus, this new psect can be explicitly positioned by the linker without affect the original psects
location.
If the name of the default psect that is being redirected contains a counter, e.g. text0, text1,
text2, then the placeholder %%u should be used in the name of the psect at the position of the counter,
e.g. text%%u. Any default psect, regardless of the counter value, will match such a psect name.
This pragma remains in force until the end of the module and any given psect should only be
redirected once in a particular module. All psect redirections for a particular module should be
placed at the top of the source file, below any #include statements and above any other declarations.
A particular function, called read_port(), needs to be located at the absolute address 0x400 in a
program. Using the #pragma psect directive in the source code, and adding a new linker option can
do this. First write the function in the usual way. Place the function definition in a separate module.
There is obviously something special about this function so a module all to itself is probably a good
idea anyway.
unsigned char read_port(void)
{
return PORTA;
}
Now, how do we know in which psect the code associated with the function will be placed?
Compile you program, including this new module and generate an assembly list file, see Section
2.4.17.
Look for the definition of the function. A function starts with an assembly label which is the
name of the function prepended with an underscore. In this example, the label appears on line 37.
73
Preprocessing C Language Features
36 psect text
37 0002 _read_port:
Look above this to see the first PSECT directive you encounter. This will indicate the name of the
psect in which the code is located. In this case it is the psect called text.
So let us redirect this psect into one with a unique and more meaningful name. In the C module
that contains the definition for read_port() place the following pragma:
#pragma psect text=readport
at the top of the module, before the function definition. With this, the read_port() function
will be placed in the psect called readport. Confirm this in the new assembly list file.
Now we can tell the linker where we would like this psect positioned. Issue an additional option
to the command-line driver to place this psect at address 0x400.
-L-preadport=0400h
The generate an check the map file, see Section 2.4.8. You should see the additional linker
command (minus the leading -L part of the option) present in the section after Linker command
line:. You should also see the remapped psect name appear in the source file list of psects, e.g.:
Name Link Load Length Selector Space Scale
/tmp/cgt9e31jr.obj
main.obj maintext 0 0 2 0 0
portread 400 400 2 800 0
Check the link address to ensure it is that requested, in this case, 0x400.
where register_list is a comma-separated list of registers names. Those registers not listed are
assumed to be unused by the function or routine. The code generator may use the unlisted registers
to hold values across a function call. Hence, if the routine does in fact use these registers, unreliable
program execution may eventuate. The list of registers to be saved will apply to the first interrupt
qualified function defined after the pragmas usage.
The register names are not case sensitive and a warning will be produced if the register name is
not recognised. A blank list indicates that the specified function or routine uses no registers.
74
C Language Features Linking Programs
75
Linking Programs C Language Features
obtained by using the PICC --SUMMARY=psect option. Generate a map file for the complete memory
specification of the program.
76
C Language Features Standard I/O Functions and Serial I/O
called _widget which takes two int arguments and returns a char value. The prototype used to call
this function from C would be:
extern char widget(int, int);
Where a call to _widget is made in the C code, the signature for a function with two int
arguments and a char return value would be generated. In order to match the correct signature the
source code for widget needs to contain an assembler SIGNAT pseudo-op which defines the same
signature value. To determine the correct value, you would write the following code:
char widget(int arg1, int arg2)
{
}
and compile it to assembler code using
PICC -S x.c
The resultant assembler code includes the following line:
SIGNAT _widget,8249
The SIGNAT pseudo-op tells the assembler to include a record in the .obj file which associates
the value 8249 with symbol _widget. The value 8249 is the correct signature for a function with
two int arguments and a char return value. If this line is copied into the .as file where _widget is
defined, it will associate the correct signature with the function and the linker will be able to check
for correct argument passing. For example, if another .c file contains the declaration:
extern char widget(long);
then a different signature will be generated and the linker will report a signature mis-match which
will alert you to the possible existence of incompatible calling conventions.
77
Standard I/O Functions and Serial I/O C Language Features
78
Chapter 4
Macro Assembler
The Macro Assembler included with HI-TECH PICC assembles source files for PIC MCUs. This
chapter describes the usage of the assembler and the directives (assembler pseudo-ops and controls)
accepted by the assembler in the source files.
The HI-TECH C Macro Assembler package includes a linker, librarian, cross reference generator
and an object code converter.
Athough the term assembler is almost universally used to decribe the tool which con-
verts human-readable mnemonics into machine code, both assembler and assembly
are used to describe the source code which such a tool reads. The latter is more com-
mon and is used in this manual to describe the language. Thus you will see the terms
assembly language (or just assembly), assembly listing and etc, but assembler options,
assembler directive and assembler optimizer.
79
Assembler Options Macro Assembler
where the assembler is being called directly, or when they are specified using the command-line
driver option --SETOPTION, see Section 2.4.48.
The usage of the assembler is similar under all of available operating systems. All command-line
options are recognised in either upper or lower case. The basic command format is shown:
files is a space-separated list of one or more assembler source files. Where more than one source
file is specified the assembler treats them as a single module, i.e. a single assembly will be performed
on the concatenation of all the source files specified. The files must be specified in full, no default
extensions or suffixes are assumed.
options is an optional space-separated list of assembler options, each with a minus sign - as
the first character. A full list of possible options is given in Table 4.1, and a full description of each
option follows.
80
Macro Assembler Assembler Options
-A An assembler file with an extension .opt will be produced if this option is used. This is useful
when checking the optimized assembler produced using the -O option.
-C A cross reference file will be produced when this option is used. This file, called srcfile.crf,
where srcfile is the base portion of the first source file name, will contain raw cross refer-
ence information. The cross reference utility CREF must then be run to produce the formatted
cross reference listing. See Section 4.7 for more information.
-Cchipinfo Specify the chipinfo file to use. The chipinfo file is called picc.ini and can be found
in the DAT directory of the compiler distribution.
-E[file|digit] The default format for an error message is in the form:
where the error of type message occurred on line line of the file filename.
The -E option with no argument will make the assembler use an alternate format for
error and warning messages.
Specifying a digit as argument has a similar effect, only it allows selection of any of
the available message formats.
Specifying a filename as argument will force the assembler to direct error and warning
messages to a file with the name specified.
-Flength By default the listing format is pageless, i.e. the assembler listing output is continuous.
The output may be formatted into pages of varying lengths. Each page will begin with a
header and title, if specified. The -F option allows a page length to be specified. A zero value
of length implies pageless output. The length is specified in a number of lines.
-H Particularly useful in conjunction with the -A or -L ASPIC options, this option specifies that
output constants should be shown as hexadecimal values rather than decimal values.
-I This option forces listing of macro expansions and unassembled conditionals which would other-
wise be suppressed by a NOLIST assembler control. The -L option is still necessary to produce
a listing.
-Llistfile This option requests the generation of an assembly listing file. If listfile is specified
then the listing will be written to that file, otherwise it will be written to the standard output.
-O This requests the assembler to perform optimization on the assembly code. Note that the use of
this option slows the assembly process down, as the assembler must make an additional pass
over the input code. Debug information for assembler code generated from C source code
may become unreliable.
81
HI-TECH C Assembly Language Macro Assembler
-Ooutfile By default the assembler determines the name of the object file to be created by stripping
any suffix or extension (i.e. the portion after the last dot) from the first source filename and
appending .obj. The -O option allows the user to override the default filename and specify a
new name for the object file.
-Pprocessor This option defines the processor which is being used. The processor type can also be
indicated by use of the PROCESSOR directive in the assembler source file, see Section 4.3.8.24.
You can also add your own processors to the compiler via the compilers chipinfo file.
-V This option will include line number and filename information in the object file produced by
the assembler. Such information may be used by debuggers. Note that the line numbers will
correspond with assembler code lines in the assembler file. This option should not be used
when assembling an assembler file produced by the code generator from a C source file.
-Twidth This option allows specification of the listfile paper width, in characters. width should be
a decimal number greater than 41. The default width is 80 characters.
-X The object file created by the assembler contains symbol information, including local symbols,
i.e. symbols that are neither public or external. The -X option will prevent the local symbols
from being included in the object file, thereby reducing the file size.
82
Macro Assembler HI-TECH C Assembly Language
4.3.2 Characters
The character set used is standard 7 bit ASCII. Alphabetic case is significant for identifiers, but not
mnemonics and reserved words. Tabs are treated as equivalent to spaces.
4.3.2.1 Delimiters
All numbers and identifiers must be delimited by white space, non-alphanumeric characters or the
end of a line.
4.3.3 Comments
An assembly comment is initiated with a semicolon that is not part of a string or character constant.
If the assembly file is first processed by the C preprocessor, see Section 2.4.11, then it may also
contain C or C++ style comments using the standard /* ... */ and // syntax.
83
HI-TECH C Assembly Language Macro Assembler
4.3.4 Constants
4.3.4.1 Numeric Constants
The assembler performs all arithmetic with signed 32-bit precision.
The default radix for all numbers is 10. Other radices may be specified by a trailing base specifier
as given in Table 4.3.
Hexadecimal numbers must have a leading digit (e.g. 0ffffh) to differentiate them from identi-
fiers. Hexadecimal digits are accepted in either upper or lower case.
Note that a binary constant must have an upper case B following it, as a lower case b is used for
temporary (numeric) label backward references.
In expressions, real numbers are accepted in the usual format, and are interpreted as IEEE 32-bit
format.
4.3.5 Identifiers
Assembly identifiers are user-defined symbols representing memory locations or numbers. A sym-
bol may contain any number of characters drawn from the alphabetics, numerics and the special
characters dollar, $, question mark, ? and underscore, _.
The first character of an identifier may not be numeric. The case of alphabetics is significant,
e.g. Fred is not the same symbol as fred. Some examples of identifiers are shown here:
An_identifier
an_identifier
an_identifier1
84
Macro Assembler HI-TECH C Assembly Language
$
?$_12345
goto $
will represent code that will jump to itself and form an endless loop. By using this symbol and an
offset, a relative jump destination to be specified.
The address represented by $ is a word address and thus any offset to this symbol represents a
number of instructions. For example:
goto $+1
movlw 8
movwf _foo
85
HI-TECH C Assembly Language Macro Assembler
86
Macro Assembler HI-TECH C Assembly Language
4.3.6 Expressions
The operands to instructions and directives are comprised of expressions. Expressions can be made
up of numbers, identifiers, strings and operators.
Operators can be unary (one operand, e.g. not) or binary (two operands, e.g. +). The operators
allowable in expressions are listed in Table 4.4. The usual rules governing the syntax of expressions
apply.
The operators listed may all be freely combined in both constant and relocatable expressions. The
HI-TECH linker permits relocation of complex expressions, so the results of expressions involving
relocatable identifiers may not be resolved until link time.
The concept of a program section is not a HI-TECH-only feature. Often referred to as
blocks or segments in other compilers, these grouping of code and data have long used
the names text, bss and data.
A psect is identified by a name and has several attributes. The PSECT assembler directive is used
to define a psect. It takes as arguments a name and an optional comma-separated list of flags. See
Section 4.3.8.3 for full information on psect definitions. Chapter 5 has more information on the
operation of the linker and on optins that can be used to control psect placement in memory.
The assembler associates no significance to the name of a psect and the linker is also not aware
of which are compiler-generated or user-defined psects. Unless defined as abs (absolute), psects are
relocatable.
The following is an example showing some executable instructions being placed in the text
psect, and some data being placed in the rbss psect.
PSECT text0,class=CODE,delta=2
adjust
goto clear_fred
increment
incf _fred
PSECT rbss_0,class=BANK0,space=1
fred
87
HI-TECH C Assembly Language Macro Assembler
88
Macro Assembler HI-TECH C Assembly Language
DS 2
PSECT text0,class=CODE,delta=2
clear_fred
clrf _fred
return
Note that even though the two blocks of code in the text psect are separated by a block in the rbss
psect, the two text psect blocks will be contiguous when loaded by the linker. In other words,
the incf _fred instruction will be followed by the clrf instruction in the final ouptut. The actual
location in memory of the text and rbss psects will be determined by the linker.
Code or data that is not explicitly placed into a psect will become part of the default (unnamed)
psect.
4.3.8.1 GLOBAL
GLOBAL declares a list of symbols which, if defined within the current module, are made public. If
the symbols are not defined in the current module, it is a reference to symbols in external modules.
Example:
GLOBAL lab1,lab2,lab3
4.3.8.2 END
END is optional, but if present should be at the very end of the program. It will terminate the assembly
and not even blank lines should follow this directive. If an expression is supplied as an argument,
that expression will be used to define the start address of the program. Whether this is of any use
will depend on the linker. Example:
END start_label
89
HI-TECH C Assembly Language Macro Assembler
90
Macro Assembler HI-TECH C Assembly Language
4.3.8.3 PSECT
The PSECT directive declares or resumes a program section. It takes as arguments a name and,
optionally, a comma-separated list of flags. The allowed flags are listed in Table 4.6, below.
Once a psect has been declared it may be resumed later by another PSECT directive, however the
flags need not be repeated.
abs defines the current psect as being absolute, i.e. it is to start at location 0. This does
not mean that this modules contribution to the psect will start at 0, since other modules may
contribute to the same psect.
The bit flag specifies that a psect hold objects that are 1 bit long. Such psects have a scale
value of 8 to indicate that there are 8 addressable units to each byte of storage.
The class flag specifies a class name for this psect. Class names are used to allow local psects
to be referred to by a class name at link time, since they cannot be referred to by their own
name. Class names are also useful where psects need only be positioned anywhere within a
range of addresses rather than at one specific address.
The delta flag defines the size of an addressing unit. In other words, the number of bytes
covered for an increment in the address.
91
HI-TECH C Assembly Language Macro Assembler
A psect defined as global will be combined with other global psects of the same name from
other modules at link time. This is the default behaviour for psects, unless the local flag is
used.
The limit flag specifies a limit on the highest address to which a psect may extend.
A psect defined as local will not be combined with other local psects at link time, even if
there are others with the same name. Where there are two local psects in the one module,
they reference the same psect. A local psect may not have the same name as any global
psect, even one in another module.
A psect defined as ovrld will have the contribution from each module overlaid, rather than
concatenated at runtime. ovrld in combination with abs defines a truly absolute psect, i.e. a
psect within which any symbols defined are absolute.
The pure flag instructs the linker that this psect will not be modified at runtime and may
therefore, for example, be placed in ROM. This flag is of limited usefulness since it depends
on the linker and target system enforcing it.
The reloc flag allows specification of a requirement for alignment of the psect on a particular
boundary, e.g. reloc=100h would specify that this psect must start on an address that is a
multiple of 100h.
The size flag allows a maximum size to be specified for the psect, e.g. size=100h. This will
be checked by the linker after psects have been combined from all modules.
The space flag is used to differentiate areas of memory which have overlapping addresses,
but which are distinct. Psects which are positioned in program memory and data memory may
have a different space value to indicate that the program space address zero, for example,
is a different location to the data memory address zero. Devices which use banked RAM
data memory typically have the same space value as their full addresses (including bank
information) are unique.
The with flag allows a psect to be placed in the same page with a specified psect. For example
with=text will specify that this psect should be placed in the same page as the text psect.
PSECT fred
PSECT bill,size=100h,global
PSECT joh,abs,ovrld,class=CODE,delta=2
92
Macro Assembler HI-TECH C Assembly Language
4.3.8.4 ORG
The ORG directive changes the value of the location counter within the current psect. This means that
the addresses set with ORG are relative to the base address of the psect, which is not determined
until link time.
The much-abused ORG directive does not necessarily move the location counter to the
absolute address you specify as the operand. This directive is rarely needed in programs.
The argument to ORG must be either an absolute value, or a value referencing the current psect. In
either case the current location counter is set to the value determined by the argument. It is not
possible to move the location counter backward. For example:
ORG 100h
will move the location counter to the beginning of the current psect plus 100h. The actual location
will not be known until link time.
In order to use the ORG directive to set the location counter to an absolute value, the directive
must be used from within an absolute, overlaid psect. For example:
PSECT absdata,abs,ovrld
ORG 50h
4.3.8.5 EQU
This pseudo-op defines a symbol and equates its value to an expression. For example
The identifier thomas will be given the value 123h. EQU is legal only when the symbol has not
previously been defined. See also Section 4.3.8.6.
4.3.8.6 SET
This pseudo-op is equivalent to EQU except that allows a symbol to be re-defined. For example
thomas SET 0h
93
HI-TECH C Assembly Language Macro Assembler
4.3.8.7 DB
DB is used to initialize storage as bytes. The argument is a list of expressions, each of which will be
assembled into one byte. Each character of the string will be assembled into one memory location.
Examples:
alabel: DB X,1,2,3,4,
Note that because the size of an address unit in ROM is 2 bytes, the DB pseudo-op will initialise a
word with the upper byte set to zero.
4.3.8.8 DW
DW operates in a similar fashion to DB, except that it assembles expressions into words. Example:
4.3.8.9 DS
This directive reserves, but does not initialize, memory locations. The single argument is the number
of bytes to be reserved. Examples:
4.3.8.10 FNADDR
This directive tells the linker that a function has its address taken, and thus could be called indirectly
through a function pointer. For example
FNADDR _func1
4.3.8.11 FNARG
The directive
FNARG fun1,fun2
tells the linker that evaluation of the arguments to function fun1 involves a call to fun2, thus the
memory argument memory allocated for the two functions should not overlap. For example, the C
function calls
94
Macro Assembler HI-TECH C Assembly Language
FNARG _fred,_bill
thereby telling the linker that bill() is called while evaluating the arguments for a call to fred().
4.3.8.12 FNBREAK
This directive is used to break links in the call graph information. The form of this directive is as
follows:
FNBREAK fun1,fun2
and is automatically generated when the interrupt_level pragma is used. It states that any calls to
fun1 in trees other than the one rooted at fun2 should not be considered when checking for functions
that appear in multiple call graphs. Fun2() is typically intlevel0 or intlevel1 in compiler-generated
code when the interrupt_level pragma is used. Memory for the auto/parameter area for a fun1 will
only be assigned in the tree rooted at fun2.
4.3.8.13 FNCALL
This directive takes the form:
FNCALL fun1,fun2
FNCALL is usually used in compiler generated code. It tells the linker that function fun1 calls func-
tion fun2. This information is used by the linker when performing call graph analysis. If you write
assembler code which calls a C function, use the FNCALL directive to ensure that your assembler
function is taken into account. For example, if you have an assembler routine called _fred which
calls a C routine called foo(), in your assembler code you should write:
FNCALL _fred,_foo
4.3.8.14 FNCONF
The FNCONF directive is used to supply the linker with configuration information for a call graph.
FNCONF is written as follows:
FNCONF psect,auto,args
95
HI-TECH C Assembly Language Macro Assembler
where psect is the psect containing the call graph, auto is the prefix on all auto variable symbol names
and args is the prefix on all function argument symbol names. This directive normally appears in
only one place: the runtime startup code used by C compiler generated code. For the HI-TECH
PICC Compiler the startup routine will include the directive:
FNCONF rbss,?a,?
telling the linker that the call graph is in the rbss psect, auto variable blocks start with ?a and function
argument blocks start with ?.
4.3.8.15 FNINDIR
This directive tells the linker that a function performs an indirect call to another function with a
particular signature (see the SIGNAT directive). The linker must assume worst case that the function
could call any other function which has the same signature and has had its address taken (see the
FNADDR directive). For example, if a function called fred() performs an indirect call to a function
with signature 8249, the compiler will produce the directive:
FNINDIR _fred,8249
4.3.8.16 FNSIZE
The FNSIZE directive informs the linker of the size of the local variable and argument area associ-
ated with a function. These values are used by the linker when building the call graph and assigning
addresses to the variable and argument areas. This directive takes the form:
FNSIZE func,local,args
The named function has a local variable area and argument area as specified, for example
FNSIZE _fred, 10, 5
means the function fred() has 10 bytes of local variables and 5 bytes of arguments. The function
name arguments to any of the call graph associated directives may be local or global. Local functions
are of course defined in the current module, but most be used in the call graph construction in the
same manner as global names.
4.3.8.17 FNROOT
This directive tells the assembler that a function is a root function and thus forms the root of a call
graph. It could either be the C main() function or an interrupt function. For example, the C main
module produce the directive:
FNROOT _main
96
Macro Assembler HI-TECH C Assembly Language
IF ABC
goto aardvark
ELSIF DEF
goto denver
ELSE
goto grapes
ENDIF
In this example, if ABC is non-zero, the first jmp instruction will be assembled but not the second or
third. If ABC is zero and DEF is non-zero, the second jmp will be assembled but the first and third
will not. If both ABC and DEF are zero, the third jmp will be assembled. Conditional assembly blocks
may be nested.
;macro: movlf
;args: arg1 - the literal value to load
; arg2 - the NAME of the source variable
;descr: Move a literal value into a nominated file register:
movlf MACRO arg1,arg2
movlw arg1
movwf arg2 mod 080h
ENDM
When used, this macro will expand to the 2 instructions in the body of the macro, with the formal
parameters substituted by the arguments. Thus:
97
HI-TECH C Assembly Language Macro Assembler
movlf 2,tempvar
expands to:
movlw 2
movwf tempvar mod 080h
A point to note in the above example: the & character is used to permit the concatenation of macro
parameters with other text, but is removed in the actual expansion.
A comment may be suppressed within the expansion of a macro (thus saving space in the macro
storage) by opening the comment with a double semicolon, ;;.
When invoking a macro, the argument list must be comma-separated. If it is desired to include a
comma (or other delimiter such as a space) in an argument then angle brackets < and > may be used
to quote the argument. In addition the exclamation mark, ! may be used to quote a single character.
The character immediately following the exclamation mark will be passed into the macro argument
even if it is normally a comment indicator.
If an argument is preceded by a percent sign %, that argument will be evaluated as an expression
and passed as a decimal number, rather than as a string. This is useful if evaluation of the argument
inside the macro body would yield a different result.
The nul operator may be used within a macro to test a macro argument, for example:
IF nul arg3 ; argument was not supplied.
...
ELSE ; argument was supplied
...
ENDIF
By default, the assembly list file will show macro in an unexpanded format, i.e. as the macro was
invoked. Expansion of the macro in the listing file can be shown by using the EXPAND assembler
control, see Section 4.3.9.2,
4.3.8.20 LOCAL
The LOCAL directive allows unique labels to be defined for each expansion of a given macro. Any
symbols listed after the LOCAL directive will have a unique assembler generated symbol substituted
for them when the macro is expanded. For example:
down MACRO count
LOCAL more
more: decfsz count
goto more
ENDM
98
Macro Assembler HI-TECH C Assembly Language
when expanded will include a unique assembler generated label in place of more. For example:
down foobar
expands to:
4.3.8.21 ALIGN
The ALIGN directive aligns whatever is following, data storage or code etc., to the specified boundary
in the psect in which the directive is found. The boundary is specified by a number following the
directive and it specifies a number of bytes. For example, to align output to a 2 byte (even) address
within a psect, the following could be used.
ALIGN 2
Note, however, that what follows will only begin on an even absolute address if the psect begins on
an even address. The ALIGN directive can also be used to ensure that a psects length is a multiple
of a certain number. For example, if the above ALIGN directive was placed at the end of a psect, the
psect would have a length that was always an even number of bytes long.
4.3.8.22 REPT
The REPT directive temporarily defines an unnamed macro, then expands it a number of times as
determined by its argument. For example:
REPT 3
addwf fred,w
ENDM
will expand to
addwf fred,w
addwf fred,w
addwf fred,w
99
HI-TECH C Assembly Language Macro Assembler
PSECT idata_0
IRP number,4865h,6C6Ch,6F00h
DW number
ENDM
PSECT text0
PSECT idata_0
DW 4865h
DW 6C6Ch
DW 6F00h
PSECT text0
Note that you can use local labels and angle brackets in the same manner as with conventional
macros.
The IRPC directive is similar, except it substitutes one character at a time from a string of non-
space characters.
For example:
PSECT romdata,class=CODE,delta=2
IRPC char,ABC
DB char
ENDM
PSECT text
PSECT romdata,class=CODE,delta=2
DB A
DB B
DB C
PSECT text
100
Macro Assembler HI-TECH C Assembly Language
4.3.8.24 PROCESSOR
The output of the assembler may vary depending on the target device. The device name is typically
set using the --CHIP option to the command-line driver PICC, see Section 2.4.20, or using the
assembler -P option, see Table 4.1, but can also be set with this directive, e.g.
PROCESSOR 16F877
4.3.8.25 SIGNAT
This directive is used to associate a 16-bit signature value with a label. At link time the linker checks
that all signatures defined for a particular label are the same and produces an error if they are not. The
SIGNAT directive is used by the HI-TECH C compiler to enforce link time checking of C function
prototypes and calling conventions.
Use the SIGNAT directive if you want to write assembly language routines which are called from
C. For example:
SIGNAT _fred,8192
will associate the signature value 8192 with the symbol _fred. If a different signature value for
_fred is present in any object file, the linker will report an error.
OPT EXPAND
A list of keywords is given in Table 4.7, and each is described further below.
4.3.9.1 COND
Any conditional code will be included in the listing output. See also the NOCOND control in Section
4.3.9.5.
4.3.9.2 EXPAND
When EXPAND is in effect, the code generated by macro expansions will appear in the listing output.
See also the NOEXPAND control in Section 4.3.9.6.
101
HI-TECH C Assembly Language Macro Assembler
4.3.9.3 INCLUDE
This control causes the file specified by pathname to be textually included at that point in the
assembly file. The INCLUDE control must be the last control keyword on the line, for example:
The driver does not pass any search paths to the assembler, so if the include file is not located in the
working directory, the pathname must specify the exact location.
See also the driver option -P in Section 2.4.11 which forces the C preprocessor to preprocess
assembly file, thus allowing use of preprocessor directives, such as #include (see Section 3.12.1).
4.3.9.4 LIST
If the listing was previously turned off using the NOLIST control, the LIST control on its own will
turn the listing on.
Alternatively, the LIST control may includes options to control the assembly and the listing. The
options are listed in Table 4.8.
See also the NOLIST control in Section 4.3.9.7.
4.3.9.5 NOCOND
Using this control will prevent conditional code from being included in the listing output. See also
the COND control in Section 4.3.9.1.
102
Macro Assembler HI-TECH C Assembly Language
4.3.9.6 NOEXPAND
NOEXPAND disables macro expansion in the listing file. The macro call will be listed instead. See
also the EXPAND control in Section 4.3.9.2. Assembly macro are discussed in Section 4.3.8.19.
4.3.9.7 NOLIST
This control turns the listing output off from this point onward. See also the LIST control in Section
4.3.9.4.
4.3.9.8 NOXREF
NOXREF will disable generation of the raw cross reference file. See also the XREF control in Section
4.3.9.13.
4.3.9.9 PAGE
PAGE causes a new page to be started in the listing output. A Control-L (form feed) character will
also cause a new page when encountered in the source.
4.3.9.10 SPACE
The SPACE control will place a number of blank lines in the listing output as specified by its param-
eter.
4.3.9.11 SUBTITLE
SUBTITLE defines a subtitle to appear at the top of every listing page, but under the title. The string
should be enclosed in single or double quotes. See also the TITLE control in Section 4.3.9.12.
103
HI-TECH C Assembly Language Macro Assembler
4.3.9.12 TITLE
This control keyword defines a title to appear at the top of every listing page. The string should be
enclosed in single or double quotes. See also the SUBTITLE control in Section 4.3.9.11.
4.3.9.13 XREF
XREF is equivalent to the driver command line option --CR (see Section 2.4.23). It causes the assem-
bler to produce a raw cross reference file. The utility CREF should be used to actually generate the
formatted cross-reference listing.
104
Chapter 5
5.1 Introduction
HI-TECH C incorporates a relocating assembler and linker to permit separate compilation of C
source files. This means that a program may be divided into several source files, each of which
may be kept to a manageable size for ease of editing and compilation, then each source file may be
compiled separately and finally all the object files linked together into a single executable program.
This chapter describes the theory behind and the usage of the linker. Note however that in most
instances it will not be necessary to use the linker directly, as the compiler driver will automatically
invoke the linker with all necessary arguments. Using the linker directly is not simple, and should
be attempted only by those with a sound knowledge of the compiler and linking in general.
If it is absolutely necessary to use the linker directly, the best way to start is to copy the linker
arguments constructed by the compiler driver, and modify them as appropriate. This will ensure that
the necessary startup module and arguments are present.
Note also that the linker supplied with HI-TECH C is generic to a wide variety of compilers for
several different processors. Not all features described in this chapter are applicable to all compilers.
105
Program Sections Linker and Utilities
relocation by the ultimate value of a global symbol, or relocation by psect, i.e. relocation by the
base address of a particular section of code, for example the section of code containing the actual
executable instructions.
106
Linker and Utilities Link and load addresses
as static. These symbols may be referred to by modules other than the one in which they are
defined. It is the linkers job to match up the definition of a global symbol with the references to it.
Other symbols (local symbols) are passed through the linker to the symbol file, but are not otherwise
processed by the linker.
107
Compiled Stack Operation Linker and Utilities
Each function in the call graph is allocated an auto/parameter block (APB) for its parameter,
auto and temporary variables. Temporary variables act just like auto variables. Local variables
which are qualified static are not part of this block. For situations where a compiled stack is used,
the linker performs additional operations to minimise the memory consumed by the program by
overlaying each functions APB where possible.
In assembly code variables within a functions APB are referenced via special symbols, which
marks the start of the auto or parameter area in the block, and an offset. The symbol used to represent
the base address of the parameter area within the functions APB is the concatenation of ? and the
assembler name of the function. The symbol used to represent the base address of the auto area
within the functions APB is the concatenation of ?a, in the case of Standard version compilers, or
??, in the case of Pro version compilers, and the assembler name of the function.
For example, a function called foo, for example, will use the assembly symbol ?_foo as the
base address for all its parameters variables that have been allocated memory, and either ?a_foo
(Standard) or ??_foo (Pro) as the base address for auto variables which the function defines. So the
first two-byte auto variable might be referenced in Pro version compiler assembly code as ??_foo;
the second auto variable as ??_foo+2, etc. Note that some parameters may be passed in registers,
and may not have memory allocated to them in the parameter area of the APB.
The linker allocates memory for each functions APB, based on how that function is used in a
program. In particular, the linker determines which functions are, or may be, active at the same
time. If one function calls another, then both are active at the same time. To this end, a call graph
is created from information in the object files being linker. See Section 5.11.1 for information on
reading the call graph displayed in the map file. This information is directly related to the FNCALL
assembler directive (see Section 4.3.8.13 for more information) which the code generator places in
the assembler output whenever a C function calls another. Hand-written assembler code should also
contain these directives, if required. Information regarding the size of the auto and parameter areas
within in functions APB is specified by the FNSIZE assembler directive (see Section 4.3.8.16).
shows that the function input is called to determine the second parameter to the function output.
This information is very important as it indicates areas of the code that must be considered carefully,
lest the code fail due to re-entrancy related issues.
A re-entrant call is typically considered to be the situation in which a function is called and
executed while another instance of the same function is also actively executing. For a compiled
108
Linker and Utilities Compiled Stack Operation
stack program, a function must be considered active as soon as its parameter area has been modified
in preparation for a call, even though code in that function is not yet being executed and a call to
that function has not been made. This is particularly import with functions that accept more than
one parameter as the ANSI standard does not dictate the order in which function parameters must be
evaluated.
Such a condition is best illustrated by an example, which is shown in the following tutorial.
T UTRIAL
The linker indicates in the call graph those functions that may have been called to determine param-
eter values to other functions. See Section 5.11.1 for information on how this is displayed in the map
file.
109
Map Files Linker and Utilities
5.8.1 Generation
TM
If compilation is being performed via HI-TIDE a map file is generated by default without you
having to adjust the compiler options. If you are using the driver from the command line then youll
need to use the -M option, see Section 2.4.8.
Map files are produced by the linker. If the compilation process is stopped before the linker is
executed, then no map file is produced. The linker will still produce a map file even if it encounters
errors, which will allow you to use this file to track down the cause of the errors. However, if the
linker ultimately reports too many errors then it did not run to completion, and the map file will
be either not created or not complete. You can use the --ERRORS option on the command line, or as
an alternate MPLAB IDE setting, to increase the number of errors before the compiler applications
give up. See Section 2.4.27 for more information on this option.
110
Linker and Utilities Map Files
5.8.2 Contents
The sections in the map file, in order of appearance, are as follows:
The version number of the object code in the first file linked;
Optionally (dependent on the processor and compiler options selected), the call graph infor-
mation;
A segment summary;
Portions of an example map file, along with explanatory text, are shown in the following sections.
111
Map Files Linker and Utilities
The Linker command line shown is the entire list of options and files that were passed to the linker
for the build recorded by this map file. Remember, these are linker options and not command-line
driver options. Typically the first options relate to general execution of the linker: path and file
names for various input and output support files; and the chip type etc. These are followed by the
memory allocation options, e.g. -A and -p. Last are the input object and library files that will be
linked together.
The linker command line should be used to confirm that driver options that control the link step
have been specified correctly, and at the correct time. It is particularly useful when using the driver
-L- option, see Section 2.4.7.
T UTRIAL
112
Linker and Utilities Map Files
The functions in the program that are root nodes marking the top of a call tree, and which
are not directly called;
The functions that the linker deemed were called, or may have been called, during program
execution;
The programs hierarchy of function calls;
The size of the auto and parameter areas within each functions APB;
The offset of each functions APB within the programs auto/parameter psect;
Which functions APBs are consuming memory not overlapped by the APB of any other
function;
Which functions are called indirectly;
Which functions are called as part of a parameter expression for another function;
Estimated call tree depth.
Call graph:
*_main size 0,4 offset 0
* _byteconv size 0,17 offset 4
float size 3,7 offset 21
ldiv size 8,6 offset 21
_crv ARG size 0 offset 21
_crv size 1 offset 21
ldiv size 8,6 offset 21
113
Map Files Linker and Utilities
114
Linker and Utilities Map Files
int test(void) {
int a = 0;
if(a)
foo();
else
bar();
}
115
Map Files Linker and Utilities
If the ARG flag appears after a functions name, this implies that the call to this ARG function
involves other function calls to determine the parameter values for this function. For example, if
input and output are both functions that take two int parameters and and both return an int, the
following:
shows that the function input is called to determine the second parameter to the function output.
The ARG functions name is listed again under the line which actually shows the ARG flag, and
any functions this function calls appear here, indented in the usual way. Under this is listed every
function (regardless of its depth in the call tree) that could be called to determine a parameter value
to the ARG function throughout the program. If any of these functions call other functions, they
also list called functions below, indented in the usual way. For example the following annotated call
graph snippet illustrates the ARG function one.
After each tree in call tree, there is an indication of the maximum call depth that might be realised
by that tree. This may be used as a guide to the stack usage of the program. No definitive value can
be given for the programs total stack usage for several reasons:
Certain parts of the call tree may never be reached, reducing that trees stack usage;
The contribution of interrupt (or other) trees to the tree associated with the main function
cannot be determined as the point in mains call tree at which the interrupt (or other function
invocation) will occur cannot be known;
Any additional stack usage by functions, particularly interrupt functions, cannot be known;
and
The assembler optimizer may have replaced function calls with jumps to functions, reducing
that trees stack usage.
116
Linker and Utilities Map Files
T UTRIAL
I NTERPRETING A P RO COMPILER CALL GRAPH The graph graph shown above in-
dicates that the program compiled consists of two call trees rooted at the functions:
main, which can have up 3 levels of stack used, and intlevel1, which can use up to
two levels of stack. In the example above, the symbol _main is associated with the
function main, and intlevel1 associated with an interrupt function (with interrupt
level 1).
Here, the function main takes no parameters and defines 4 bytes of auto variables. The
total size of the APB for main is 4, and this was placed at an offset of 0 in the programs
auto/parameter psect. The function main may call a function called init. This function
also uses a total of 4 bytes of auto variables. The function main is still active when
init is active so their APBs must occupy distinct memory. The block for init follows
immediately after that of mains at address offset 4. The function init does not call any
other functions.
The main may also call the function byteconv. This function defines a total of 17 bytes
of auto variables. It is called when main is still active (NB main will always be active),
but it is never active at the same time as init is active, so its APB can overlap with that
of init and is placed at offset 4 within the auto/parameter psect.
The function byteconv may call several functions: float, ldiv, crv and srv. (Any
function name that does not start with an underscore must be an assembly routine.
The routine float and ldiv in this case relating to floating point and long division
library routines.) All these functions have their APB placed at the same offset in the
auto/parameter psect. Of these functions, srv also may call convert.
The call to crv from byteconv indicates that other functions might be called to obtain
crvs parameter values. Those other functions are listed in a flattened call list below
the ARG function line which shows every possible function that might be called, re-
gardless of call depth. The functions which might be called are: ldiv, convert and
srv. The function srv, which also calls convert still indicates this fact by also listing
convert below and indented in the more conventional call graph format. The two lines
of C code that produced this outcome were:
T UTRIAL
if(crv((my_long%10)) != 5) // ...
if(crv(srv(8)) != 6) // ...
where crv accepts one char parameter and returns a char. The call to srv is obvious;
the other call come from the modulus operator, calling ldiv.
117
Map Files Linker and Utilities
The other call tree rooted at intlevel1 relates to the interrupt function. intlevel1
is not a real function, but is used to represent the interrupt level associated with the
interrupt function. There is no call from intlevel1 to the function isr and no stack
usage. Note that an additional level of call depth is indicated for interrupt functions.
This is used to mark the place of the return address of the stack. The selected device
may use a differing number of stack locations when interrupts occur and this needs to
be factored into any stack calculations.
Notice that the interrupt function isr calls a function called i1ldiv. This is a du-
plicate of the ldiv routine that is callable by functions under the intlevel1 call tree.
Having duplicate routines means that these implicitly called assembly library routines
can safely be called from both code under the main call tree and code under the interrupt
tree. Pro compilers will have as many duplicates of these routines as there are interrupt
levels.
The call graph shows that the functions: main, byteconv, srv, convert, isr and
i1ldiv are all consuming APB memory that does not fully overlap with that of other
functions. Reducing the auto/parameter memory requirements for these functions will
reduce the programs memory requirements. The call graph reveals that 82 bytes of
memory are required by the program for autos and parameters, but that only 58 are re-
served and used by the program. The difference shows the amount of memory saved by
overlapping of these blocks by the linker.
Under this on the far left is a list of object files. These object files include both files generated from
source modules and those that were extracted from object library files. In the case of those from
library files, the name of the library file is printed before the object file list.
This section shows all the psects (under the Name column) that were linked into the program
from each object file, and information regarding that psect. This only deals with object files linked
by the linker. P-code modules derived from p-code library files are handled by the code generator,
and do not appear in the map file.
The Link address indicates the address at which this psect will be located when the program
is running. (The Load address is also shown for those psects that may reside in the HEX file at
118
Linker and Utilities Map Files
a different location and which are mapped before program execution.) The Length of the psect is
shown (in units suitable for that psect). The Selector is less commonly used, but the Space field is
important as it indicates the memory space in which the psect was placed. For Harvard architecture
machines, with separate memory spaces, this field must be used in conjunction with the address to
specify an exact storage location. The Scale of a psect indicates the number of address units per byte
this is left blank if the scale is 1 and typically this will show 8 for psects that hold bit objects.
The Load address of psects that hold bits is used to display the link address converted into units of
bytes, rather than the load address.
T UTRIAL
The list of files, that make up the program, indicated in this section of the map file will typically
consist of one or more object files derived from input source code. The map file produced by Pro
compilers will show one object file derived from all C source modules, however Standard version
compilers will show one object file per C source module.
In addition, there will typically be the runtime startup module. The runtime startup code is
precompiled into an object file, in the case of Standard version compilers, or is a compiler-written
assembler source file, which is then compiled along with the remainder of the program. In either
case, an object file module will be listed in this section, along with those psects which it defines.
119
Map Files Linker and Utilities
If the startup module is not being deleted after compilation (see the --RUNTIME option in Section
2.4.45) then the module name will be startup.obj, otherwise this module will have a system-
dependent temporary file name, stored in a system-dependent location.
Modules derived from library files area also shown in this list. The name of the library file is
printed as a header, followed by a list of the modules that contributed to the output. Only mod-
ules that define symbols that are referenced are included in the program output. For example, the
following:
indicates that both the i1aldiv.obj and aldiv.obj modules were linked in from the library file
pic86l-c.lib.
Underneath the library file contributions, there may be a label COMMON. This shows the con-
tribution to the program from program-wide psects, in particular that used by the compiled stack
auto/parameter area.
This information in this section of the map file can be used to observe several details;
To confirm that a module is making a contribution to the output file by ensuring that the
module appears in the module list;
For cases where a user-defined routine, with the same name as a library routine, is present in
the programs source file list, to confirm that the user-defined routine was linked in preference
to the library routine.
Under this are the class names followed by those psects which belong to this class. These psects are
the same as those listed by module in the above section; there is no new information contained in
this section.
120
Linker and Utilities Map Files
The name of a segment is derived from the psect in the contiguous group with the lowest link address.
This can lead to confusion with the psect with the same name. Do not read psect information from
this section of the map file.
Typically this section of the map file can be ignored by the user.
and is followed by a list of classes and the memory still available in each class defined in the program.
If there is more than one range in a class, each range is printed on a separate line. Any paging
boundaries within a class are ignored and not displayed in any way.
Note that classes often define memory that is also covered by other classes, thus the total free
space in a memory area is not simply the addition of the size of all the ranges indicated. For example
if there are two classes the cover the RAM memory RAM and BANKRAM and the first 100h
out of 500h bytes are used, then both will indicate 000100-0004FF as the unused memory.
Symbol Table
and is followed by two columns in which the symbols are alphabetically listed. As always with the
linker, any C derived symbol is shown with its assembler equivalent symbol name. The symbols
listed in this table are:
121
Operation Linker and Utilities
Assembly symbols are made global via the GLOBAL assembler directive, see Section 4.3.8.1 for more
information. linker-defined symbols act like EQU directives, however they are defined by the linker
during the link process, and no definition for them will appear in any source or intermediate file.
Non-static C functions, and non-auto and non-static C variables directly map to assembly
labels. The name of the label will be the C identifier with a leading underscore character. The
linker-defined symbols include symbols used to mark the bounds of psects. See Section 3.13.3. The
symbols used to mark the base address of each functions auto and parameter block are also shown.
Although these symbols are used to represent the local autos and parameters of a function, they
themselves must be globally accessible to allow each calling function to load their contents. The
C auto and parameter variable identifiers are local symbols that only have scope in the function in
which they are defined.
Each symbol is shown with the psect in which they are placed, and the address which the symbol
has been assigned. There is no information encoded into a symbol to indicate whether it represents
code or variables, nor in which memory space it resides.
If the psect of a symbol is shown as (abs), this implies that the symbol is not directly associated
with a psect as is the case with absolute C variables. Linker-defined symbols showing this as the
psect name may be symbols that have never been used throughout the program, or relate to symbols
that are not directly associated with a psect.
Note that a symbol table is also shown in each assembler list file. (See Section 2.4.17 for in-
formation on generating these files.) These differ to that shown in the map file in that they list
all symbols, whether they be of global or local scope, and they only list the symbols used in the
module(s) associated with that list file.
5.9 Operation
A command to the linker takes the following form:
Options is zero or more linker options, each of which modifies the behaviour of the linker in some
way. Files is one or more object files, and zero or more library names. The options recognised by
the linker are listed in Table 5.1 and discussed in the following paragraphs.
122
Linker and Utilities Operation
Option Effect
-8 Use 8086 style segment:offset address form
-Aclass=low-high,... Specify address ranges for a class
-Cx Call graph options
-Cpsect=class Specify a class name for a global psect
-Cbaseaddr Produce binary output file based at baseaddr
-Dclass=delta Specify a class delta value
-Dsymfile Produce old-style symbol file
-Eerrfile Write error messages to errfile
-F Produce .obj file with only symbol records
-Gspec Specify calculation for segment selectors
-Hsymfile Generate symbol file
-H+symfile Generate enhanced symbol file
-I Ignore undefined symbols
-Jnum Set maximum number of errors before aborting
-K Prevent overlaying function parameter and auto areas
-L Preserve relocation items in .obj file
-LM Preserve segment relocation items in .obj file
-N Sort symbol table in map file by address order
-Nc Sort symbol table in map file by class address order
-Ns Sort symbol table in map file by space address order
-Mmapfile Generate a link map in the named file
-Ooutfile Specify name of output file
-Pspec Specify psect addresses and ordering
-Qprocessor Specify the processor type (for cosmetic reasons only)
-S Inhibit listing of symbols in symbol file
-Sclass=limit[,bound] Specify address limit, and start boundary for a class of psects
-Usymbol Pre-enter symbol in table as undefined
-Vavmap Use file avmap to generate an Avocet format symbol file
-Wwarnlev Set warning level (-9 to 9)
-Wwidth Set map file width (>=10)
-X Remove any local symbols from the symbol file
-Z Remove trivial local symbols from the symbol file
123
Operation Linker and Utilities
5.9.2 -Aclass=low-high,...
Normally psects are linked according to the information given to a -P option (see below) but some-
times it is desired to have a class of psects linked into more than one non-contiguous address range.
This option allows a number of address ranges to be specified for a class. For example:
-ACODE=1020h-7FFEh,8000h-BFFEh
specifies that the class CODE is to be linked into the given address ranges. Note that a contribution
to a psect from one module cannot be split, but the linker will attempt to pack each block from each
module into the address ranges, starting with the first specified.
Where there are a number of identical, contiguous address ranges, they may be specified with a
repeat count, e.g.
-ACODE=0-FFFFhx16
specifies that there are 16 contiguous ranges each 64k bytes in size, starting from zero. Even though
the ranges are contiguous, no code will straddle a 64k boundary. The repeat count is specified as the
character x or * after a range, followed by a count.
5.9.3 -Cx
These options allow control over the call graph information which may be included in the map file
produced by the linker. The -CN option removes the call graph information from the map file. The
-CC option only include the critical paths of the call graph. A function call that is marked with a * in
a full call graph is on a critical path and only these calls are included when the -CC option is used.
A call graph is only produced for processors and memory models that use a compiled stack.
5.9.4 -Cpsect=class
This option will allow a psect to be associated with a specific class. Normally this is not required on
the command line since classes are specified in object files.
124
Linker and Utilities Operation
5.9.5 -Dclass=delta
This option allows the delta value for psects that are members of the specified class to be defined.
The delta value should be a number and represents the number of bytes per addressable unit of
objects within the psects. Most psects do not need this option as they are defined with a delta value.
5.9.6 -Dsymfile
Use this option to produce an old-style symbol file. An old-style symbol file is an ASCII file, where
each line has the link address of the symbol followed by the symbol name.
5.9.7 -Eerrfile
Error messages from the linker are written to standard error (file handle 2). Under DOS there is no
convenient way to redirect this to a file (the compiler drivers will redirect standard error if standard
output is redirected). This option will make the linker write all error messages to the specified file
instead of the screen, which is the default standard error destination.
5.9.8 -F
Normally the linker will produce an object file that contains both program code and data bytes, and
symbol information. Sometimes it is desired to produce a symbol-only object file that can be used
again in a subsequent linker run to supply symbol values. The -F option will suppress data and code
bytes from the output file, leaving only the symbol records.
This option can be used when producing more than one hex file for situations where the program
is contained in different memory devices located at different addresses. The files for one device are
compiled using this linker option to produce a symbol-only object file; this is then linked with the
files for the other device. The process can then be repeated for the other files and device.
5.9.9 -Gspec
When linking programs using segmented, or bank-switched psects, there are two ways the linker
can assign segment addresses, or selectors, to each segment. A segment is defined as a contiguous
group of psects where each psect in sequence has both its link and load address concatenated with
the previous psect in the group. The segment address or selector for the segment is the value derived
when a segment type relocation is processed by the linker.
By default the segment selector will be generated by dividing the base load address of the seg-
ment by the relocation quantum of the segment, which is based on the reloc= flag value given to
psects at the assembler level. This is appropriate for 8086 real mode code, but not for protected mode
125
Operation Linker and Utilities
or some bank-switched arrangements. In this instance the -G option is used to specify a method for
calculating the segment selector. The argument to -G is a string similar to:
A/10h-4h
where A represents the load address of the segment and / represents division. This means "Take the
load address of the psect, divide by 10 hex, then subtract 4". This form can be modified by substi-
tuting N for A, * for / (to represent multiplication), and adding rather than subtracting a constant.
The token N is replaced by the ordinal number of the segment, which is allocated by the linker. For
example:
N*8+4
means "take the segment number, multiply by 8 then add 4". The result is the segment selector. This
particular example would allocate segment selectors in the sequence 4, 12, 20, ... for the number
of segments defined. This would be appropriate when compiling for 80286 protected mode, where
these selectors would represent LDT entries.
5.9.10 -Hsymfile
This option will instruct the linker to generate a symbol file. The optional argument symfile
specifies a file to receive the symbol file. The default file name is l.sym.
5.9.11 -H+symfile
This option will instruct the linker to generate an enhanced symbol file, which provides, in addition
to the standard symbol file, class names associated with each symbol and a segments section which
lists each class name and the range of memory it occupies. This format is recommended if the code
is to be run in conjunction with a debugger. The optional argument symfile specifies a file to
receive the symbol file. The default file name is l.sym.
5.9.12 -Jerrcount
The linker will stop processing object files after a certain number of errors (other than warnings).
The default number is 10, but the -J option allows this to be altered.
5.9.13 -K
For compilers that use a compiled stack, the linker will try and overlay function auto and parameter
areas in an attempt to reduce the total amount of RAM required. For debugging purposes, this feature
can be disabled with this option.
126
Linker and Utilities Operation
5.9.14 -I
Usually failure to resolve a reference to an undefined symbol is a fatal error. Use of this option will
cause undefined symbols to be treated as warnings instead.
5.9.15 -L
When the linker produces an output file it does not usually preserve any relocation information, since
the file is now absolute. In some circumstances a further "relocation" of the program will be done at
load time, e.g. when running a .exe file under DOS or a .prg file under TOS. This requires that some
information about what addresses require relocation is preserved in the object (and subsequently the
executable) file. The -L option will generate in the output file one null relocation record for each
relocation record in the input.
5.9.16 -LM
Similar to the above option, this preserves relocation records in the output file, but only segment
relocations. This is used particularly for generating .exe files to run under DOS.
5.9.17 -Mmapfile
This option causes the linker to generate a link map in the named file, or on the standard output if
the file name is omitted. The format of the map file is illustrated in Section 5.11.
5.9.19 -Ooutfile
This option allows specification of an output file name for the linker. The default output file name is
l.obj. Use of this option will override the default.
5.9.20 -Pspec
Psects are linked together and assigned addresses based on information supplied to the linker via -P
options. The argument to the -P option consists basically of comma-separated sequences thus:
127
Operation Linker and Utilities
-Ppsect=lnkaddr+min/ldaddr+min,psect=lnkaddr/ldaddr, ...
There are several variations, but essentially each psect is listed with its desired link and load ad-
dresses, and a minimum value. All values may be omitted, in which case a default will apply,
depending on previous values.
The minimum value, min, is preceded by a + sign, if present. It sets a minimum value for the
link or load address. The address will be calculated as described below, but if it is less than the
minimum then it will be set equal to the minimum.
The link and load addresses are either numbers as described above, or the names of other psects
or classes, or special tokens. If the link address is a negative number, the psect is linked in reverse
order with the top of the psect appearing at the specified address minus one. Psects following a
negative address will be placed before the first psect in memory. If a link address is omitted, the
psects link address will be derived from the top of the previous psect, e.g.
-Ptext=100h,data,bss
In this example the text psect is linked at 100 hex (its load address defaults to the same). The data
psect will be linked (and loaded) at an address which is 100 hex plus the length of the text psect,
rounded up as necessary if the data psect has a reloc= value associated with it. Similarly, the bss
psect will concatenate with the data psect. Again:
-Ptext=-100h,data,bss
will link in ascending order bss, data then text with the top of text appearing at address 0ffh.
If the load address is omitted entirely, it defaults to the same as the link address. If the slash /
character is supplied, but no address is supplied after it, the load address will concatenate with the
previous psect, e.g.
-Ptext=0,data=0/,bss
will cause both text and data to have a link address of zero, text will have a load address of 0, and
data will have a load address starting after the end of text. The bss psect will concatenate with data
for both link and load addresses.
The load address may be replaced with a dot . character. This tells the linker to set the load
address of this psect to the same as its link address. The link or load address may also be the name of
another (already linked) psect. This will explicitly concatenate the current psect with the previously
specified psect, e.g.
-Ptext=0,data=8000h/,bss/. -Pnvram=bss,heap
128
Linker and Utilities Operation
This example shows text at zero, data linked at 8000h but loaded after text, bss is linked and
loaded at 8000h plus the size of data, and nvram and heap are concatenated with bss. Note here
the use of two -P options. Multiple -P options are processed in order.
If -A options have been used to specify address ranges for a class then this class name may be
used in place of a link or load address, and space will be found in one of the address ranges. For
example:
-ACODE=8000h-BFFEh,E000h-FFFEh
-Pdata=C000h/CODE
This will link data at C000h, but find space to load it in the address ranges associated with CODE.
If no sufficiently large space is available, an error will result. Note that in this case the data psect
will still be assembled into one contiguous block, whereas other psects in the class CODE will be
distributed into the address ranges wherever they will fit. This means that if there are two or more
psects in class CODE, they may be intermixed in the address ranges.
Any psects allocated by a -P option will have their load address range subtracted from any
address ranges specified with the -A option. This allows a range to be specified with the -A option
without knowing in advance how much of the lower part of the range, for example, will be required
for other psects.
5.9.21 -Qprocessor
This option allows a processor type to be specified. This is purely for information placed in the map
file. The argument to this option is a string describing the processor.
5.9.22 -S
This option prevents symbol information relating from being included in the symbol file produced
by the linker. Segment information is still included.
-SCODE=400h
Note that to set an upper limit to a psect, this must be set in assembler code (with a limit= flag on
a PSECT directive).
129
Operation Linker and Utilities
If the bound (boundary) argument is used, the class of psects will start on a multiple of the bound
address. This example places the FARCODE class of psects at a multiple of 1000h, but with an upper
address limit of 6000h:
-SFARCODE=6000h,1000h
5.9.24 -Usymbol
This option will enter the specified symbol into the linkers symbol table as an undefined symbol.
This is useful for linking entirely from libraries, or for linking a module from a library where the
ordering has been arranged so that by default a later module will be linked.
5.9.25 -Vavmap
To produce an Avocet format symbol file, the linker needs to be given a map file to allow it to
map psect names to Avocet memory identifiers. The avmap file will normally be supplied with the
compiler, or created automatically by the compiler driver as required.
5.9.26 -Wnum
The -W option can be used to set the warning level, in the range -9 to 9, or the width of the map file,
for values of num >= 10.
-W9 will suppress all warning messages. -W0 is the default. Setting the warning level to -9 (-W-9)
will give the most comprehensive warning messages.
5.9.27 -X
Local symbols can be suppressed from a symbol file with this option. Global symbols will always
appear in the symbol file.
5.9.28 -Z
Some local symbols are compiler generated and not of interest in debugging. This option will
suppress from the symbol file all local symbols that have the form of a single alphabetic character,
followed by a digit string. The set of letters that can start a trivial symbol is currently "klfLSu".
The -Z option will strip any local symbols starting with one of these letters, and followed by a digit
string.
130
Linker and Utilities Invoking the Linker
-Z -OX.OBJ -MX.MAP \
-Ptext=0,data=0/,bss,nvram=bss/. \
X.OBJ Y.OBJ Z.OBJ C:\HT-Z80\LIB\Z80-SC.LIB
hlink @x.lnk
hlink < x.lnk
131
Map Files Linker and Utilities
Call graph:
*_main size 0,0 offset 0
_init size 2,3 offset 0
_ports size 2,2 offset 5
* _sprintf size 5,10 offset 0
* _putch
132
Linker and Utilities Map Files
INDIRECT 4194
INDIRECT 4194
_function_2 size 2,2 offset 0
_function size 2,2 offset 5
*_isr->_incr size 2,0 offset 15
The graph shows the functions called and the memory usage (RAM) of the functions for their own
local objects. In the example above, the symbol _main is associated with the function main(). It is
shown at the far left of the call graph. This indicates that it is the root of a call tree. The run-time
code has the FNROOT assembler directive that specifies this. The size field after the name indicates
the number of parameters and auto variables, respectively. Here, main() takes no parameters and
defines no auto variables. The offset field is the offset at which the functions parameters and auto
variables have been placed from the beginning of the area of memory used for this purpose. The
run-time code contains a FNCONF directive which tells the compiler in which psect parameters and
auto variables should reside. This memory will be shown in the map file under the name COMMON.
Main() calls a function called init(). This function uses a total of two bytes of parameters
(it may be two objects of type char or one int; that is not important) and has three bytes of auto
variables. These figures are the total of bytes of memory consumed by the function. If the function
was passed a two-byte int, but that was done via a register, then the two bytes would not be included
in this total. Since main() did not use any of the local object memory, the offset of init()s memory
is still at 0.
The function init() itself calls another function called ports(). This function uses two bytes
of parameters and another two bytes of auto variables. Since ports() is called by init(), its
local variables cannot be overlapped with those of init()s, so the offset is 5, which means that
ports()s local objects were placed immediately after those of init()s.
The function main also calls sprintf(). Since the function sprintf() is not active at the same
time as init() or ports(), their local objects can be overlapped and the offset is hence set to 0.
Sprintf() calls a function putch(), but this function uses no memory for parameters (the char
passed as argument is apparently done so via a register) or locals, so the size and offset are zero and
are not printed.
Main() also calls another function indirectly using a function pointer. This is indicated by the
two INDIRECT entries in the graph. The number following is the signature value of functions that
could potentially be called by the indirect call. This number is calculated from the parameters and
return type of the functions the pointer can indirectly call. The names of any functions that have this
signature value are listed underneath the INDIRECT entries. Their inclusion does not mean that they
were called (there is no way to determine that), but that they could potentially be called.
The last line shows another function whose name is at the far left of the call graph. This implies
that this is the root of another call graph tree. This is an interrupt function which is not called by any
code, but which is automatically invoked when an enabled interrupt occurs. This interrupt routine
133
Librarian Linker and Utilities
calls the function incr(), which is shown shorthand in the graph by the -> symbol followed by the
called functions name instead of having that function shown indented on the following line. This is
done whenever the calling function does not takes parameters, nor defines any variables.
Those lines in the graph which are starred with * are those functions which are on a critical
path in terms of RAM usage. For example, in the above, (main() is a trivial example) consider
the function sprintf(). This uses a large amount of local memory and if you could somehow
rewrite it so that it used less local memory, it would reduce the entire programs RAM usage. The
functions init() and ports() have had their local memory overlapped with that of sprintf(), so
reducing the size of these functions local memory will have no affect on the programs RAM usage.
Their memory usage could be increased, as long as the total size of the memory used by these two
functions did not exceed that of sprintf(), with no additional memory used by the program. So if
you have to reduce the amount of RAM used by the program, look at those functions that are starred.
If, when searching a call graph, you notice that a functions parameter and auto areas have been
overlapped (i.e. ?a_foo was placed at the same address as ?_foo, for example), then check to
make sure that you have actually called the function in your program. If the linker has not seen a
function actually called, then it overlaps these areas of memory since that are not needed. This is
a consequence of the linkers ability to overlap the local memory areas of functions which are not
active at the same time. Once the function is called, unique addresses will be assigned to both the
parameters and auto objects.
If you are writing a routine that calls C code from assembler, you will need to include the appro-
priate assembler directives to ensure that the linker sees the C function being called.
5.12 Librarian
The librarian program, LIBR, has the function of combining several object files into a single file
known as a library. The purposes of combining several such object modules are several.
In order to make the library concept useful, it is necessary for the linker to treat modules in a library
differently from object files. If an object file is specified to the linker, it will be linked into the final
linked module. A module in a library, however, will only be linked in if it defines one or more
symbols previously known, but not defined, to the linker. Thus modules in a library will be linked
only if required. Since the choice of modules to link is made on the first pass of the linker, and
the library is searched in a linear fashion, it is possible to order the modules in a library to produce
special effects when linking. More will be said about this later.
134
Linker and Utilities Librarian
Interpreting this, LIBR is the name of the program, options is zero or more librarian options which
affect the output of the program. k is a key letter denoting the function requested of the librarian
(replacing, extracting or deleting modules, listing modules or symbols), file.lib is the name of
the library file to be operated on, and file.obj is zero or more object file names.
The librarian options are listed in Table 5.2.
The key letters are listed in Table 5.3.
When replacing or extracting modules, the file.obj arguments are the names of the modules
to be replaced or extracted. If no such arguments are supplied, all the modules in the library will be
135
Librarian Linker and Utilities
replaced or extracted respectively. Adding a file to a library is performed by requesting the librarian
to replace it in the library. Since it is not present, the module will be appended to the library. If the
r key is used and the library does not exist, it will be created.
Under the d key letter, the named object files will be deleted from the library. In this instance, it
is an error not to give any object file names.
The m and s key letters will list the named modules and, in the case of the s keyletter, the symbols
defined or referenced within (global symbols only are handled by the librarian). As with the r and x
key letters, an empty list of modules means all the modules in the library.
5.12.3 Examples
Here are some examples of usage of the librarian. The following lists the global symbols in the
modules a.obj, b.obj and c.obj:
This command deletes the object modules a.obj, b.obj and c.obj from the library file.lib:
libr
libr> r file.lib 1.obj 2.obj 3.obj \
libr> 4.obj 5.obj 6.obj
will perform much the same as if the object files had been typed on the command line. The libr>
prompts were printed by LIBR itself, the remainder of the text was typed as input.
libr <lib.cmd
LIBR will read input from lib.cmd, and execute the command found therein. This allows a virtually
unlimited length command to be given to LIBR.
136
Linker and Utilities Objtohex
5.13 Objtohex
The HI-TECH linker is capable of producing simple binary files, or object files as output. Any other
format required must be produced by running the utility program OBJTOHEX. This allows conversion
of object files as produced by the linker into a variety of different formats, including various hex
formats. The program is invoked thus:
OBJTOHEX options inputfile outputfile
All of the arguments are optional. If outputfile is omitted it defaults to l.hex or l.bin depend-
ing on whether the -b option is used. The inputfile defaults to l.obj.
The options for OBJTOHEX are listed in Table 5.4. Where an address is required, the format is the
same as for HLINK.
137
Objtohex Linker and Utilities
138
Linker and Utilities Cref
All of addr1, addr2, where1, where2 and offset are hex numbers, without the usual H suffix.
Such a specification says that the bytes at addr1 through to addr2 inclusive should be summed
and the sum placed in the locations where1 through where2 inclusive. For an 8 bit checksum
these two addresses should be the same. For a checksum stored low byte first, where1 should be less
than where2, and vice versa. The +offset is optional, but if supplied, the value offset will be used
to initialise the checksum. Otherwise it is initialised to zero. For example:
This will sum the bytes in 5 through 1FFFH inclusive, then add 1FFFH to the sum. The 16 bit
checksum will be placed in locations 3 and 4, low byte in 3. The checksum is initialised with 1FFFH
to provide protection against an all zero ROM, or a ROM misplaced in memory. A run time check of
this checksum would add the last address of the ROM being checksummed into the checksum. For
the ROM in question, this should be 1FFFH. The initialization value may, however, be used in any
desired fashion.
5.14 Cref
The cross reference list utility CREF is used to format raw cross-reference information produced by
the compiler or the assembler into a sorted listing. A raw cross-reference file is produced with the
--CR option to the compiler. The assembler will generate a raw cross-reference file with a -C option
(most assemblers) or by using an OPT CRE directive (6800 series assemblers) or a XREF control line
(PIC assembler). The general form of the CREF command is:
where options is zero or more options as described below and files is one or more raw cross-
reference files. CREF takes the options listed in Table 5.5.
Each option is described in more detail in the following paragraphs.
139
Cref Linker and Utilities
5.14.1 -Fprefix
It is often desired to exclude from the cross-reference listing any symbols defined in a system header
file, e.g. <stdio.h>. The -F option allows specification of a path name prefix that will be used to
exclude any symbols defined in a file whose path name begins with that prefix. For example, -F\
will exclude any symbols from all files with a path name starting with \.
5.14.2 -Hheading
The -H option takes a string as an argument which will be used as a header in the listing. The default
heading is the name of the first raw cross-ref information file specified.
5.14.3 -Llen
Specify the length of the paper on which the listing is to be produced, e.g. if the listing is to be
printed on 55 line paper you would use a -L55 option. The default is 66 lines.
5.14.4 -Ooutfile
Allows specification of the output file name. By default the listing will be written to the standard
output and may be redirected in the usual manner. Alternatively outfile may be specified as the
output file name.
140
Linker and Utilities Cromwell
5.14.5 -Pwidth
This option allows the specification of the width to which the listing is to be formatted, e.g. -P132
will format the listing for a 132 column printer. The default is 80 columns.
5.14.6 -Sstoplist
The -S option should have as its argument the name of a file containing a list of symbols not to be
listed in the cross-reference. Multiple stoplists may be supplied with multiple -S options.
5.14.7 -Xprefix
The -X option allows the exclusion of symbols from the listing, based on a prefix given as argument
to -X. For example if it was desired to exclude all symbols starting with the character sequence xyz
then the option -Xxyz would be used. If a digit appears in the character sequence then this will match
any digit in the symbol, e.g. -XX0 would exclude any symbols starting with the letter X followed by
a digit.
CREF will accept wildcard filenames and I/O redirection. Long command lines may be supplied
by invoking CREF with no arguments and typing the command line in response to the cref> prompt.
A backslash at the end of the line will be interpreted to mean that more command lines follow.
5.15 Cromwell
The CROMWELL utility converts code and symbol files into different formats. The formats available
are shown in Table 5.6.
The general form of the CROMWELL command is:
where options can be any of the options shown in Table 5.7. Output_file (optional) is the
name of the output file. The input_files are typically the HEX and SYM file. CROMWELL
automatically searches for the SDB files and reads those if they are found. The options are further
described in the following paragraphs.
5.15.1 -Pname[,architecture]
The -P options takes a string which is the name of the processor used. CROMWELL may use this in the
generation of the output format selected. Note that to produce output in COFF format an additional
argument to this option which also specifies the processor architecture is required. Hence for this
141
Cromwell Linker and Utilities
142
Linker and Utilities Cromwell
format the usage of this option must take the form: -Pname,architecture. Table 5.8 enumerates
the architectures supported for producing COFF files.
5.15.2 -N
To produce some output file formats (e.g. COFF), Cromwell requires that the names of the program
memory space psect classes be provided. The names of the classes are given as a comma separated
list. For example, in the DSPIC C compiler these classes are typically CODE and NEARCODE,
i.e. -NCODE,NEARCODE.
5.15.3 -D
The -D option is used to display to the screen details about the named input file in a readable format.
The input file can be one of the file types as shown in Table 5.6.
5.15.4 -C
This option will attempt to identify if the specified input files are one of the formats as shown in
Table 5.6. If the file is recognised, a confirmation of its type will be displayed.
5.15.5 -F
When generating a COD file, this option can be used to force all local symbols to be represented as
global symbols. The may be useful where an emulator cannot read local symbol information from
the COD file.
143
Hexmate Linker and Utilities
5.15.6 -Okey
This option specifies the format of the output file. The key can be any of the types listed in Table
5.6.
5.15.7 -Ikey
This option can be used to specify the default input file format. The key can be any of the types
listed in Table 5.6.
5.15.8 -L
Use this option to show what file format types are supported. A list similar to that given in Table 5.6
will be shown.
5.15.9 -E
Use this option to tell CROMWELL to ignore any filename extensions that were given. The default
extension will be used instead.
5.15.10 -B
In formats that support different endian types, use this option to specify big-endian byte ordering.
5.15.11 -M
When generating COD files this option will remove the preceding underscore character from sym-
bols.
5.15.12 -V
Turns on verbose mode which will display information about operations CROMWELL is performing.
5.16 Hexmate
The Hexmate utility is a program designed to manipulate Intel HEX files. Hexmate is a post-link
stage utility that provides the facility to:
144
Linker and Utilities Hexmate
Calculating a checksum over a range of program memory and storing its value in program
memory or EEPROM
Filling unused memory locations with an instruction to send the PC to a known location if it
gets lost.
145
Hexmate Linker and Utilities
Where file1.hex through to fileN.hex are a list of input Intel hex files to merge using hexmate. Ad-
ditional options can be provided to further customize this process. Table 5.9 lists the command line
options that hexmate accepts.
The input parameters to hexmate are now discussed in greater detail. Note that any integral
values supplied to the hexmate options should be entered as hexadecimal values without leading 0x
or trailing h characters. Note also that any address fields specified in these options are to be entered
as byte addresses, unless specified otherwise in the -ADDRESSING option.
5.16.1.1 specifications,filename.hex
Intel hex files that can be processed by hexmate should be in either INHX32 or INHX8M format.
Additional specifications can be applied to each hex file to put restrictions or conditions on how this
file should be processed. If any specifications are used they must precede the filename. The list of
specifications will then be separated from the filename by a comma.
A range restriction can be applied with the specification rStart-End. A range restriction will
cause only the address data falling within this range to be used. For example:
r100-1FF,myfile.hex
will use myfile.hex as input, but only process data which is addressed within the range 100h-1FFh
(inclusive) to be read from myfile.hex.
146
Linker and Utilities Hexmate
An address shift can be applied with the specification sOffset . If an address shift is used, data
read from this hex file will be shifted (by the Offset) to a new address when generating the output.
The offset can be either positive or negative. For example:
r100-1FFs2000,myfile.hex
will shift the block of data from 100h-1FFh to the new address range 2100h-21FFh.
Be careful when shifting sections of executable code. Program code shouldnt be shifted unless it
can be guaranteed that no part of the program relies upon the absolute location of this code segment.
5.16.1.2 + Prefix
When the + operator precedes a parameter or input file, the data obtained from that parameter will
be forced into the output file and will overwrite other data existing within its address range. For
example:
Ordinarily, hexmate will issue an error if two sources try to store differing data at the same location.
Using the + operator informs hexmate that if more than one data source tries to store data to the same
address, the one specified with a + will take priority.
5.16.1.3 -ADDRESSING
By default, all address parameters in hexmate options expect that values will be entered as byte
addresses. In some device architectures the native addressing format may be something other than
byte addressing. In these cases it would be much simpler to be able to enter address-components
in the devices native format. To facilitate this, the -ADDRESSING option is used. This option takes
exactly one parameter which configures the number of bytes contained per address location. If for
example a devices program memory naturally used a 16-bit (2 byte) word-addressing format, the
option -ADDRESSING=2 will configure hexmate to interpret all command line addess fields as word
addresses. The affect of this setting is global and all hexmate options will now interpret addresses
according to this setting. This option will allow specification of addressing modes from one byte-
per-address to four bytes-per-address.
5.16.1.4 -CK
The -CK option is for calculating a checksum. The usage of this option is:
-CK=start-end@destination[+offset][wWidth][tCode][gAlogithm]
147
Hexmate Linker and Utilities
where:
Start and End specify the address range that the checksum will be calculated over.
Destination is the address where to store the checksum result. This value cannot be within the
range of calculation.
Offset is an optional initial value to add to the checksum result. Width is optional and specifies
the byte-width of the checksum result. Results can be calculated for byte-widths of 1 to 4
bytes. If a positive width is requested, the result will be stored in big-endian byte order. A
negative width will cause the result to be stored in little-endian byte order. If the width is left
unspecified, the result will be 2 bytes wide and stored in little-endian byte order.
Code is a hexadecimal code that will trail each byte in the checksum result. This can allow
each byte of the checksum result to be embedded within an instruction.
Algorithm is an integer to select which hexmate algorithm to use to calculate the checksum
result. A list of selectable algorithms are given in Table 5.10. If unspecified, the default
checksum algorithm used is 8 bit addition.
-CK=0-1FFF@2FFE+2100w2
This will calculate a checksum over the range 0-1FFFh and program the checksum result at address
2FFEh, checksum value will apply an initial offset of 2100h. The result will be two bytes wide.
148
Linker and Utilities Hexmate
5.16.1.5 -FILL
The -FILL option is used for filling unused memory locations with a known value. The usage of this
option is:
-FILL=Code@Start-End[,data]
where:
Code is the opcode that will be programmed to unused locations in memory. Multi-byte codes
should be entered in little endian order.
Start and End specify the address range that this fill will apply to.
For example:
-FILL=3412@0-1FFF,data
will program opcode 1234h in all unused addresses from program memory address 0 to 1FFFh (Note
the endianism). -FILL accepts whole bytes of hexadecimal data from 1 to 8 bytes in length.
Adding the ,data flag to this option is not required. If the data flag has been specified, hexmate
will only perform ROM filling to records that actually contain data. This means that these records
will be padded out to the default data record length or the width specified in the -FORMAT option.
Records will also begin on addresses which are multiples of the data record length used. The default
data record length is 16 bytes. This facility is particularly useful or is a requirement for some
bootloaders that expect that all data records will be of a particular length and address alignment.
5.16.1.6 -FIND
This option is used to detect and log occurrences of an opcode or partial code sequence. The usage
of this option is:
-FIND=Findcode[mMask]@Start-End[/Align][w][tTitle]
where:
Findcode is the hexadecimal code sequence to search for and is entered in little endian byte
order.
Mask is optional. It allows a bitmask over the Findcode value and is entered in little endian
byte order.
Start and End limit the address range to search through.
149
Hexmate Linker and Utilities
Align is optional. It specifies that a code sequence can only match if it begins on an address
which is a multiple of this value. w, if present will cause hexmate to issue a warning whenever
the code sequence is detected.
Title is optional. It allows a title to be given to this code sequence. Defining a title will make
log-reports and messages more descriptive and more readable. A title will not affect the actual
search results.
T UTRIAL
Lets look at some examples. The option -FIND=3412@0-7FFF/2w will detect the code
sequence 1234h when aligned on a 2 (two) byte address boundary, between 0h and
7FFFh. w indicates that a warning will be issued each time this sequence is found.
Another example, -FIND=3412M0F00@0-7FFF/2wt"ADDXY" is same as last example
but the code sequence being matched is masked with 000Fh, so hexmate will search for
123xh. If a byte-mask is used, is must be of equal byte-width to the opcode it is applied
to. Any messaging or reports generated by hexmate will refer to this opcode by the
name, ADDXY as this was the title defined for this search.
If hexmate is generating a logfile, it will contain the results of all searches. -FIND accepts whole
bytes of hex data from 1 to 8 bytes in length. Optionally, -FIND can be used in conjunction with
,REPLACE (described below).
5.16.1.7 -FIND...,REPLACE
REPLACE Can only be used in conjunction with a -FIND option. Code sequences that matched the
-FIND criteria can be replaced or partially replaced with new codes. The usage for this sub-option
is:
-FIND...,REPLACE=Code[mMask]
where:
Code is a little endian hexadecimal code to replace the sequences that match the -FIND crite-
ria.
Mask is an optional bitmask to specify which bits within Code will replace the code sequence
that has been matched. This may be useful if, for example, it is only necessary to modify 4
bits within a 16-bit instruction. The remaining 12 bits can masked and be left unchanged.
150
Linker and Utilities Hexmate
5.16.1.8 -FORMAT
The -FORMAT option can be used to specify a particular variant of INHX format or adjust maximum
record length. The usage of this option is:
-FORMAT=Type[,Length]
where:
Length is optional and sets the maximum number of bytes per data record. A valid length is
between 1 and 16, with 16 being the default.
T UTRIAL
Consider this case. A bootloader trying to download an INHX32 file fails succeed
because it cannot process the extended address records which are part of the INHX32
standard. You know that this bootloader can only program data addressed within the
range 0 to 64k, and that any data in the hex file outside of this range can be safely
disregarded. In this case, by generating the hex file in INHX8M format the operation
might succeed. The hexmate option to do this would be -FORMAT=INHX8M.
Now consider this. What if the same bootloader also required every data record to
contain eight bytes of data, no more, no less? This is possible by combining -FORMAT
with -FILL. Appropriate use of -FILL can ensure that there are no gaps in the data
for the address range being programmed. This will satisfy the minimum data length
requirement. To set the maximum length of data records to eight bytes, just modify the
previous option to become -FORMAT=INHX8M,8.
The possible types that are supported by this option are listed in Table 5.11. Note that INHX032 is
not an actual INHX format. Selection of this type generates an INHX32 file but will also initialize
the upper address information to zero. This is a requirement of some device programmers.
151
Hexmate Linker and Utilities
5.16.1.9 -HELP
Using -HELP will list all hexmate options. By entering another hexmate option as a parameter of
-HELP will show a detailed help message for the given option. For example:
-HELP=string
5.16.1.10 -LOGFILE
The -LOGFILE option saves hexfile statistics to the named file. For example:
-LOGFILE=output.log
will analyse the hex file that hexmate is generating and save a report to a file named output.log.
5.16.1.11 -Ofile
The generated Intel hex output will be created in this file. For example:
-Oprogram.hex
will save the resultant output to program.hex. The output file can take the same name as one of its
input files, but by doing so, it will replace the input file entirely.
5.16.1.12 -SERIAL
This option will store a particular hex value at a fixed address. The usage of this option is:
-SERIAL=Code[+/-Increment]@Address[+/-Interval][rRepetitions]
where:
Code is a hexadecimal value to store and is entered in little endian byte order.
Increment is optional and allows the value of Code to change by this value with each repetition
(if requested).
Address is the location to store this code, or the first repetition thereof.
Interval is optional and specifies the address shift per repetition of this code.
Repetitions is optional and specifies the number of times to repeat this code.
152
Linker and Utilities Hexmate
For example:
-SERIAL=000001@EFFE
-SERIAL=0000+2@1000+10r5
will store 5 codes, beginning with value 0000 at address 1000h. Subsequent codes will appear at
address intervals of +10h and the code value will change in increments of +2h.
5.16.1.13 -STRING
The -STRING option will embed an ASCII string at a fixed address. The usage of this option is:
-STRING@Address[tCode]=Text
where:
For example:
will store the ASCII data for the string, My favourite string (including null terminator) at ad-
dress 1000h.
Another example:
will store the same string with every byte in the string being trailed with the hexcode 34h.
153
Hexmate Linker and Utilities
154
Appendix A
Library Functions
The functions within the standard compiler library are listed in this chapter. Each entry begins with
the name of the function. This is followed by information decomposed into the following categories.
Synopsis the C declaration of the function, and the header file in which it is declared.
Description a narrative description of the function and its purpose.
Example an example of the use of the function. It is usually a complete small program that illus-
trates the function.
Data types any special data types (structures etc.) defined for use with the function. These data
types will be defined in the header file named under Synopsis.
See also any allied functions.
Return value the type and nature of the return value of the function, if any. Information on error
returns is also included
Only those categories which are relevant to each function are used.
155
Library Functions
__CONFIG
Synopsis
#include <htc.h>
__CONFIG(data)
Description
This macro is used to program the configuration fuses that set the device into various modes of
operation.
The macro accepts the 16-bit value it is to update it with.
16-Bit masks have been defined to describe each programmable attribute available on each de-
vice. These attribute masks can be found tabulated in this manual in the Features and Runtime
Environment section.
Multiple attributes can be selected by ANDing them together.
Example
#include <htc.h>
void
main (void)
{
}
See also
__EEPROM_DATA(), __IDLOC(), __IDLOC7()
156
Library Functions
__EEPROM_DATA
Synopsis
#include <htc.h>
__EEPROM_DATA(a,b,c,d,e,f,g,h)
Description
This macro is used to store initial values into the devices EEPROM registers at the time of program-
ming.
The macro must be given blocks of 8 bytes to write each time it is called, and can be called
repeatedly to store multiple blocks.
__EEPROM_DATA() will begin writing to EEPROM address zero, and will auto-increment the
address written to by 8, each time it is used.
Example
#include <htc.h>
__EEPROM_DATA(0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07)
__EEPROM_DATA(0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F)
void
main (void)
{
}
See also
__CONFIG()
157
Library Functions
__IDLOC
Synopsis
#include <htc.h>
__IDLOC(x)
Description
This macro places data into the devices special locations outside of addressable memory reserved
for ID. This would be useful for storage of serial numbers etc.
The macro will attempt to write 4 nibbles of data to the 4 locations reserved for ID purposes.
Example
#include <htc.h>
__IDLOC(15F0);
/* will store 1, 5, F and 0 in the ID registers*/
void
main (void)
{
}
See also
__IDLOC7(), __CONFIG()
158
Library Functions
__IDLOC7
Synopsis
#include <htc.h>
__IDLOC7(a,b,c,d)
Description
This macro places data into the devices special locations outside of addressable memory reserved
for ID. This would be useful for storage of serial numbers etc.
The macro will attempt to write 7 bits of data to each of the 4 locations reserved for ID purposes.
Example
#include <htc.h>
__IDLOC(0x7F,70,1,0x5A);
/* will store 7Fh, 70, 1 and 5Ah in the ID registers */
void
main (void)
{
}
Note
Not all devices permit 7 bit programming of the ID locations. Refer to the device datasheet to see
whether this macro can be used on your particular device.
See also
__IDLOC(), __CONFIG()
159
Library Functions
__RAM_CELL_TEST
Synopsis
void _ram_cell_test(void)
Description
Should not be called from user code. This routine is called from a loop within the generated runtime
startup code if the system requires a RAM integrity test before program execution. Upon entry to this
routine, the FSR register has been loaded with the RAM cell to test. The value 0x55 will be assigned
to the cell and verified, followed by 0xAA. If either of these values fail verification, the routine will
call ram_test_failed() with an error code in the working register and FSR still containing the
address that was in error.
This routine is called repeatedly during startup, with each subsequent call testing the next address
in sequence. If the location being tested contains non volatile data, the value will be backed up before
the test routine is called and restored upon return from the routine.
This library routine can be overriden by a users implementation if the standard cell tests are
insufficient for a particular systems verification.
See also
ram_cell_test()
160
Library Functions
ABS
Synopsis
#include <stdlib.h>
Description
The abs() function returns the absolute value of j.
Example
#include <stdio.h>
#include <stdlib.h>
void
main (void)
{
int a = -5;
Return Value
The absolute value of j.
161
Library Functions
ACOS
Synopsis
#include <math.h>
Description
The acos() function implements the inverse of cos(), i.e. it is passed a value in the range -1 to +1,
and returns an angle in radians whose cosine is equal to that value.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
float i, a;
See Also
sin(), cos(), tan(), asin(), atan(), atan2()
Return Value
An angle in radians, in the range 0 to
162
Library Functions
ASCTIME
Synopsis
#include <time.h>
Description
The asctime() function takes the time broken down into the struct tm structure, pointed to by its
argument, and returns a 26 character string describing the current date and time in the format:
Sun Sep 16 01:03:52 1973\n\0
Note the newline at the end of the string. The width of each field in the string is fixed. The
example gets the current time, converts it to a struct tm pointer with localtime(), it then converts
this to ASCII and prints it. The time() function will need to be provided by the user (see time() for
details).
Example
#include <stdio.h>
#include <time.h>
void
main (void)
{
time_t clock;
struct tm * tp;
time(&clock);
tp = localtime(&clock);
printf("%s", asctime(tp));
}
See Also
163
Library Functions
Return Value
A pointer to the string.
Note
The example will require the user to provide the time() routine as it cannot be supplied with the
compiler. See time() for more details.
164
Library Functions
ASIN
Synopsis
#include <math.h>
Description
The asin() function implements the converse of sin(), i.e. it is passed a value in the range -1 to +1,
and returns an angle in radians whose sine is equal to that value.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
float i, a;
See Also
sin(), cos(), tan(), acos(), atan(), atan2()
Return Value
An angle in radians, in the range -
165
Library Functions
ASSERT
Synopsis
#include <assert.h>
Description
This macro is used for debugging purposes; the basic method of usage is to place assertions liberally
throughout your code at points where correct operation of the code depends upon certain conditions
being true initially. An assert() routine may be used to ensure at run time that an assumption holds
true. For example, the following statement asserts that the pointer tp is not equal to NULL:
assert(tp);
If at run time the expression evaluates to false, the program will abort with a message identifying
the source file and line number of the assertion, and the expression used as an argument to it. A fuller
discussion of the uses of assert() is impossible in limited space, but it is closely linked to methods
of proving program correctness.
Example
void
ptrfunc (struct xyz * tp)
{
assert(tp != 0);
}
Note
When required for ROM based systems, the underlying routine _fassert(...) will need to be imple-
mented by the user.
166
Library Functions
ATAN
Synopsis
#include <math.h>
Description
This function returns the arc tangent of its argument, i.e. it returns an angle e in the range -
Example
#include <stdio.h>
#include <math.h>
void
main (void)
{
printf("%f\n", atan(1.5));
}
See Also
sin(), cos(), tan(), asin(), acos(), atan2()
Return Value
The arc tangent of its argument.
167
Library Functions
ATOF
Synopsis
#include <stdlib.h>
Description
The atof() function scans the character string passed to it, skipping leading blanks. It then converts
an ASCII representation of a number to a double. The number may be in decimal, normal floating
point or scientific notation.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
char buf[80];
double i;
gets(buf);
i = atof(buf);
printf("Read %s: converted to %f\n", buf, i);
}
See Also
atoi(), atol()
Return Value
A double precision floating point number. If no number is found in the string, 0.0 will be returned.
168
Library Functions
ATOI
Synopsis
#include <stdlib.h>
Description
The atoi() function scans the character string passed to it, skipping leading blanks and reading an
optional sign. It then converts an ASCII representation of a decimal number to an integer.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
char buf[80];
int i;
gets(buf);
i = atoi(buf);
printf("Read %s: converted to %d\n", buf, i);
}
See Also
xtoi(), atof(), atol()
Return Value
A signed integer. If no number is found in the string, 0 will be returned.
169
Library Functions
ATOL
Synopsis
#include <stdlib.h>
Description
The atol() function scans the character string passed to it, skipping leading blanks. It then converts
an ASCII representation of a decimal number to a long integer.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
char buf[80];
long i;
gets(buf);
i = atol(buf);
printf("Read %s: converted to %ld\n", buf, i);
}
See Also
atoi(), atof()
Return Value
A long integer. If no number is found in the string, 0 will be returned.
170
Library Functions
BSEARCH
Synopsis
#include <stdlib.h>
Description
The bsearch() function searches a sorted array for an element matching a particular key. It uses a
binary search algorithm, calling the function pointed to by compar to compare elements in the array.
Example
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct value {
char name[40];
int value;
} values[100];
int
val_cmp (const void * p1, const void * p2)
{
return strcmp(((const struct value *)p1)->name,
((const struct value *)p2)->name);
}
void
main (void)
{
char inbuf[80];
int i;
struct value * vp;
171
Library Functions
i = 0;
while(gets(inbuf)) {
sscanf(inbuf,"%s %d", values[i].name, &values[i].value);
i++;
}
qsort(values, i, sizeof values[0], val_cmp);
vp = bsearch("fred", values, i, sizeof values[0], val_cmp);
if(!vp)
printf("Item fred was not found\n");
else
printf("Item fred has value %d\n", vp->value);
}
See Also
qsort()
Return Value
A pointer to the matched array element (if there is more than one matching element, any of these
may be returned). If no match is found, a null pointer is returned.
Note
The comparison function must have the correct prototype.
172
Library Functions
CEIL
Synopsis
#include <math.h>
Description
This routine returns the smallest whole number not less than f.
Example
#include <stdio.h>
#include <math.h>
void
main (void)
{
double j;
scanf("%lf", &j);
printf("The ceiling of %lf is %lf\n", j, ceil(j));
}
173
Library Functions
CGETS
Synopsis
#include <conio.h>
Description
The cgets() function will read one line of input from the console into the buffer passed as an ar-
gument. It does so by repeated calls to getche(). As characters are read, they are buffered, with
backspace deleting the previously typed character, and ctrl-U deleting the entire line typed so far.
Other characters are placed in the buffer, with a carriage return or line feed (newline) terminating
the function. The collected string is null terminated.
Example
#include <conio.h>
#include <string.h>
char buffer[80];
void
main (void)
{
for(;;) {
cgets(buffer);
if(strcmp(buffer, "exit") == 0)
break;
cputs("Type exit to finish\n");
}
}
See Also
174
Library Functions
Return Value
The return value is the character pointer passed as the sole argument.
175
Library Functions
CLRWDT
Synopsis
#include <htc.h>
CLRWDT();
Description
This macro is used to clear the devices internal watchdog timer.
Example
#include <htc.h>
void
main (void)
{
WDTCON=1;
/* enable the WDT */
CLRWDT();
}
176
Library Functions
COS
Synopsis
#include <math.h>
Description
This function yields the cosine of its argument, which is an angle in radians. The cosine is calculated
by expansion of a polynomial series approximation.
Example
#include <math.h>
#include <stdio.h>
#define C 3.141592/180.0
void
main (void)
{
double i;
See Also
sin(), tan(), asin(), acos(), atan(), atan2()
Return Value
A double in the range -1 to +1.
177
Library Functions
#include <math.h>
Description
These functions are the implement hyperbolic equivalents of the trigonometric functions; cos(), sin()
and tan().
Example
#include <stdio.h>
#include <math.h>
void
main (void)
{
printf("%f\n", cosh(1.5));
printf("%f\n", sinh(1.5));
printf("%f\n", tanh(1.5));
}
Return Value
The function cosh() returns the hyperbolic cosine value.
The function sinh() returns the hyperbolic sine value.
The function tanh() returns the hyperbolic tangent value.
178
Library Functions
CPUTS
Synopsis
#include <conio.h>
Description
The cputs() function writes its argument string to the console, outputting carriage returns before
each newline in the string. It calls putch() repeatedly. On a hosted system cputs() differs from puts()
in that it writes to the console directly, rather than using file I/O. In an embedded system cputs() and
puts() are equivalent.
Example
#include <conio.h>
#include <string.h>
char buffer[80];
void
main (void)
{
for(;;) {
cgets(buffer);
if(strcmp(buffer, "exit") == 0)
break;
cputs("Type exit to finish\n");
}
}
See Also
cputs(), puts(), putch()
179
Library Functions
CTIME
Synopsis
#include <time.h>
Description
The ctime() function converts the time in seconds pointed to by its argument to a string of the same
form as described for asctime(). Thus the example program prints the current time and date.
Example
#include <stdio.h>
#include <time.h>
void
main (void)
{
time_t clock;
time(&clock);
printf("%s", ctime(&clock));
}
See Also
gmtime(), localtime(), asctime(), time()
Return Value
A pointer to the string.
Note
The example will require the user to provide the time() routine as one cannot be supplied with the
compiler. See time() for more detail.
180
Library Functions
DI, EI
Synopsis
#include <htc.h>
void ei (void)
void di (void)
Description
The di() and ei() routines disable and re-enable interrupts respectively. These are implemented as
macros defined in pic.h. The example shows the use of ei() and di() around access to a long
variable that is modified during an interrupt. If this was not done, it would be possible to return an
incorrect value, if the interrupt occurred between accesses to successive words of the count value.
Example
#include <htc.h>
long count;
void
interrupt tick (void)
{
count++;
}
long
getticks (void)
{
long val; /* Disable interrupts around access
to count, to ensure consistency.*/
di();
val = count;
ei();
return val;
}
181
Library Functions
DIV
Synopsis
#include <stdlib.h>
Description
The div() function computes the quotient and remainder of the numerator divided by the denomina-
tor.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
div_t x;
x = div(12345, 66);
printf("quotient = %d, remainder = %d\n", x.quot, x.rem);
}
Return Value
Returns the quotient and remainder into the div_t structure.
182
Library Functions
EEPROM_READ, EEPROM_WRITE
Synopsis
#include <htc.h>
Description
These function allow access to the on-chip eeprom (when present). The eeprom is not in the directly-
accessible memory space and a special byte sequence is loaded to the eeprom control registers to
access the device. Writing a value to the eeprom is a slow process and the eeprom_write() function
polls the appropriate registers to ensure that any previous writes have completed before writing the
next datum. Reading data is completed in the one cycle and no polling is necessary to check for a
read completion.
Example
#include <htc.h>
void
main (void)
{
unsigned char data;
unsigned char address;
address = 0x10;
data = eeprom_read(address);
}
Note
It may be necessary to poll the eeprom registers to ensure that the write has completed if an eep-
rom_write() call is immediately followed by an eeprom_read(). The global interrupt enable bit
(GIE) is now restored by the eeprom_write() routine. The EEIF interrupt flag is not reset by this
function.
183
Library Functions
EVAL_POLY
Synopsis
#include <math.h>
Description
The eval_poly() function evaluates a polynomial, whose coefficients are contained in the array d, at
x, for example:
Example
#include <stdio.h>
#include <math.h>
void
main (void)
{
double x, y;
double d[3] = {1.1, 3.5, 2.7};
x = 2.2;
y = eval_poly(x, d, 2);
printf("The polynomial evaluated at %f is %f\n", x, y);
}
Return Value
A double value, being the polynomial evaluated at x.
184
Library Functions
EXP
Synopsis
#include <math.h>
Description
The exp() routine returns the exponential function of its argument, i.e. e to the power of f.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
double f;
See Also
log(), log10(), pow()
185
Library Functions
FABS
Synopsis
#include <math.h>
Description
This routine returns the absolute value of its double argument.
Example
#include <stdio.h>
#include <math.h>
void
main (void)
{
printf("%f %f\n", fabs(1.5), fabs(-1.5));
}
See Also
abs()
186
Library Functions
FLASH_COPY
Synopsis
#include <htc.h>
Description
This utility function is useful for copying a large section of memory to a new location in flash
memory.
Note it is only applicable to those devices which have an internal set of flash buffer registers.
When the function is called, it needs to be supplied with a const pointer to the source address
of the data to copy. The pointer may point to a valid address in either RAM or flash memory.
A length parameter must be specified to indicate the number of words of the data to be copied.
Finally the flash address where this data is destined must be specified.
Example
#include <htc.h>
void
main (void){
const unsigned char * ptr = &ROMSTRING[0];
flash_copy( ptr, 5, 0x70 );
}
See Also
EEPROM_READ, EEPROM_WRITE, FLASH_READ, FLASH_WRITE
Note
This function is only applicable to those devices which use internal buffer registers when writing to
flash.
187
Library Functions
Ensure that the function does not attempt to overwrite the section of program memory from
which it is currently executing, and extreme caution must be exercised if modifying code at the
devices reset or interrupt vectors. A reset or interrupt must not be triggered while this sector is in
erasure.
188
Library Functions
FLASH_ERASE(), FLASH_READ()
Synopsis
#include <htc.h>
Description
These functions allow access to the flash memory of the microcontroller (if supported).
Reading from the flash memory can be done one word at a time with use of the flash_read()
function. flash_read() returns the data value found at the specified word address in flash memory.
Entire sectors of 32 words can be restored to an unprogrammed state (value=FF) with use of the
flash_erase() function. Specifying an address to the flash_erase() function, will erase all 32 words
in the sector that contains the given address.
Example
#include <htc.h>
void
main (void)
{
unsigned int data;
unsigned short address=0x1000;
data = flash_read(address);
flash_erase(address);
Return Value
flash_read() returns the data found at the given address, as an unsigned int.
189
Library Functions
Note
The functions flash_erase() and flash_read() are only available on those devices that support such
functionality.
190
Library Functions
FLOOR
Synopsis
#include <math.h>
Description
This routine returns the largest whole number not greater than f.
Example
#include <stdio.h>
#include <math.h>
void
main (void)
{
printf("%f\n", floor( 1.5 ));
printf("%f\n", floor( -1.5));
}
191
Library Functions
FREXP
Synopsis
#include <math.h>
Description
The frexp() function breaks a floating point number into a normalized fraction and an integral power
of 2. The integer is stored into the int object pointed to by p. Its return value x is in the interval (0.5,
1.0) or zero, and f equals x times 2 raised to the power stored in *p. If f is zero, both parts of the
result are zero.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
double f;
int i;
f = frexp(23456.34, &i);
printf("23456.34 = %f * 2^%d\n", f, i);
}
See Also
ldexp()
192
Library Functions
GETCH, GETCHE
Synopsis
#include <conio.h>
Description
The getch() function reads a single character from the console keyboard and returns it without echo-
ing. The getche() function is similar but does echo the character typed.
In an embedded system, the source of characters is defined by the particular routines supplied.
By default, the library contains a version of getch() that will interface to the Lucifer Debugger. The
user should supply an appropriate routine if another source is desired, e.g. a serial port.
The module getch.c in the SOURCES directory contains model versions of all the console I/O
routines. Other modules may also be supplied, e.g. ser180.c has routines for the serial port in a
Z180.
Example
#include <conio.h>
void
main (void)
{
char c;
See Also
cgets(), cputs(), ungetch()
193
Library Functions
GETCHAR
Synopsis
#include <stdio.h>
Description
The getchar() routine is a getc(stdin) operation. It is a macro defined in stdio.h. Note that under
normal circumstances getchar() will NOT return unless a carriage return has been typed on the
console. To get a single character immediately from the console, use the function getch().
Example
#include <stdio.h>
void
main (void)
{
int c;
See Also
getc(), fgetc(), freopen(), fclose()
Note
This routine is not usable in a ROM based system.
194
Library Functions
GETS
Synopsis
#include <stdio.h>
Description
The gets() function reads a line from standard input into the buffer at s, deleting the newline (cf.
fgets()). The buffer is null terminated. In an embedded system, gets() is equivalent to cgets(), and
results in getche() being called repeatedly to get characters. Editing (with backspace) is available.
Example
#include <stdio.h>
void
main (void)
{
char buf[80];
See Also
fgets(), freopen(), puts()
Return Value
It returns its argument, or NULL on end-of-file.
195
Library Functions
GET_CAL_DATA
Synopsis
#include <htc.h>
Description
This function returns the 32-bit floating point calibration data from the PIC14000 calibration space.
Only use this function to access KREF, KBG, VHTHERM and KTC (that is, the 32-bit floating point
parameters). FOSC and TWDT can be accessed directly as they are bytes.
Example
#include <htc.h>
void
main (void)
{
double x;
unsigned char y;
Return Value
The value of the calibration parameter
Note
This function can only be used on the PIC14000.
196
Library Functions
GMTIME
Synopsis
#include <time.h>
Description
This function converts the time pointed to by t which is in seconds since 00:00:00 on Jan 1, 1970,
into a broken down time stored in a structure as defined in time.h. The structure is defined in the
Data Types section.
Example
#include <stdio.h>
#include <time.h>
void
main (void)
{
time_t clock;
struct tm * tp;
time(&clock);
tp = gmtime(&clock);
printf("Its %d in London\n", tp->tm_year+1900);
}
See Also
197
Library Functions
Return Value
Returns a structure of type tm.
Note
The example will require the user to provide the time() routine as one cannot be supplied with the
compiler. See time() for more detail.
198
Library Functions
Description
These macros, defined in ctype.h, test the supplied character for membership in one of several over-
lapping groups of characters. Note that all except isascii() are defined for c, if isascii(c) is true or if
c = EOF.
199
Library Functions
Example
#include <ctype.h>
#include <stdio.h>
void
main (void)
{
char buf[80];
int i;
gets(buf);
i = 0;
while(isalnum(buf[i]))
i++;
buf[i] = 0;
printf("%s is the word\n", buf);
}
See Also
toupper(), tolower(), toascii()
200
Library Functions
LDEXP
Synopsis
#include <math.h>
Description
The ldexp() function performs the inverse of frexp() operation; the integer i is added to the exponent
of the floating point f and the resultant returned.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
double f;
f = ldexp(1.0, 10);
printf("1.0 * 2^10 = %f\n", f);
}
See Also
frexp()
Return Value
The return value is the integer i added to the exponent of the floating point value f.
201
Library Functions
LDIV
Synopsis
#include <stdlib.h>
Description
The ldiv() routine divides the numerator by the denominator, computing the quotient and the remain-
der. The sign of the quotient is the same as that of the mathematical quotient. Its absolute value is
the largest integer which is less than the absolute value of the mathematical quotient.
The ldiv() function is similar to the div() function, the difference being that the arguments and
the members of the returned structure are all of type long int.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
ldiv_t lt;
lt = ldiv(1234567, 12345);
printf("Quotient = %ld, remainder = %ld\n", lt.quot, lt.rem);
}
See Also
div()
Return Value
Returns a structure of type ldiv_t
202
Library Functions
LOCALTIME
Synopsis
#include <time.h>
Description
The localtime() function converts the time pointed to by t which is in seconds since 00:00:00 on Jan
1, 1970, into a broken down time stored in a structure as defined in time.h. The routine localtime()
takes into account the contents of the global integer time_zone. This should contain the number of
minutes that the local time zone is westward of Greenwich. On systems where it is not possible to
predetermine this value, localtime() will return the same result as gmtime().
Example
#include <stdio.h>
#include <time.h>
char * wday[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
};
void
main (void)
{
time_t clock;
struct tm * tp;
time(&clock);
tp = localtime(&clock);
printf("Today is %s\n", wday[tp->tm_wday]);
}
203
Library Functions
See Also
ctime(), asctime(), time()
Return Value
Returns a structure of type tm.
Note
The example will require the user to provide the time() routine as one cannot be supplied with the
compiler. See time() for more detail.
204
Library Functions
LOG, LOG10
Synopsis
#include <math.h>
Description
The log() function returns the natural logarithm of f. The function log10() returns the logarithm to
base 10 of f.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
double f;
See Also
exp(), pow()
Return Value
Zero if the argument is negative.
205
Library Functions
LONGJMP
Synopsis
#include <setjmp.h>
Description
The longjmp() function, in conjunction with setjmp(), provides a mechanism for non-local gotos.
To use this facility, setjmp() should be called with a jmp_buf argument in some outer level function.
The call from setjmp() will return 0.
To return to this level of execution, longjmp() may be called with the same jmp_buf argument
from an inner level of execution. Note however that the function which called setjmp() must still be
active when longjmp() is called. Breach of this rule will cause disaster, due to the use of a stack
containing invalid data. The val argument to longjmp() will be the value apparently returned from
the setjmp(). This should normally be non-zero, to distinguish it from the genuine setjmp() call.
Example
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
jmp_buf jb;
void
inner (void)
{
longjmp(jb, 5);
}
void
main (void)
{
int i;
206
Library Functions
if(i = setjmp(jb)) {
printf("setjmp returned %d\n", i);
exit(0);
}
printf("setjmp returned 0 - good\n");
printf("calling inner...\n");
inner();
printf("inner returned - bad!\n");
}
See Also
setjmp()
Return Value
The longjmp() routine never returns.
Note
The function which called setjmp() must still be active when longjmp() is called. Breach of this rule
will cause disaster, due to the use of a stack containing invalid data.
207
Library Functions
MEMCHR
Synopsis
#include <string.h>
Description
The memchr() function is similar to strchr() except that instead of searching null terminated strings,
it searches a block of memory specified by length for a particular byte. Its arguments are a pointer
to the memory to be searched, the value of the byte to be searched for, and the length of the block.
A pointer to the first occurrence of that byte in the block is returned.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
char * cp;
208
Library Functions
See Also
strchr()
Return Value
A pointer to the first byte matching the argument if one exists; NULL otherwise.
209
Library Functions
MEMCMP
Synopsis
#include <string.h>
Description
The memcmp() function compares two blocks of memory, of length n, and returns a signed value
similar to strncmp(). Unlike strncmp() the comparison does not stop on a null character.
Example
#include <stdio.h>
#include <string.h>
void
main (void)
{
int buf[10], cow[10], i;
buf[0] = 1;
buf[2] = 4;
cow[0] = 1;
cow[2] = 5;
buf[1] = 3;
cow[1] = 3;
i = memcmp(buf, cow, 3*sizeof(int));
if(i < 0)
printf("less than\n");
else if(i > 0)
printf("Greater than\n");
else
printf("Equal\n");
}
210
Library Functions
See Also
strncpy(), strncmp(), strchr(), memset(), memchr()
Return Value
Returns negative one, zero or one, depending on whether s1 points to string which is less than, equal
to or greater than the string pointed to by s2 in the collating sequence.
211
Library Functions
MEMCPY
Synopsis
#include <string.h>
Description
The memcpy() function copies n bytes of memory starting from the location pointed to by s to
the block of memory pointed to by d. The result of copying overlapping blocks is undefined. The
memcpy() function differs from strcpy() in that it copies a specified number of bytes, rather than all
bytes up to a null terminator.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
char buf[80];
See Also
212
Library Functions
Return Value
The memcpy() routine returns its first argument.
213
Library Functions
MEMMOVE
Synopsis
#include <string.h>
Description
The memmove() function is similar to the function memcpy() except copying of overlapping blocks
is handled correctly. That is, it will copy forwards or backwards as appropriate to correctly copy one
block to another that overlaps it.
See Also
strncpy(), strncmp(), strchr(), memcpy()
Return Value
The function memmove() returns its first argument.
214
Library Functions
MEMSET
Synopsis
#include <string.h>
Description
The memset() function fills n bytes of memory starting at the location pointed to by s with the byte
c.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
char abuf[20];
See Also
strncpy(), strncmp(), strchr(), memcpy(), memchr()
215
Library Functions
MODF
Synopsis
#include <math.h>
Description
The modf() function splits the argument value into integral and fractional parts, each having the
same sign as value. For example, -3.17 would be split into the integral part (-3) and the fractional
part (-0.17).
The integral part is stored as a double in the object pointed to by iptr.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
double i_val, f_val;
Return Value
The signed fractional part of value.
216
Library Functions
PERSIST_CHECK, PERSIST_VALIDATE
Synopsis
#include <sys.h>
Description
The persist_check() function is used with non-volatile RAM variables, declared with the persistent
qualifier. It tests the nvram area, using a magic number stored in a hidden variable by a previous call
to persist_validate() and a checksum also calculated by persist_validate(). If the magic number and
checksum are correct, it returns true (non-zero). If either are incorrect, it returns zero. In this case it
will optionally zero out and re-validate the non-volatile RAM area (by calling persist_validate()).
This is done if the flag argument is true.
The persist_validate() routine should be called after each change to a persistent variable. It will
set up the magic number and recalculate the checksum.
Example
#include <sys.h>
#include <stdio.h>
void
main (void)
{
if(!persist_check(1))
printf("Reset count invalid - zeroed\n");
else
printf("Reset number %ld\n", reset_count);
reset_count++; /* update count */
persist_validate(); /* and checksum */
for(;;)
continue; /* sleep until next reset */
217
Library Functions
Return Value
FALSE (zero) if the NVRAM area is invalid; TRUE (non-zero) if the NVRAM area is valid.
218
Library Functions
POW
Synopsis
#include <math.h>
Description
The pow() function raises its first argument, f, to the power p.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
double f;
See Also
log(), log10(), exp()
Return Value
f to the power of p.
219
Library Functions
PRINTF
Synopsis
#include <stdio.h>
Description
The printf() function is a formatted output routine, operating on stdout. There are corresponding
routines operating into a string buffer (sprintf()). The printf() routine is passed a format string,
followed by a list of zero or more arguments. In the format string are conversion specifications, each
of which is used to print out one of the argument list values.
Each conversion specification is of the form %m.nc where the percent symbol % introduces
a conversion, followed by an optional width specification m. The n specification is an optional
precision specification (introduced by the dot) and c is a letter specifying the type of the conversion.
Field widths and precision are only supported on the midrange and high-end processors, with the
precision specification only applicable to %s.
If the character * is used in place of a decimal constant, e.g. in the format %*d, then one integer
argument will be taken from the list to provide that value. The types of conversion for the Baseline
series are:
oxXud
Integer conversion - in radices 8, 16, 16, 10 and 10 respectively. The conversion is signed in the case
of d, unsigned otherwise. The precision value is the total number of digits to print, and may be used
to force leading zeroes. E.g. %8.4x will print at least 4 hex digits in an 8 wide field. The letter X
prints out hexadecimal numbers using the upper case letters A-F rather than a-f as would be printed
when using x. When the alternate format is specified, a leading zero will be supplied for the octal
format, and a leading 0x or 0X for the hex format.
s
Print a string - the value argument is assumed to be a character pointer. At most n characters from
the string will be printed, in a field m characters wide.
c
The argument is assumed to be a single character and is printed literally.
Any other characters used as conversion specifications will be printed. Thus % will produce a
single percent sign.
For the Midrange and High-end series, the types of conversions are as for the Baseline with the
addition of:
220
Library Functions
l
Long integer conversion - Preceding the integer conversion key letter with an l indicates that the
argument list is long.
f
Floating point - m is the total width and n is the number of digits after the decimal point. If n is
omitted it defaults to 6. If the precision is zero, the decimal point will be omitted unless the alternate
format is specified.
Example
printf("Total = %4d%", 23)
yields Total = 23%
Note that the precision number is only available when using Midrange
and High-end processors when using the %s placeholder.
printf("Name = %.8s", "a1234567890")
yields Name = a1234567
Note that the variable width number is only available when using Midrange
and High-end processors placeholder.
printf("xx%*d", 3, 4)
yields xx 4
/* vprintf example */
#include <stdio.h>
int
error (char * s, ...)
{
va_list ap;
va_start(ap, s);
printf("Error: ");
vprintf(s, ap);
221
Library Functions
putchar(\n);
va_end(ap);
}
void
main (void)
{
int i;
i = 3;
error("testing 1 2 %d", i);
}
See Also
sprintf()
Return Value
The printf() routine returns the number of characters written to stdout.
NB The return value is a char, NOT an int.
Note
Certain features of printf are only available for the midrange and high-end processors. Read the
description for details. Printing floating point numbers requires that the float to be printed be no
larger than the largest possible long integer. In order to use long or float formats, the appropriate
supplemental library must be included. See the description on the PICC -L option and the HPDPIC
Options/Long formats in printf menu for more details.
222
Library Functions
PUTCH
Synopsis
#include <conio.h>
Description
The putch() function outputs the character c to the console screen, prepending a carriage return if
the character is a newline. In a CP/M or MS-DOS system this will use one of the system I/O calls.
In an embedded system this routine, and associated others, will be defined in a hardware dependent
way. The standard putch() routines in the embedded library interface either to a serial port or to the
Lucifer Debugger.
Example
#include <conio.h>
void
main (void)
{
char * cp;
cp = x;
while(*x)
putch(*x++);
putch(\n);
}
See Also
cgets(), cputs(), getch(), getche()
223
Library Functions
PUTCHAR
Synopsis
#include <stdio.h>
Description
Example
#include <stdio.h>
void
main (void)
{
char * cp;
cp = x;
while(*x)
putchar(*x++);
putchar(\n);
}
See Also
Return Value
224
Library Functions
Note
This routine is not usable in a ROM based system.
225
Library Functions
PUTS
Synopsis
#include <stdio.h>
Description
The puts() function writes the string s to the stdout stream, appending a newline. The null character
terminating the string is not copied.
Example
#include <stdio.h>
void
main (void)
{
puts("Hello, world!");
}
See Also
fputs(), gets(), freopen(), fclose()
Return Value
EOF is returned on error; zero otherwise.
226
Library Functions
QSORT
Synopsis
#include <stdlib.h>
Description
The qsort() function is an implementation of the quicksort algorithm. It sorts an array of nel items,
each of length width bytes, located contiguously in memory at base. The argument func is a pointer
to a function used by qsort() to compare items. It calls func with pointers to two items to be com-
pared. If the first item is considered to be greater than, equal to or less than the second then func
should return a value greater than zero, equal to zero or less than zero respectively.
Example
#include <stdio.h>
#include <stdlib.h>
int aray[] = {
567, 23, 456, 1024, 17, 567, 66
};
int
sortem (const void * p1, const void * p2)
{
return *(int *)p1 - *(int *)p2;
}
void
main (void)
{
register int i;
227
Library Functions
Note
The function parameter must be a pointer to a function of type similar to:
i.e. it must accept two const void * parameters, and must be prototyped.
228
Library Functions
RAM_TEST_FAILED
Synopsis
void ram_test_failed (unsigned char errcode)
Description
The ram_test_failed() function is not intended to be called from within the general execution of
the program. This routine is called during execution of the generated runtime startup code if the
program is using a compiler generated RAM integrity test and the integrity test detects a bad cell.
Upon entry to this function, the working register contains an error code, the address that failed
can be determined from the FSR register and IRP bit. The failed value will still be accessable through
the INDF register. The default operation of this routine will halt program execution if a bad cell is
detected, however the user is free to enhance this functionality if required.
See Also
__ram_cell_test
Note
This routine is intended to be replaced by an equivalent routine to suit the users implementation.
Possible enhancements include logging the location of the dead cell and continuing to test if there
are any more more dead cells, or alerting the outside world that the device has a memory problem.
229
Library Functions
RAND
Synopsis
#include <stdlib.h>
Description
The rand() function is a pseudo-random number generator. It returns an integer in the range 0
to 32767, which changes in a pseudo-random fashion on each call. The algorithm will produce a
deterministic sequence if started from the same point. The starting point is set using the srand() call.
The example shows use of the time() function to generate a different starting point for the sequence
each time.
Example
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void
main (void)
{
time_t toc;
int i;
time(&toc);
srand((int)toc);
for(i = 0 ; i != 10 ; i++)
printf("%d\t", rand());
putchar(\n);
}
See Also
srand()
230
Library Functions
Note
The example will require the user to provide the time() routine as one cannot be supplied with the
compiler. See time() for more detail.
231
Library Functions
SCANF, VSCANF
Synopsis
#include <stdio.h>
#include <stdio.h>
#include <stdarg.h>
Description
The scanf() function performs formatted input ("de-editing") from the stdin stream. Similar func-
tions are available for streams in general, and for strings. The function vscanf() is similar, but takes
a pointer to an argument list rather than a series of additional arguments. This pointer should have
been initialised with va_start().
The input conversions are performed according to the fmt string; in general a character in the
format string must match a character in the input; however a space character in the format string will
match zero or more "white space" characters in the input, i.e. spaces, tabs or newlines.
A conversion specification takes the form of the character %, optionally followed by an assign-
ment suppression character (*), optionally followed by a numerical maximum field width, followed
by a conversion specification character. Each conversion specification, unless it incorporates the as-
signment suppression character, will assign a value to the variable pointed at by the next argument.
Thus if there are two conversion specifications in the fmt string, there should be two additional
pointer arguments.
The conversion characters are as follows:
oxd
Skip white space, then convert a number in base 8, 16 or 10 radix respectively. If a field width was
supplied, take at most that many characters from the input. A leading minus sign will be recognized.
f
Skip white space, then convert a floating number in either conventional or scientific notation. The
field width applies as above.
s
Skip white space, then copy a maximal length sequence of non-white-space characters. The pointer
232
Library Functions
argument must be a pointer to char. The field width will limit the number of characters copied. The
resultant string will be null terminated.
c
Copy the next character from the input. The pointer argument is assumed to be a pointer to char. If a
field width is specified, then copy that many characters. This differs from the s format in that white
space does not terminate the character sequence.
The conversion characters o, x, u, d and f may be preceded by an l to indicate that the corre-
sponding pointer argument is a pointer to long or double as appropriate. A preceding h will indicate
that the pointer argument is a pointer to short rather than int.
Example
scanf("%d %s", &a, &c)
with input " 12s"
will assign 12 to a, and "s" to s.
See Also
fscanf(), sscanf(), printf(), va_arg()
Return Value
The scanf() function returns the number of successful conversions; EOF is returned if end-of-file
was seen before any conversions were performed.
233
Library Functions
SETJMP
Synopsis
#include <setjmp.h>
Description
The setjmp() function is used with longjmp() for non-local gotos. See longjmp() for further infor-
mation.
Example
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>
jmp_buf jb;
void
inner (void)
{
longjmp(jb, 5);
}
void
main (void)
{
int i;
if(i = setjmp(jb)) {
printf("setjmp returned %d\n", i);
exit(0);
}
printf("setjmp returned 0 - good\n");
printf("calling inner...\n");
234
Library Functions
inner();
printf("inner returned - bad!\n");
}
See Also
longjmp()
Return Value
The setjmp() function returns zero after the real call, and non-zero if it apparently returns after a call
to longjmp().
235
Library Functions
SIN
Synopsis
#include <math.h>
Description
This function returns the sine function of its argument.
Example
#include <math.h>
#include <stdio.h>
#define C 3.141592/180.0
void
main (void)
{
double i;
See Also
cos(), tan(), asin(), acos(), atan(), atan2()
Return Value
Sine vale of f.
236
Library Functions
SPRINTF
Synopsis
#include <stdio.h>
Description
The sprintf() function operates in a similar fashion to printf(), except that instead of placing the
converted output on the stdout stream, the characters are placed in the buffer at buf. The resultant
string will be null terminated, and the number of characters in the buffer will be returned.
See Also
printf()
Return Value
The sprintf() routine returns the number of characters placed into the buffer.
NB: The return value is a char not an int.
Note
For High-end processors the buffer is accessed via a far pointer.
237
Library Functions
SQRT
Synopsis
#include <math.h>
Description
The function sqrt(), implements a square root routine using Newtons approximation.
Example
#include <math.h>
#include <stdio.h>
void
main (void)
{
double i;
See Also
exp()
Return Value
Returns the value of the square root.
Note
A domain error occurs if the argument is negative.
238
Library Functions
SRAND
Synopsis
#include <stdlib.h>
Description
The srand() function initializes the random number generator accessed by rand() with the given
seed. This provides a mechanism for varying the starting point of the pseudo-random sequence
yielded by rand(). On the Z80, a good place to get a truly random seed is from the refresh register.
Otherwise timing a response from the console will do, or just using the system time.
Example
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
void
main (void)
{
time_t toc;
int i;
time(&toc);
srand((int)toc);
for(i = 0 ; i != 10 ; i++)
printf("%d\t", rand());
putchar(\n);
}
See Also
rand()
239
Library Functions
STRCAT
Synopsis
#include <string.h>
Description
This function appends (contcatenates) string s2 to the end of string s1. The result will be null
terminated. The argument s1 must point to a character array big enough to hold the resultant string.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
char buffer[256];
char * s1, * s2;
See Also
strcpy(), strcmp(), strncat(), strlen()
240
Library Functions
Return Value
The value of s1 is returned.
241
Library Functions
STRCHR, STRICHR
Synopsis
#include <string.h>
Description
The strchr() function searches the string s for an occurrence of the character c. If one is found, a
pointer to that character is returned, otherwise NULL is returned.
The strichr() function is the case-insensitive version of this function.
Example
#include <strings.h>
#include <stdio.h>
void
main (void)
{
static char temp[] = "Here it is...";
char c = s;
if(strchr(temp, c))
printf("Character %c was found in string\n", c);
else
printf("No character was found in string");
}
242
Library Functions
See Also
strrchr(), strlen(), strcmp()
Return Value
A pointer to the first match found, or NULL if the character does not exist in the string.
Note
The functions takes an integer argument for the character, only the lower 8 bits of the value are used.
243
Library Functions
STRCMP, STRICMP
Synopsis
#include <string.h>
Description
The strcmp() function compares its two, null terminated, string arguments and returns a signed
integer to indicate whether s1 is less than, equal to or greater than s2. The comparison is done with
the standard collating sequence, which is that of the ASCII character set.
The stricmp() function is the case-insensitive version of this function.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
int i;
See Also
244
Library Functions
Return Value
A signed integer less than, equal to or greater than zero.
Note
Other C implementations may use a different collating sequence; the return value is negative, zero
or positive, i.e. do not test explicitly for negative one (-1) or one (1).
245
Library Functions
STRCPY
Synopsis
#include <string.h>
Description
This function copies a null terminated string s2 to a character array pointed to by s1. The destination
array must be large enough to hold the entire string, including the null terminator.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
char buffer[256];
char * s1, * s2;
See Also
strncpy(), strlen(), strcat(), strlen()
246
Library Functions
Return Value
The destination buffer pointer s1 is returned.
247
Library Functions
STRCSPN
Synopsis
#include <string.h>
Description
The strcspn() function returns the length of the initial segment of the string pointed to by s1 which
consists of characters NOT from the string pointed to by s2.
Example
#include <stdio.h>
#include <string.h>
void
main (void)
{
static char set[] = "xyz";
See Also
strspn()
Return Value
Returns the length of the segment.
248
Library Functions
STRLEN
Synopsis
#include <string.h>
Description
The strlen() function returns the number of characters in the string s, not including the null termina-
tor.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
char buffer[256];
char * s1, * s2;
Return Value
The number of characters preceding the null terminator.
249
Library Functions
STRNCAT
Synopsis
#include <string.h>
Description
This function appends (concatenates) string s2 to the end of string s1. At most n characters will be
copied, and the result will be null terminated. s1 must point to a character array big enough to hold
the resultant string.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
char buffer[256];
char * s1, * s2;
250
Library Functions
See Also
strcpy(), strcmp(), strcat(), strlen()
Return Value
The value of s1 is returned.
251
Library Functions
STRNCMP, STRNICMP
Synopsis
#include <string.h>
Description
The strncmp() function compares its two, null terminated, string arguments, up to a maximum of n
characters, and returns a signed integer to indicate whether s1 is less than, equal to or greater than s2.
The comparison is done with the standard collating sequence, which is that of the ASCII character
set.
The strnicmp() function is the case-insensitive version of this function.
Example
#include <stdio.h>
#include <string.h>
void
main (void)
{
int i;
i = strcmp("abcxyz", "abcxyz");
if(i == 0)
printf("Both strings are equal\n");
else if(i > 0)
printf("String 2 less than string 1\n");
else
printf("String 2 is greater than string 1\n");
}
See Also
strlen(), strcmp(), strcpy(), strcat()
252
Library Functions
Return Value
A signed integer less than, equal to or greater than zero.
Note
Other C implementations may use a different collating sequence; the return value is negative, zero
or positive, i.e. do not test explicitly for negative one (-1) or one (1).
253
Library Functions
STRNCPY
Synopsis
#include <string.h>
Description
This function copies a null terminated string s2 to a character array pointed to by s1. At most
n characters are copied. If string s2 is longer than n then the destination string will not be null
terminated. The destination array must be large enough to hold the entire string, including the null
terminator.
Example
#include <string.h>
#include <stdio.h>
void
main (void)
{
char buffer[256];
char * s1, * s2;
254
Library Functions
See Also
strcpy(), strcat(), strlen(), strcmp()
Return Value
The destination buffer pointer s1 is returned.
255
Library Functions
STRPBRK
Synopsis
#include <string.h>
Description
The strpbrk() function returns a pointer to the first occurrence in string s1 of any character from
string s2, or a null pointer if no character from s2 exists in s1.
Example
#include <stdio.h>
#include <string.h>
void
main (void)
{
char * str = "This is a string.";
while(str != NULL) {
printf( "%s\n", str );
str = strpbrk( str+1, "aeiou" );
}
}
Return Value
Pointer to the first matching character, or NULL if no character found.
256
Library Functions
STRRCHR, STRRICHR
Synopsis
#include <string.h>
Description
The strrchr() function is similar to the strchr() function, but searches from the end of the string
rather than the beginning, i.e. it locates the last occurrence of the character c in the null terminated
string s. If successful it returns a pointer to that occurrence, otherwise it returns NULL.
The strrichr() function is the case-insensitive version of this function.
Example
#include <stdio.h>
#include <string.h>
void
main (void)
{
char * str = "This is a string.";
while(str != NULL) {
printf( "%s\n", str );
str = strrchr( str+1, s);
}
}
257
Library Functions
See Also
strchr(), strlen(), strcmp(), strcpy(), strcat()
Return Value
A pointer to the character, or NULL if none is found.
258
Library Functions
STRSPN
Synopsis
#include <string.h>
Description
The strspn() function returns the length of the initial segment of the string pointed to by s1 which
consists entirely of characters from the string pointed to by s2.
Example
#include <stdio.h>
#include <string.h>
void
main (void)
{
printf("%d\n", strspn("This is a string", "This"));
printf("%d\n", strspn("This is a string", "this"));
}
See Also
strcspn()
Return Value
The length of the segment.
259
Library Functions
STRSTR, STRISTR
Synopsis
#include <string.h>
Description
The strstr() function locates the first occurrence of the sequence of characters in the string pointed
to by s2 in the string pointed to by s1.
The stristr() routine is the case-insensitive version of this function.
Example
#include <stdio.h>
#include <string.h>
void
main (void)
{
printf("%d\n", strstr("This is a string", "str"));
}
Return Value
Pointer to the located string or a null pointer if the string was not found.
260
Library Functions
STRTOK
Synopsis
#include <string.h>
Description
A number of calls to strtok() breaks the string s1 (which consists of a sequence of zero or more text
tokens separated by one or more characters from the separator string s2) into its separate tokens.
The first call must have the string s1. This call returns a pointer to the first character of the first
token, or NULL if no tokens were found. The inter-token separator character is overwritten by a null
character, which terminates the current token.
For subsequent calls to strtok(), s1 should be set to a null pointer. These calls start searching
from the end of the last token found, and again return a pointer to the first character of the next token,
or NULL if no further tokens were found.
Example
#include <stdio.h>
#include <string.h>
void
main (void)
{
char * ptr;
char * buf = "This is a string of words.";
char * sep_tok = ".,?! ";
261
Library Functions
Return Value
Returns a pointer to the first character of a token, or a null pointer if no token was found.
Note
The separator string s2 may be different from call to call.
262
Library Functions
TAN
Synopsis
#include <math.h>
Description
The tan() function calculates the tangent of f.
Example
#include <math.h>
#include <stdio.h>
#define C 3.141592/180.0
void
main (void)
{
double i;
See Also
sin(), cos(), asin(), acos(), atan(), atan2()
Return Value
The tangent of f.
263
Library Functions
TIME
Synopsis
#include <time.h>
Description
This function is not provided as it is dependant on the target system supplying the current time. This
function will be user implemented. When implemented, this function should return the current time
in seconds since 00:00:00 on Jan 1, 1970. If the argument t is not equal to NULL, the same value is
stored into the object pointed to by t.
Example
#include <stdio.h>
#include <time.h>
void
main (void)
{
time_t clock;
time(&clock);
printf("%s", ctime(&clock));
}
See Also
Return Value
This routine when implemented will return the current time in seconds since 00:00:00 on Jan 1,
1970.
264
Library Functions
Note
The time() routine is not supplied, if required the user will have to implement this routine to the
specifications outlined above.
265
Library Functions
#include <ctype.h>
Description
The toupper() function converts its lower case alphabetic argument to upper case, the tolower()
routine performs the reverse conversion and the toascii() macro returns a result that is guaranteed
in the range 0-0177. The functions toupper() and tolower() return their arguments if it is not an
alphabetic character.
Example
#include <stdio.h>
#include <ctype.h>
#include <string.h>
void
main (void)
{
char * array1 = "aBcDE";
int i;
See Also
islower(), isupper(), isascii(), et. al.
266
Library Functions
UNGETCH
Synopsis
#include <conio.h>
Description
The ungetch() function will push back the character c onto the console stream, such that a subse-
quent getch() operation will return the character. At most one level of push back will be allowed.
See Also
getch(), getche()
267
Library Functions
#include <stdarg.h>
Description
These macros are provided to give access in a portable way to parameters to a function represented in
a prototype by the ellipsis symbol (...), where type and number of arguments supplied to the function
are not known at compile time.
The rightmost parameter to the function (shown as parmN) plays an important role in these
macros, as it is the starting point for access to further parameters. In a function taking variable num-
bers of arguments, a variable of type va_list should be declared, then the macro va_start() invoked
with that variable and the name of parmN. This will initialize the variable to allow subsequent calls
of the macro va_arg() to access successive parameters.
Each call to va_arg() requires two arguments; the variable previously defined and a type name
which is the type that the next parameter is expected to be. Note that any arguments thus accessed
will have been widened by the default conventions to int, unsigned int or double. For example if a
character argument has been passed, it should be accessed by va_arg(ap, int) since the char will
have been widened to int.
An example is given below of a function taking one integer parameter, followed by a number
of other parameters. In this example the function expects the subsequent parameters to be pointers
to char, but note that the compiler is not aware of this, and it is the programmers responsibility to
ensure that correct arguments are supplied.
Example
#include <stdio.h>
#include <stdarg.h>
void
pf (int a, ...)
{
268
Library Functions
va_list ap;
va_start(ap, a);
while(a--)
puts(va_arg(ap, char *));
va_end(ap);
}
void
main (void)
{
pf(3, "Line 1", "line 2", "line 3");
}
269
Library Functions
XTOI
Synopsis
#include <stdlib.h>
Description
The xtoi() function scans the character string passed to it, skipping leading blanks reading an optional
sign, and converts an ASCII representation of a hexadecimal number to an integer.
Example
#include <stdlib.h>
#include <stdio.h>
void
main (void)
{
char buf[80];
int i;
gets(buf);
i = xtoi(buf);
printf("Read %s: converted to %x\n", buf, i);
}
See Also
atoi()
Return Value
A signed integer. If no number is found in the string, zero will be returned.
270
Library Functions
271
Library Functions
272
Appendix B
This chapter lists most error, warning and advisory messages from all HI-TECH C compilers, with
an explanation of each message. Most messages have been assigned a unique number which appears
in brackets before each message in this chapter, and which is also printed by the compiler when the
message is issued. The messages shown here are sorted by their number. Un-numbered messages
appear toward the end and are sorted alphabetically.
The name of the application(s) that could have produced the messages are listed in brackets
opposite the error message. In some cases examples of code or options that could trigger the error
are given. The use of * in the error message is used to represent a string that the compiler will
substitute that is specific to that particular error.
Note that one problem in your C or assembler source code may trigger more than one error
message.
A #if or similar block was not terminated with a matching #endif, e.g.:
273
Error and Warning Messages
#ifdef FOO
result = foo;
#else
result = bar;
#elif defined(NEXT) /* the #else above terminated the #if */
result = next(0);
#endif
#ifdef FOO
result = foo;
#endif
result = bar;
#elif defined(NEXT) /* the #endif above terminated the #if */
result = next(0);
#endif
274
Error and Warning Messages
A #endasm operator has been encountered, but there was no previous matching #asm, e.g.:
void cleardog(void)
{
clrwdt
#endasm /* this ends the in-line assembler, only where did it begin? */
}
It is not legal to nest #asm directives. Check for a missing or misspelt #endasm directive, e.g.:
#asm
move r0, #0aah
#asm ; the previous #asm must be closed before opening another
sleep
#endasm
The compiler does not understand the # directive. It is probably a misspelling of a pre-processor #
directive, e.g.:
The preprocessor directives #if, #ifdef and #ifndef must have an argument. The argument to #if
should be an expression, while the argument to #ifdef or #ifndef should be a single name, e.g.:
275
Error and Warning Messages
(110) too many file arguments; usage: cpp [input [output]] (Preprocessor)
CPP should be invoked with at most two file arguments. Contact HI-TECH Support if the preproces-
sor is being executed by a compiler driver.
#define ONE 1
/* elsewhere: */
/* Is this correct? It will overwrite the first definition. */
#define ONE one
276
Error and Warning Messages
The named macro has been defined in such a manner that expanding it causes a recursive expansion
of itself!
(116) end of file within preprocessor macro argument from line * (Preprocessor)
A macro argument has not been terminated. This probably means the closing parenthesis has been
omitted from a macro invocation. The line number given is the line where the macro argument
started, e.g.:
A constant in a #if expression should only occur in syntactically correct places. This error is most
probably caused by omission of an operator, e.g.:
#if FOO BAR /* woops -- did you mean: #if FOO == BAR ? */
The preprocessor filled up its expression evaluation stack in a #if expression. Simplify the expres-
sion it probably contains too many parenthesized subexpressions.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
An operator has been encountered in a #if expression that is incorrectly placed, e.g. two binary
operators are not separated by a value, e.g.:
277
Error and Warning Messages
Expressions in #if lines are evaluated using a stack with a size of 128. It is possible for very complex
expressions to overflow this. Simplify the expression.
The evaluation of a #if expression found mismatched parentheses. Check the expression for correct
parenthesisation, e.g.:
A colon operator has been encountered in a #if expression that does not match up with a corre-
sponding ? operator, e.g.:
#if XXX : YYY /* did you mean: #if COND ? XXX : YYY */
There is a character in a #if expression that has no business being there. Valid characters are the
letters, digits and those comprising the acceptable operators, e.g.:
There is a non-printable character in a #if expression that has no business being there. Valid char-
acters are the letters, digits and those comprising the acceptable operators, e.g.:
278
Error and Warning Messages
279
Error and Warning Messages
The preprocessor found an illegal type combination in the argument to sizeof() in a #if expres-
sion, e.g.
Sizeof() was used in a preprocessor #if expression, but no type was specified. The argument to
sizeof() in a preprocessor expression must be a valid simple type, or pointer to a simple type, e.g.:
The preprocessor has made an internal error in evaluating a sizeof() expression. Check for a
malformed type specifier. This is an internal error. Contact HI-TECH Software technical support
with details.
The preprocessor found a syntax error in the argument to sizeof, in a #if expression. Probable
causes are mismatched parentheses and similar things, e.g.:
The preprocessor has tried to evaluate an expression with an operator it does not understand. This is
an internal error. Contact HI-TECH Software technical support with details.
280
Error and Warning Messages
(140) cant open * file "*": * (Driver, Preprocessor, Code Generator, Assembler)
The command file specified could not be opened for reading. Confirm the spelling and path of the
file specified on the command line, e.g.:
picc @communds
picc @commands
281
Error and Warning Messages
282
Error and Warning Messages
(160) too many errors (Preprocessor, Parser, Code Generator, Assembler, Linker)
There were so many errors that the compiler has given up. Correct the first few errors and many of
the later ones will probably go away.
283
Error and Warning Messages
#if defined(END)
#define NEXT
#endif END /* END would be better in a comment here */
The #include file name had to be converted to lowercase before it could be opened, e.g.:
(165) #include filename "*" does not match actual name (check upper/lower case) (Prepro-
cessor)
In Windows versions this means the file to be included actually exists and is spelt the same way as
the #include filename, however the case of each does not exactly match. For example, specifying
#include code.c will include Code.c if it is found. In Linux versions this warning could occur
if the file wasnt found.
The list of values to the preprocessor (CPP) -S option is incomplete. This should not happen if the
preprocessor is being invoked by the compiler driver. The values passes to this option represent the
sizes of char, short, int, long, float and double types.
(167) too many values specified with -S option; "*" unused (Preprocessor)
There were too many values supplied to the -S preprocessor option. See the Error Message -s, too
few values specified in * on page 284.
This option given to the component which caused the error is not recognized.
284
Error and Warning Messages
The symbol supplied as argument to #undef was not already defined. This warning may be disabled
with some compilers. This warning can be avoided with code like:
#ifdef SYM
#undef SYM /* only undefine if defined */
#endif
(171) wrong number of preprocessor macro arguments for "*" (* instead of *)(Preprocessor)
A macro has been invoked with the wrong number of arguments, e.g.:
The stringization operator # (not to be confused with the leading # used for preprocessor control
lines) must be followed by a formal macro parameter, e.g.:
If you need to stringize a token, you will need to define a special macro to do it, e.g.
#define __mkstr__(x) #x
then use __mkstr__(token) wherever you need to convert a token into a string.
A symbol on a #if expression was not a defined preprocessor macro. For the purposes of this
expression, its value has been taken as zero. This warning may be disabled with some compilers.
Example:
285
Error and Warning Messages
Multi-byte constants are not portable, and in fact will be rejected by later passes of the compiler,
e.g.:
#if CHAR == ab
#define MULTI
#endif
Inside a #if expression, there is a division by zero which has been treated as yielding zero, e.g.:
A new line is missing at the end of the line. Each line, including the last line, must have a new line
at the end. This problem is normally introduced by editors.
A macro name specified in a -U option to the preprocessor was not initially defined, and thus cannot
be undefined.
This warning is issued when nested comments are found. A nested comment may indicate that a
previous closing comment marker is missing or malformed, e.g.:
Comments begun inside an included file must end inside the included file.
286
Error and Warning Messages
Note that even if a structure only contains an int, for example, it cannot be assigned to an int
variable, and vice versa.
int a, b, c, d;
a = b(c+d); /* b is not a function -- did you mean a = b*(c+d) ? */
int get_value(void);
void main(void)
{
287
Error and Warning Messages
int input;
input = get_value(6); /* woops -- the parameter should not be here */
}
int a;
switch(input) {
case a: /* woops! you cannot use a variable as part of a case label */
input++;
}
int i, array[10];
i = array[3.5]; /* woops -- exactly which element do you mean? */
288
Error and Warning Messages
int a;
a.b = 9; /* woops -- a is not a structure */
289
Error and Warning Messages
int array[10];
int * ip;
char c;
array = ip; /* array is not a variable, it cannot be written to */
290
Error and Warning Messages
*(int *)&c = 1
bit b;
int * ip;
ip = &b; /* woops -- cannot take the address of a bit object */
void run(void)
{
step();
return 1; /* either run should not be void, or remove the 1 */
}
291
Error and Warning Messages
int * ip;
char * cp, * cp2;
cp = flag ? ip : cp2; /* result of ? : will either be int * or char * */
#pragma pack 2
292
Error and Warning Messages
Pragmas for all the standard printf-like function are already contained in <stdio.h>.
293
Error and Warning Messages
294
Error and Warning Messages
The only context in which two successive dots may appear is as part of the ellipsis symbol, which
must have 3 dots. (An ellipsis is used in function prototypes to indicate a variable number of param-
eters.)
Either .. was meant to be an ellipsis symbol which would require you to add an extra dot, or it
was meant to be a structure member operator which would require you remove one dot.
This character is illegal in the C code. Valid characters are the letters, digits and those comprising
the acceptable operators, e.g.:
This is an internal compiler error. Contact HI-TECH Software technical support with details.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
295
Error and Warning Messages
int address;
char LOCK @ address;
int twice(int a)
{
return a*2;
}
long twice(long a) /* only one prototype & definition of rv can exist */
{
return a*2;
}
Note that variables with the same name, but defined with different scopes are legal, but not recom-
mended.
296
Error and Warning Messages
There are too many initializers for this object. Check the number of initializers against the object
definition (array or structure), e.g.:
The initialisation of this object is syntactically incorrect. Check for the correct placement and num-
ber of braces and commas, e.g.:
A switch operation must have an expression that is either an integral type or an enumerated value,
e.g:
double d;
switch(d) { /* woops -- this must be integral */
case 1.0:
d = 0;
}
A break or continue statement has been found that is not enclosed in an appropriate control struc-
ture. A continue can only be used inside a while, for or do while loop, while break can only be
used inside those loops or a switch statement, e.g.:
switch(input) {
case 0:
if(output == 0)
input = 0xff;
} /* woops! this shouldnt be here and closed the switch */
break; /* this should be inside the switch */
297
Error and Warning Messages
There is only allowed to be one default label in a switch statement. You have more than one, e.g.:
switch(a) {
default: /* if this is the default case... */
b = 9;
break;
default: /* then what is this? */
b = 10;
break;
A label has been encountered called default but it is not enclosed by a switch statement. A
default label is only legal inside the body of a switch statement.
If there is a switch statement before this default label, there may be one too many closing
braces in the switch code which would prematurely terminate the switch statement. See example
for Error Message case not in switch on page 298.
A case label has been encountered, but there is no enclosing switch statement. A case label may
only appear inside the body of a switch statement.
If there is a switch statement before this case label, there may be one too many closing braces
in the switch code which would prematurely terminate the switch statement, e.g.:
switch(input) {
case 0:
count++;
break;
case 1:
if(count>MAX)
count= 0;
} /* woops -- this shouldnt be here */
break;
case 2: /* error flagged here */
298
Error and Warning Messages
The same name is used for a label more than once in this function. Note that the scope of labels is
the entire function, not just the block that encloses a label, e.g.:
start:
if(a > 256)
goto end;
start: /* error flagged here */
if(a == 0)
goto start; /* which start label do I jump to? */
An else keyword has been encountered that cannot be associated with an if statement. This may
mean there is a missing brace or other syntactic error, e.g.:
The compiler has encountered what looks like a function or other declaration, but the preceding
function has not been ended with a closing brace. This probably means that a closing brace has been
omitted from somewhere in the previous function, although it may well not be the last one, e.g.:
void set(char a)
{
PORTA = a;
/* the closing brace was left out here */
void clear(void) /* error flagged here */
{
PORTA = 0;
}
299
Error and Warning Messages
300
Error and Warning Messages
struct {
int a, b, c;
} data;
if(data.d) /* woops -- there is no member d in this structure */
return;
The only storage class allowed for a function parameter is register, e.g.:
There are two occurrences of the same qualifier in this type specification. This can occur either
directly or through the use of a typedef. Remove the redundant qualifier. For example:
far near int spooky; /* woops -- choose either far or near, not both */
301
Error and Warning Messages
struct {
int a;
int b;
int a; /* woops -- a different name is required here */
} input;
struct {
int a;
} ms;
struct {
int a;
} ms; /* was this meant to be the same name as above? */
struct {
int a;
int get(int); /* this should be a pointer: int (*get)(int); */
} object;
struct FREG {
char b0:1; /* woops -- these must be part of an int, not char */
char :6;
char b7:1;
} freg;
302
Error and Warning Messages
A colon appearing after a member name in a structure declaration indicates that the member is a
bitfield. An integral constant must appear after the colon to define the number of bits in the bitfield,
e.g.:
struct {
unsigned first: /* woops -- should be: unsigned first; */
unsigned second;
} my_struct;
If this was meant to be a structure with bitfields, then the following illustrates an example:
struct {
unsigned first : 4; /* 4 bits wide */
unsigned second: 4; /* another 4 bits */
} my_struct;
A structure or union member may not be given a storage class. Its storage class is determined by the
storage class of the structure, e.g.:
struct {
/* no additional qualifiers may be present with members */
static int first;
} ;
The code generator has encountered a variable definition whose storage class is invalid, e.g.:
303
Error and Warning Messages
304
Error and Warning Messages
305
Error and Warning Messages
306
Error and Warning Messages
int a;
void b; /* this makes no sense */
307
Error and Warning Messages
const char ccrv(void) /* woops! did you mean const * char ccrv(void) ? */
{ /* error flagged here */
return ccip;
}
int process(input)
int unput; /* woops -- that should be int input; */
{
}
308
Error and Warning Messages
#asm
mov r0, #55
mov [r1], r0
} /* woops -- where is the #endasm */
void main(void)
{
init();
run(); /* is that it? What about the close brace */
309
Error and Warning Messages
while(a) {
b = a-- /* woops -- where is the semicolon? */
} /* error is flagged here */
310
Error and Warning Messages
Note: Omitting a semicolon from statements not preceding a close brace or keyword typically results
in some other error being issued for the following code which the parser assumes to be part of the
original statement.
An opening brace was expected here. This error may be the result of a function definition missing
the opening brace, e.g.:
A closing brace was expected here. This error may be the result of a initialized array missing the
closing brace, e.g.:
An opening parenthesis, (, was expected here. This must be the first token after a while, for, if,
do or asm keyword, e.g.:
311
Error and Warning Messages
do {
func(i++);
} /* do the block while what condition is true? */
if(i > 5) /* error flagged here */
end();
switch(input) {
case 0; /* woops -- that should have been: case 0: */
state = NEW;
if(a)
goto 20; /* this is not BASIC -- a valid C label must follow a goto */
struct {
int a;
} my_struct;
312
Error and Warning Messages
(327) long long int argument required in printf-style format string (Parser)
A long long argument is required for this format specifier. Check the number and order of format
specifiers and corresponding arguments, e.g.:
Note that not all HI-TECH C compilers provide support for a long long integer type.
313
Error and Warning Messages
314
Error and Warning Messages
char * cp = hi
there; /* this is okay, but is it what you had intended? */
extern int other = 99; /* if its extern and not allocated storage,
how can it be initialized? */
315
Error and Warning Messages
int get_value(void)
{
if(flag)
return val++;
return; /* what is the return value in this instance? */
}
316
Error and Warning Messages
{
int input; /* local blockscope input */
a = input; /* this will use the local variable. Is this right? */
int process(int a)
{
extern int away; /* this would be better outside the function */
return away + a;
}
int process(input)
int input; /* warning flagged here */
{
}
317
Error and Warning Messages
318
Error and Warning Messages
will perform a sign extension of the char variable to the longer type. If you do not want this to take
place, use a cast, e.g.:
ui = (unsigned char)sc;
double dd;
int i;
i = dd; /* is this really what you meant? */
If you do intend to use an expression like this, then indicate that this is so by a cast:
i = (int)dd;
int * ip;
int i;
ip = i; /* woops -- did you mean ip = &i ? */
If you do intend to use an expression like this, then indicate that this is so by a cast:
ip = (int *)i;
319
Error and Warning Messages
int * ip;
int i;
i = ip; /* woops -- did you mean i = *ip ? */
If you do intend to use an expression like this, then indicate that this is so by a cast:
i = (int)ip;
A pointer of one type (i.e. pointing to a particular kind of object) has been converted into a pointer
of a different type. This will usually mean you have used the wrong variable, but if this is genuinely
what you want to do, use a typecast to inform the compiler that you want the conversion and the
warning will be suppressed, e.g.:
long input;
char * cp;
cp = &input; /* is this correct? */
This is common way of accessing bytes within a multi-byte variable. To indicate that this is the
intended operation of the program, use a cast:
This warning may also occur when converting between pointers to objects which have the same type,
but which have different qualifiers, e.g.:
char * cp;
/* yes, but what sort of characters? */
cp = I am a string of characters;
If the default type for string literals is const char *, then this warning is quite valid. This should
be written:
Omitting a qualifier from a pointer type is often disastrous, but almost certainly not what you intend.
320
Error and Warning Messages
321
Error and Warning Messages
char * get_addr(void)
{
char c;
/* returning this is dangerous; the pointer could be dereferenced */
return &c;
}
322
Error and Warning Messages
void main(void)
{
/* at this point the compiler assumes set is extern... */
set(10L, 6);
}
static void set(long a, int b) /* now it finds out otherwise */
{
PORTA = a + b;
}
struct {
signed int sign: 1; /* this must be unsigned */
signed int value: 15;
} ;
323
Error and Warning Messages
This declaration does not include a basic type, so int has been assumed. This declaration is not
illegal, but it is preferable to include a basic type to make it clear what is intended, e.g.:
char c;
i; /* dont let the compiler make assumptions, use : int i */
func(); /* ditto, use: extern int func(int); */
A comma was expected here. This could mean you have left out the comma between two identifiers
in a declaration list. It may also mean that the immediately preceding type name is misspelled, and
has thus been interpreted as an identifier, e.g.:
unsigned char a;
/* thinks: chat & b are unsigned, but where is the comma? */
unsigned chat b;
An unsigned type was expected where a signed type was given and was implicitly cast to unsigned,
e.g.:
The basic type of a cast to a qualified basic type was missing and assumed to be int., e.g.:
This is an internal compiler error. Contact HI-TECH Software technical support with details.
324
Error and Warning Messages
325
Error and Warning Messages
The map file name has been specified to the linker for a second time. This should not occur if you
are using a compiler driver. If invoking the linker manually, ensure that only one instance of this
option is present on the command line. See Section 5.9.9 for information on the correct syntax for
this option.
This linker -o flag is illegal, or another -o option has been encountered. A -o option to the linker
must be immediately followed by a filename with no intervening space.
There have been too many -p options passed to the linker, or a -p option was not followed by any
arguments. The arguments of separate -p options may be combined and separated by commas.
The symbol file name has been specified to the linker for a second time. This should not occur if you
are using a compiler driver. If invoking the linker manually, ensure that only one instance of either
of these options is present on the command line.
The maximum number of errors before aborting must be specified following the -j linker option.
326
Error and Warning Messages
327
Error and Warning Messages
328
Error and Warning Messages
329
Error and Warning Messages
-GA/f0+10
-GA/f0h+10
330
Error and Warning Messages
-SCODE=f000
-SCODE=f000h
-DCODE
What is the delta value for this class? Maybe you meant something like:
-DCODE=2
-ACODE
-ACODE=0h-1fffh
331
Error and Warning Messages
332
Error and Warning Messages
-AENTRY=0-0FFh-1FF
-AENTRY=0-0FFh-1FFh
-ACODE=0h-3fffh/a000
-ACODE=0h-3fffh/a000h
-AENTRY=0-0FFhxf
-AENTRY=0-0FFhxfh
333
Error and Warning Messages
-pbss=f000
-pbss=f000h
-pbss=data+f000
-pbss=data+f000h
(454) link and load address cant both be set to "." in -P option (Linker)
The link and load address of a psect have both been specified with a dot character. Only one of these
addresses may be specified in this manner, e.g.:
-Pmypsect=1000h/.
-Pmypsect=./1000h
Both of these options are valid and equivalent, however the following usage is ambiguous:
-Pmypsect=./.
334
Error and Warning Messages
335
Error and Warning Messages
The linker has found an undefined symbol in the FNSIZE record for a non-reentrant function. Contact
HI-TECH Support if this is not handwritten assembler code.
These functions (or function) call each other recursively. One or more of these functions has stat-
ically allocated local variables (compiled stack). Either use the reentrant keyword (if supported
with this compiler) or recode to avoid recursion, e.g.:
int test(int a)
{
if(a == 5) {
/* recursion may not be supported by some compilers */
return test(a++);
}
return 0;
}
(472) non-reentrant function "*" appears in multiple call graphs: rooted at "*" and "*"
(Linker)
This function can be called from both main-line code and interrupt code. Use the reentrant key-
word, if this compiler supports it, or recode to avoid using local variables or parameters, or duplicate
the function, e.g.:
The indicated function is never called from an interrupt function of the same interrupt level, e.g.:
336
Error and Warning Messages
#pragma interrupt_level 1
void foo(void)
{
...
}
#pragma interrupt_level 1
void interrupt bar(void)
{
// this function never calls foo()
}
(476) fixup overflow referencing * * (location 0x* (0x*+*), size *, value 0x*) (Linker)
The linker was asked to relocate (fixup) an item that would not fit back into the space after relocation.
See the following error message (477) for more information..
(477) fixup overflow in expression (location 0x* (0x*+*), size *, value 0x*) (Linker)
Fixup is the process conducted by the linker of replacing symbolic references to variables etc, in an
assembler instruction with an absolute value. This takes place after positioning the psects (program
sections or blocks) into the available memory on the target device. Fixup overflow is when the
value determined for a symbol is too large to fit within the allocated space within the assembler
instruction. For example, if an assembler instruction has an 8-bit field to hold an address and the
linker determines that the symbol that has been used to represent this address has the value 0x110,
then clearly this value cannot be inserted into the instruction.
The causes for this can be many, but hand-written assembler code is always the first suspect.
Badly written C code can also generate assembler that ultimately generates fixup overflow errors.
Consider the following error message.
337
Error and Warning Messages
This indicates that the file causing the problem was main.obj. This would be typically be the output
of compiling main.c or main.as. This tells you the file in which you should be looking. The next
number (8 in this example) is the record number in the object file that was causing the problem. If
you use the DUMP utility to examine the object file, you can identify the record, however you do not
normally need to do this.
The location (loc) of the instruction (0x1FD), the size (in bytes) of the field in the instruction
for the value (1) , and the value which is the actual value the symbol represents, is typically the only
information needed to track down the cause of this error. Note that a size which is not a multiple of
8 bits will be rounded up to the nearest byte size, i.e. a 7 bit space in an instruction will be shown as
1 byte.
Generate an assembler list file for the appropriate module. Look for the address specified in the
error message.
and to confirm, look for the symbol referenced in the assembler instruction at this address in the
symbol table at the bottom of the same file.
In this example, the instruction causing the problem takes an 8-bit offset into a bank of memory, but
clearly the address 0x1FC exceeds this size. Maybe the instruction should have been written as:
movwf (_foo&0ffh)
which masks out the top bits of the address containing the bank information.
If the assembler instruction that caused this error was generated by the compiler, in the assem-
bler list file look back up the file from the instruction at fault to determine which C statement has
generated this instruction. You will then need to examine the C code for possible errors. incorrectly
qualified pointers are an common trigger.
(478) * range check failed (location 0x* (0x*+*), value 0x* > limit 0x*) (Linker)
This is an internal compiler error. Contact HI-TECH Software technical support with details.
338
Error and Warning Messages
The specified symbol has been equated to an external symbol which, in turn, has been equated to the
first symbol.
The specified function has different signatures in different modules. This means it has been declared
differently, e.g. it may have been prototyped in one module and not another. Check what declarations
for the function are visible in the two modules specified and make sure they are compatible, e.g.:
This symbol has been defined in more than one place. The assembler will issue this error if a symbol
is defined more than once in the same module, e.g.:
_next:
move r0, #55
move [r1], r0
_next: ; woops -- choose a different name
The linker will issue this warning if the symbol (C or assembler) was defined multiple times in
different modules. The names of the modules are given in the error message. Note that C identifiers
often have an underscore prepended to their name after compilation.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
339
Error and Warning Messages
A psect cannot be in more than one class. This is either due to assembler modules with conflicting
class= options to the PSECT directive, or use of the -C option to the linker, e.g.:
psect final,class=CODE
finish:
/* elsewhere: */
psect final,class=ENTRY
The specified psect has been placed with a psect using the psect with flag. The psect it has been
placed with does not exist, e.g.:
The selector value for this psect has been defined more than once.
This psect has had its type defined differently by different modules. This probably means you are
trying to link incompatible object modules, e.g. linking 386 flat model code with 8086 real mode
code.
A global psect has been defined in two different memory spaces. Either rename one of the psects or,
if they are the same psect, place them in the same memory space using the space psect flag, e.g.:
psect spdata,class=RAM,space=0
ds 6
; elsewhere:
psect spdata,class=RAM,space=1
340
Error and Warning Messages
A global psect has been defined with two different delta values, e.g.:
psect final,class=CODE,delta=2
finish:
; elsewhere:
psect final,class=CODE,delta=1
A class has been defined in two different memory spaces. Either rename one of the classes or, if they
are the same class, place them in the same memory space.
(491) cant find 0x* words for psect "*" in segment "*" (Linker)
One of the main tasks the linker performs is positioning the blocks (or psects) of code and data that
is generated from the program into the memory available for the target device. This error indicates
that the linker was unable to find an area of free memory large enough to accommodate one of the
psects. The error message indicates the name of the psect that the linker was attempting to position
and the segment name which is typically the name of a class which is defined with a linker -A option.
Section 3.9.1 lists each compiler-generated psect and what it contains. Typically psect names
which are, or include, text relate to program code. Names such as bss or data refer to variable
blocks. This error can be due to two reasons.
First, the size of the program or the programs data has exceeded the total amount of space on
the selected device. In other words, some part of your devices memory has completely filled. If this
is the case, then the size of the specified psect must be reduced.
The second cause of this message is when the total amount of memory needed by the psect being
positioned is sufficient, but that this memory is fragmented in such a way that the largest contiguous
block is too small to accommodate the psect. The linker is unable to split psects in this situation.
That is, the linker cannot place part of a psect at one location and part somewhere else. Thus, the
linker must be able to find a contiguous block of memory large enough for every psect. If this is the
cause of the error, then the psect must be split into smaller psects if possible.
To find out what memory is still available, generate and look in the map file, see Section 2.4.8 for
information on how to generate a map file. Search for the string UNUSED ADDRESS RANGES. Under
this heading, look for the name of the segment specified in the error message. If the name is not
present, then all the memory available for this psect has been allocated. If it is present, there will be
one address range specified under this segment for each free block of memory. Determine the size
of each block and compare this with the number of words specified in the error message.
341
Error and Warning Messages
Psects containing code can be reduced by using all the compilers optimizations, or restructuring
the program. If a code psect must be split into two or more small psects, this requires splitting a
function into two or more smaller functions (which may call each other). These functions may need
to be placed in new modules.
Psects containing data may be reduced when invoking the compiler optimizations, but the effect
is less dramatic. The program may need to be rewritten so that it needs less variables. Section
5.11.1 has information on interpreting the map files call graph if the compiler you are using uses
a compiled stack. (If the string Call graph: is not present in the map file, then the compiled
code uses a hardware stack.) If a data psect needs to be split into smaller psects, the definitions
for variables will need to be moved to new modules or more evenly spread in the existing modules.
Memory allocation for auto variables is entirely handled by the compiler. Other than reducing the
number of these variables used, the programmer has little control over their operation. This applies
whether the compiled code uses a hardware or compiled stack.
For example, after receiving the message:
Cant find 0x34 words (0x34 withtotal) for psect text in segment CODE
(error)
In the CODE segment, there is 0x1c (0x25f-0x244+1) bytes of space available in one block and 0x30
available in another block. Neither of these are large enough to accommodate the psect text which
is 0x34 bytes long. Notice, however, that the total amount of memory available is larger than 0x34
bytes.
342
Error and Warning Messages
343
Error and Warning Messages
344
Error and Warning Messages
345
Error and Warning Messages
(525) too many address (memory) spaces; space (*) ignored (Linker)
The limit to the number of address spaces (specified with the PSECT assembler directive) is currently
16.
(526) psect "*" not specified in -P option (first appears in "*") (Linker)
This psect was not specified in a -P or -A option to the linker. It has been linked at the end of the
program, which is probably not where you wanted it.
(593) cant find 0x* words (0x* withtotal) for psect "*" in segment "*" (Linker)
See error (491) on page 341.
346
Error and Warning Messages
347
Error and Warning Messages
348
Error and Warning Messages
349
Error and Warning Messages
(629) bad storage class "*" in SDB file "*" line * column * (Cromwell)
This is an internal compiler error. Contact HI-TECH Software technical support with details.
(630) invalid syntax for prefix list in SDB file "*" (Cromwell)
This is an internal compiler error. Contact HI-TECH Software technical support with details.
(631) syntax error at token "*" in SDB file "*" line * column * (Cromwell)
This is an internal compiler error. Contact HI-TECH Software technical support with details.
(636) checksum error in Intel HEX file "*" on line * (Cromwell, Hexmate)
A checksum error was found at the specified line in the specified Intel hex file. The HEX file may
be corrupt.
350
Error and Warning Messages
(668) prefix list did not match any SDB types (Cromwell)
This is an internal compiler error. Contact HI-TECH Software technical support with details.
(669) prefix list matched more than one SDB type (Cromwell)
This is an internal compiler error. Contact HI-TECH Software technical support with details.
351
Error and Warning Messages
(691) interrupt functions not implemented for 12 bit PIC (Code Generator)
The 12-bit range of PIC processors do not support interrupts.
352
Error and Warning Messages
(692) interrupt function "*" may only have one interrupt level (Code Generator)
Only one interrupt level may be associated with an interrupt function. Check to ensure that only
one interrupt_level pragma has been used with the function specified. This pragma may be used
more than once on main-line functions that are called from interrupt functions. For example:
#pragma interrupt_level 0
#pragma interrupt_level 1 /* which is it to be: 0 or 1? */
void interrupt isr(void)
{
switch(in) {
case 0: /* if this is case 0... */
b++;
break;
case 0: /* then what is this case? */
b--;
break;
}
353
Error and Warning Messages
bit proc(int a)
{
bit bb; /* woops -- this should be: static bit bb; */
bb = (a > 66);
return bb;
}
switch(input) {
} /* there is nothing to match the value of input */
354
Error and Warning Messages
355
Error and Warning Messages
This is an internal compiler error. Contact HI-TECH Software technical support with details.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
The code generator has been passed a pragma directive that it does not understand. This implies that
the pragma you have used is a HI-TECH specific pragma, but the specific compiler you are using
has not implemented this pragma.
The code generator has been passed a -M option that it does not understand. This should not happen
if it is being invoked by a standard compiler driver.
The intermediate code file produced by P1 is not the correct version for use with this code generator.
This is either that incompatible versions of one or more compilers have been installed in the same
directory, or a temporary file error has occurred leading to corruption of a temporary file. Check the
setting of the TEMP environment variable. If it refers to a long path name, change it to something
shorter. Contact HI-TECH Support with details if required.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
This is an internal compiler error. Contact HI-TECH Software technical support with details.
356
Error and Warning Messages
357
Error and Warning Messages
The code generator has been passed a pragma psect directive that has a badly formed string, e.g.:
The #pragma switch directive has been used with an invalid switch code generation method. Pos-
sible arguments are: auto, simple and direct.
The compiler detected an error when closing a file. Contact HI-TECH Support with details.
The code generator has been passed a declaration that results in an array having a zero dimension.
The maximum number of bits in a bit field is the same as the number of bits in an int, e.g. assuming
an int is 16 bits wide:
struct {
unsigned flag : 1;
unsigned value : 12;
unsigned cont : 6; /* woops -- that makes a total of 19 bits */
} object;
358
Error and Warning Messages
void fn1(void)
{
fn3( 7, fn2(3), fn2(9)); /* Offending call */
}
char fn2(char fred)
{
return fred + fn3(5,1,0);
}
char fn3(char one, char two, char three)
{
return one+two+three;
}
where fn1 is calling fn3, and two arguments are evaluated by calling fn2, which in turn calls fn3.
The program structure should be modified to prevent this type of call sequence.
359
Error and Warning Messages
void main(void)
{
int a;
if(a) /* woops -- a has never been assigned a value */
process();
}
{
int a;
a = 6;
if(a || b) /* a is 6, therefore this is always true */
b++;
signed char c;
c = 0xFF;
As a signed 8-bit quantity, c can only be assigned values -128 to 127. The constant is equal to 255
and is outside this range. If you mean to set all bits in this variable, then use either of:
c = ~0x0;
c = -1;
which will set all the bits in the variable regardless of the size of the variable and without warning.
This warning can also be triggered by intermediate values overflowing. For example:
360
Error and Warning Messages
361
Error and Warning Messages
{
int a, b;
a = 5;
/* this can never be false; always perform the true statement */
if(a == 4)
b = 6;
will produce code that sets a to 5, then immediately sets b to 6. No code will be produced for the
comparison if(a == 4). If a was a global variable, it may be that other functions (particularly
interrupt functions) may modify it and so tracking the variable cannot be performed.
This warning may indicate more than an optimization made by the compiler. It may indicate an
expression with missing or badly placed parentheses, causing the evaluation to yield a value different
to what you expected.
This warning may also be issued because you have written something like while(1). To produce
an infinite loop, use for(;;).
A similar situation arises with for loops, e.g.:
{
int a, b;
for(a=0; a!=10; a++) /* this loop must iterate at least once */
b = func(a);
In this case the code generator can again pick up that a is assigned the value 0, then immediately
checked to see if it is equal to 10. Because a is modified during the for loop, the comparison
362
Error and Warning Messages
code cannot be removed, but the code generator will adjust the code so that the comparison is not
performed on the first pass of the loop; only on the subsequent passes. This may not reduce code
size, but it will speed program execution.
(758) constant conditional branch: possible use of "=" instead of "==" (Code Generator)
There is an expression inside an if or other conditional construct, where a constant is being assigned
to a variable. This may mean you have inadvertently used an assignment = instead of a compare ==,
e.g.:
int a, b;
/* this can never be false; always perform the true statement */
if(a = 4)
b = 6;
will assign the value 4 to a, then , as the value of the assignment is always true, the comparison can
be omitted and the assignment to b always made. Did you mean:
/* this can never be false; always perform the true statement */
if(a == 4)
b = 6;
which checks to see if a is equal to 4.
363
Error and Warning Messages
unsigned char c;
if(c > 300) /* woops -- how can this be true? */
close();
unsigned char c;
if(c >= 0)
will always be true, because an unsigned value can never be less than zero.
char c;
if(c >= -128)
will always be true, because an 8 bit signed char has a maximum negative value of -128.
364
Error and Warning Messages
unsigned int a;
if(a == -10) /* if a is unsigned, how can it be -10? */
b = 9;
(777) cant allocate space for opnd structure within object "*", (offs: *) (Assembler)
The assembler has run out of memory.
365
Error and Warning Messages
psect my_text,local,class=CODE,with=basecode
which will define a psect called my_text and place this in the same page as the psect basecode.
366
Error and Warning Messages
367
Error and Warning Messages
368
Error and Warning Messages
(816) duplicate ARCH specification in chipinfo file "*" at line * (Assembler, Driver)
The chipinfo file has a processor section with multiple ARCH values. Only one ARCH value is
allowed. If you have not manually edited the chip info file, contact HI-TECH Support with details.
369
Error and Warning Messages
(825) too many RAMBANK lines in chipinfo file for "*" (Assembler)
The chipinfo file contains a processor section with too many RAMBANK fields. Reduce the number
of values.
LIST C=10 ; the page width will need to be wider than this
370
Error and Warning Messages
getval MACRO
mov r0, r1
ENDM
getval EQU 55h ; woops -- choose a different name to the macro
371
Error and Warning Messages
_next:
move r0, #55
move [r1], r0
_next: ; woops -- choose a different name
The linker will issue this warning if the symbol (C or assembler) was defined multiple times in
different modules. The names of the modules are given in the error message. Note that C identifiers
often have an underscore prepended to their name after compilation.
372
Error and Warning Messages
A local psect may not have the same name as a global psect, e.g.:
The global flag is the default for a psect if its scope is not explicitly stated.
The parameter to the LIST assembler controls C= option (which sets the column width of the listing
output) must be a positive decimal constant number, e.g.:
LIST C=a0h ; constant must be decimal and positive, try: LIST C=80
The parameter to the LIST assembler controls N option (which sets the page length for the listing
output) must be a positive constant number, e.g.:
A symbol has been declared as EXTRN but is also defined in the current module.
373
Error and Warning Messages
(864) argument to "size" psect flag must specify a positive constant (Assembler)
The parameter to the PSECT assembler directives size option must be a positive constant number,
e.g.:
psect spdata,class=RAM,size=400
; elsewhere:
psect spdata,class=RAM,size=500
(866) argument to "reloc" psect flag must specify a positive constant (Assembler)
The parameter to the PSECT assembler directives reloc option must be a positive constant number,
e.g.:
psect spdata,class=RAM,reloc=4
; elsewhere:
psect spdata,class=RAM,reloc=8
(868) argument to "delta" psect flag must specify a positive constant (Assembler)
The parameter to the PSECT assembler directives DELTA option must be a positive constant number,
e.g.:
374
Error and Warning Messages
(870) argument to "pad" psect flag must specify a positive constant (Assembler)
The parameter to the PSECT assembler directives PAD option must be a non-zero positive integer.
(871) argument to "space" psect flag must specify a positive constant (Assembler)
The parameter to the PSECT assembler directives space option must be a positive constant number,
e.g.:
psect spdata,class=RAM,space=0
; elsewhere:
psect spdata,class=RAM,space=1
psect text,class=CODE
Look for other psect definitions that specify a different class name.
psect bss,with=data
Look for other psect definitions that specify a different with psect name.
375
Error and Warning Messages
(880) invalid number of parameters. Use "* HELP" for help (Driver)
Improper command-line usage of the of the compilers driver.
(884) please ensure you have write permissions to the configuration file (Driver)
The compiler was not successfully setup using the --setup driver option because the driver was
unable to access the XML configuration file. Ensure that you have write permission to this file. The
driver will search the following configuration files in order:
the file /etc/htsoft.xml if the directory /etc is writable and there is no .htsoft.xml file
in your home directory
If none of the files can be located then the above error will occur.
376
Error and Warning Messages
(890) contact HI-TECH Software to purchase and re-activate this compiler (Driver)
The evaluation period of this demo installation of the compiler has expired. You will need to pur-
chase the compiler to re-activate it. If however you sincerely believe the evaluation period has ended
prematurely please contact HI-TECH technical support.
(895) cant request and specify options in the one command (Driver)
The usage of the driver options --getoption and --setoption is mutually exclusive.
(899) cant open option file "*" for application "*": * (Driver)
An option file specified by a --getoption or --setoption driver option could not be opened. If
you are using the --setoption option ensure that the name of the file is spelt correctly and that
it exists. If you are using the --getoption option ensure that this file can be created at the given
location or that it is not in use by any other application.
377
Error and Warning Messages
The subcomponent listed failed to execute. Does the file exist? Try re-installing the compiler.
(902) no chip name specified; use "* CHIPINFO" to see available chip names (Driver)
The driver was invoked without selecting what chip to build for. Running the driver with the
CHIPINFO option will display a list of all chips that could be selected to build for.
The usage of this option was incorrect. Confirm correct usage with HELP or refer to the part of the
manual that discusses this option.
The application given to this option is not understood or does not belong to the compiler.
(907) unknown memory space tag "*" in "*" option specification (Driver)
A parameter to this memory option was a string but did not match any valid tags. Refer to the section
of this manual that describes this option to see what tags (if any) are valid for this device.
One of the subcomponents being executed encountered a problem and returned an error code. Other
messages should have been reported by the subcomponent to explain the problem that was encoun-
tered.
(913) "*" option may cause compiler errors in some standard header files (Driver)
Using this option will invalidate some of the qualifiers used in the standard header files resulting in
errors. This issue and its solution are detailed in the section of this manual that specifically discusses
this option.
(915) no room for arguments (Preprocessor, Parser, Code Generator, Linker, Objtohex)
378
Error and Warning Messages
379
Error and Warning Messages
380
Error and Warning Messages
(949) start of checksum range must be less than end of range (Hexmate)
The -CKSUM option has been given a range where the start is greater than the end. The parameters
may be incomplete or entered in the wrong order.
(951) start of fill range must be less than end of range (Hexmate)
The -FILL option has been given a range where the start is greater than the end. The parameters may
be incomplete or entered in the wrong order.
381
Error and Warning Messages
(965) -STRPACK option not yet implemented, option will be ignored (Hexmate)
This option currently is not available and will be ignored.
382
Error and Warning Messages
(972) only modifiers "h" and "l" valid with this format (Parser)
Only modifiers h (short) and l (long) are legal with this printf format specifier.
The only modifier that is legal with this format is l (for long).
The format specifier or modifier in the printf-style string is illegal for this particular format.
A field width may not appear at this point in a printf() type format specifier.
This identifier following a struct or union keyword is already the tag for an enumerated type, and
thus should only follow the keyword enum, e.g.:
383
Error and Warning Messages
struct IN {
int a, b;
};
enum IN {ONE=1, TWO}; /* woops -- IN is already defined */
union IN {
int a, b;
};
enum IN {ONE=1, TWO}; /* woops -- IN is already defined */
int a;
char a; /* woops -- what is the correct type? */
384
Error and Warning Messages
385
Error and Warning Messages
(1016) missing argument* to "*" specification in chipinfo file "*" at line * (Driver)
This value of this attribute is blank in the chip configuration file.
(1018) illegal number of "*" specification* (* found; * expected) in chipinfo file "*" at line *
(Driver)
This attribute was expected to appear a certain number of times but it did not for this chip.
(1021) syntax error reading "*" value in chipinfo file "*" at line * (Driver)
The chip configuration file incorrectly defines the specified value for this device. If you are modify-
ing this file yourself, take care and refer to the comments at the beginning of this file for a description
on what type of values are expected here.
(1022) syntax error reading "*" range in chipinfo file "*" at line * (Driver)
The chip configuration file incorrectly defines the specified range for this device. If you are modify-
ing this file yourself, take care and refer to the comments at the beginning of this file for a description
on what type of values are expected here.
386
Error and Warning Messages
(1032) use HELP=<option> for usage of these command line options (Hexmate)
More detailed information is available for a specific option by passing that option to the HELP
option.
387
Error and Warning Messages
388
Error and Warning Messages
389
Error and Warning Messages
390
Error and Warning Messages
(1139) functions parameter area too large; must be less than 1024 bytes (Code Generator)
The amount of data used by this function for parameters has exceeded its maximum limit. Reduce
the amount of data passed to this function through parameters.
(1141) bad interrupt vector address for "*": 0x* (Code Generator)
An invalid vector address was assigned to this function. It was possibly out of range or not an even
address.
(1142) missing interrupt vector address for function "*" (Code Generator)
This function was qualified as an interrupt function but has not been assigned a vector address.
Assign a vector address to this function.
(1143) functions auto area too large, must be less than 65536 bytes (Code Generator)
The amount of data used by this function for auto variables has exceeded its maximum limit. Reduce
the number of auto variables.
391
Error and Warning Messages
(1150) constant operand must be one of: -6, -4, -2, 2, 4, 6 (Assembler)
An illegal value was used in this increment/decrement of this instruction. Only values of -6, -4, -2,
2, 4 and 6 are permitted.
(1156) prefetch destination register must be one of: W4, W5, W6, W7 (Assembler)
An illegal working register was selected as a prefetch destination register. For this prefetch, valid
destinations are W4, W5, W6 or W7.
392
Error and Warning Messages
(1164) psect flag "width" must specify a positive constant 1,2,3 (Assembler)
The width flag used when declaring or resuming this psect has an invalid value.
393
Error and Warning Messages
mov [Ws + Wb],[Wd + Wb] ; expects the same Wb in both source and destination
394
Error and Warning Messages
(1178) the "*" option has been removed and has no effect (Driver)
This option no longer exists in this version of the compiler and has been ignored. Use the compilers
help option or refer to the manual to find a replacement option.
The directory specified in the setup option does not exist. Create the directory and try again.
A variable qualified as near must also be qualified with static or made global. An auto variable
cannot be qualified as near.
The fast qualifier can only be used on a function that is also qualified with interrupt. As this qualifier
affects the context switching code used by an interrupt function, it serves no purpose in any other
function.
(1190) FAE license only - not for use in commercial applications (Driver)
Indicates that this compiler has been activated with an FAE licence. This licence does not permit the
product to be used for the development of commercial applications.
Indicates that this compiler has been activated with an education licence. The educational licence is
only available to educational facilities and does not permit the product to be used for the development
of commercial applications.
Indicates that this compiler has been activated with an evaluation licence.
The compiler has been installed as a time-limited trial. This trial will end on the date specified.
395
Error and Warning Messages
A command line option that accepts additional parameters was given inappropriate data or insuffi-
cient data. For example an option may expect two parameters with both being integers. Passing a
string as one of these parameters or supplying only one parameter could result in this error.
This option has been specified too many times. If possible, try performing these operations over
several command lines.
The trial period for this compiler has expired. The compiler is now inoperable until activated with
a valid serial number. Contact HI-TECH Software to purchase this software and obtain a serial
number.
The code sequence specified in a -FIND option has been found at this address.
All find, replace and mask attributes in this option must be of the same byte width. Check the
parameters supplied to this option. For example finding 1234h (2 bytes) masked with FFh (1 byte)
will result in an error, but masking with 00FFh (2 bytes) will be Ok.
An unknown or unsupported INHX format has been requested. Refer to documentation for supported
INHX formats.
Data to this option was not entered as whole bytes. Perhaps the data was incomplete or a leading
zero was omitted. For example the value Fh contains only four bits of significant data and is not a
whole byte. The value 0Fh contains eight bits of significant data and is a whole byte.
396
Error and Warning Messages
(1205) using the configuration file *; you may override this with the environment variable
HTC_XML (Driver)
This is the compiler configuration file selected during compiler setup. This can be changed via
the HTC_XML environment variable. This file is used to determine where the compiler has been
installed.
(1207) some of the command line options you are using are now obsolete (Driver)
Some of the command line options passed to the driver have now been discontinued in this version
of the compiler, however during a grace period these old options will still be processed by the driver.
(1208) use help option or refer to the user manual for option details (Driver)
An obsolete option was detected. Use help or refer to the manual to find a replacement option that
will not result in this advisory message.
(1210) Visit the HI-TECH Software website (www.htsoft.com) for a possible update (Driver)
Visit our website to see if an update is available to address the issue(s) listed in the previous compiler
message. Please refer to the on-line self-help facilities such as the Frequently asked Questions or
search the On-line forums. In the event of no details being found here, contact HI-TECH Software
for further information.
397
Error and Warning Messages
(1226) invalid instruction or instruction mode for this architecture: "*" (Assembler)
An instruction or instruction mode has been used that is not implemented in this particular device.
This may be because code has been ported to a lesser device that does not implement all of the
features of the original device. Rewrite the section of code that is affected to avoid the use of this
instruction or select another device.
398
Error and Warning Messages
libr d c:\ht-pic\lib\pic704-c.lib
libr r lcd.lib
This command needs the name of a module (.obj file) after the library name.
399
Error and Warning Messages
400
Appendix C
Chip Information
The following table lists all devices currently supported by HI-TECH PICC.
401
Chip Information
402
Chip Information
403
Chip Information
404
Chip Information
405
Chip Information
406
Index
407
INDEX INDEX
408
INDEX INDEX
409
INDEX INDEX
410
INDEX INDEX
411
INDEX INDEX
412
INDEX INDEX
413
INDEX INDEX
format, 44 initialization, 40
mantissa, 44 header files
floating suffix, 41 problems in, 26
floor function, 191 HEX file format, 151
fnconf directive, 133 HEX file map, 152
fnroot directive, 133 hex files
frexp function, 192 address alignment, 18, 149
fsr, 75 address map, 145
function prototypes, 77, 101 calculating check sums, 144
ellipsis, 53 converting to other Intel formats, 145
function return values, 54 data alignment, 25
function signatures, 101 data padding, 25
functions detecting instruction sequences, 145
argument passing, 53 embedding serial numbers, 145
bank selection on return, 56 filling unused memory, 17, 145
calling convention, 55 find and replacing instructions, 145
fastcall, 56 for bootloaders, 25
getch, 77 merging multiple, 145
interrupt, 61 multiple, 125
interrupt qualifier, 61 record length, 18, 145, 149, 151
kbhit, 77 hexadecimal constants
putch, 77 assembly, 84
return values, 54 hexmate application, 144
signatures, 76 hexmate option
stack usage, 55 +prefix, 147
structure return values, 55 -CK, 147
written in assembler, 65 -FILL, 149, 151
-FIND, 149
get_cal_data, 35
get_cal_data function, 196 -FIND...,REPLACE, 150
getch function, 77, 193 -FORMAT, 151
getchar function, 194 -HELP, 152
getche function, 193 -LOGFILE, 152
gets function, 195 -O, 152
GLOBAL directive, 86, 89 -SERIAL, 24, 152
global PSECT flag, 91 -STRING, 153
global symbols, 106 -addressing, 147
gmtime function, 197 file specifications, 146
hexmate options, 145
hardware HI-TIDE, 18
414
INDEX INDEX
415
INDEX INDEX
416
INDEX INDEX
417
INDEX INDEX
418
INDEX INDEX
419
INDEX INDEX
420
INDEX INDEX
421
INDEX INDEX
422
INDEX INDEX
423
INDEX INDEX
424
INDEX INDEX
425
INDEX INDEX
426
PICC Command-line Options
Option Meaning
-C Compile to object files only
-Dmacro Define preprocessor macro
-E+file Redirect and optionally append errors to a file
-Gfile Generate source-level debugging information
-Ipath Specify a directory pathname for include files
-Llibrary Specify a library to be scanned by the linker
-L-option Specify -option to be passed directly to the linker
-Mfile Request generation of a MAP file
-Nsize Specify identifier length
-Ofile Output file name
-P Preprocess assembler files
-Q Specify quiet mode
-S Compile to assembler source files only
-Usymbol Undefine a predefined preprocessor symbol
-V Verbose: display compiler pass command lines
-X Eliminate local symbols from symbol table
--ASMLIST Generate assembler .LST file for each compilation
--CHAR=type Make the default char signed or unsigned
--CHECKSUM=start-end@dest Calculate a checksum over an address range
--CHIP=processor Selects which processor to compile for
--CHIPINFO Displays a list of supported processors
--CODEOFFSET=address Offset program code to address
--CR=file Generate cross-reference listing
--DEBUGGER=type Select the debugger that will be used
--DOUBLE=type Selects size/kind of double types
--ERRFORMAT<=format> Format error message strings to the given style
--ERRORS=number Sets the maximun number of errors displayed
--FILL=opcode Fill unused program locations with this hexadecimal
code
--GETOPTION=app,file Get the command line options for the named applica-
tion
--HELP<=option> Display the compilers command line options
--IDE=ide Configure the compiler for use by the named IDE
--LANG=language Specify language for compiler messages
continued. . .
PICC Command-line Options
Option Meaning
--MEMMAP=file Display memory summary information for the map
file
--MSGFORMAT<=format> Format general message strings to the given style
--MSGDISABLE<=numbers> Disable these warning or advisory messages
--NODEL Do not remove temporary files generated by the com-
piler
--NOEXEC Go through the motions of compiling without actually
compiling
--OPT<=type> Enable general compiler optimizations
--OUTDIR Specify output files directory
--OUTPUT=type Generate output file type
--PRE Produce preprocessed source files
--PROTO Generate function prototype information
--RAM=lo-hi<,lo-hi,...> Specify and/or reserve RAM ranges
--ROM=lo-hi<,lo-hi,...> Specify and/or reserve ROM ranges
--RUNTIME=type Configure the C runtime libraries to the specified type
--SCANDEP Generate file dependency .DEP files
--SERIAL=code@address Store this hexadecimal code at an address in program
memory
--SETOPTION=app,file Set the command line options for the named applica-
tion
--SETUP=argument Setup the product
--STRICT Enable strict ANSI keyword conformance
--SUMMARY=type Selects the type of memory summary output
--TIME Show execution time in each stage of build process
--VER Display the compilers version number
--WARN=level Set the compilers warning level
--WARNFORMAT=format Format warning message strings to given style