/* asout.c */
/*
* Copyright (C) 1989-2009 Alan R. Baldwin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
* Alan R. Baldwin
* 721 Berkeley St.
* Kent, Ohio 44240
*
*/
/*
* 28-Oct-97 JLH:
* - outsym: show s_id as string rather than array [NCPS]
* - Added outr11 to support 8051's 11 bit destination address
*/
#include "sdas.h"
#include "asxxxx.h"
/*)Module asout.c
*
* The module asout.c contains all the functions used to
* generate the .REL assembler output file.
*
*
* The assemblers' output object file is an ascii file containing
* the information needed by the linker to bind multiple object
* modules into a complete loadable memory image.
*
* The object module contains the following designators:
*
* [XDQ][HL][234]
* X Hexadecimal radix
* D Decimal radix
* Q Octal radix
*
* H Most significant byte first
* L Least significant byte first
*
* 2 16-Bit Relocatable Addresses/Data
* 3 24-Bit Relocatable Addresses/Data
* 4 32-Bit Relocatable Addresses/Data
*
* H Header
* M Module
* A Area
* S Symbol
* T Object code
* R Relocation information
* P Paging information
*
*
* (1) Radix Line
*
* The first line of an object module contains the [XDQ][HL][234]
* format specifier (i.e. XH2 indicates a hexadecimal file with
* most significant byte first and 16-bit addresses) for the
* following designators.
*
*
* (2) Header Line
*
* H aa areas gg global symbols
*
* The header line specifies the number of areas(aa) and the
* number of global symbols(gg) defined or referenced in this ob-
* ject module segment.
*
*
* (3) Module Line
*
* M name
*
* The module line specifies the module name from which this
* header segment was assembled. The module line will not appear
* if the .module directive was not used in the source program.
*
*
* (4) Symbol Line
*
* S string Defnnnn
*
* or
*
* S string Refnnnn
*
* The symbol line defines (Def) or references (Ref) the symbol
* 'string' with the value nnnn. The defined value is relative to
* the current area base address. References to constants and ex-
* ternal global symbols will always appear before the first area
* definition. References to external symbols will have a value of
* zero.
*
*
* (5) Area Line
*
* A label size ss flags ff
*
* The area line defines the area label, the size (ss) of the
* area in bytes, and the area flags (ff). The area flags
* specify the area properties:
*
* OVR/CON (0x04/0x00 i.e. bit position 2)
* ABS/REL (0x08/0x00 i.e. bit position 3)
* PAG (0x10 i.e. bit position 4)
*
*
* (6) T Line
*
* T xx xx nn nn nn nn nn ...
*
* The T line contains the assembled code output by the assem-
* bler with xx xx being the offset address from the current area
* base address and nn being the assembled instructions and data in
* byte format.
*
*
* (7) R Line
*
* R 0 0 nn nn n1 n2 xx xx ...
*
* The R line provides the relocation information to the linker.
* The nn nn value is the current area index, i.e. which area the
* current values were assembled. Relocation information is en-
* coded in groups of 4 bytes:
*
* 1. n1 is the relocation mode and object format
* 1. bit 0 word(0x00)/byte(0x01)
* 2. bit 1 relocatable area(0x00)/symbol(0x02)
* 3. bit 2 normal(0x00)/PC relative(0x04) relocation
* 4. bit 3 1-byte(0x00)/2-byte(0x08) object format for
* byte data
* 5. bit 4 signed(0x00)/unsigned(0x10) byte data
* 6. bit 5 normal(0x00)/page '0'(0x20) reference
* 7. bit 6 normal(0x00)/page 'nnn'(0x40) reference
* 8. bit 7 normal(0x00)/MSB of value
*
* 2. n2 is a byte index into the corresponding
* (i.e. preceeding) T line data (i.e. a pointer to
* the data to be updated by the relocation).
* The T line data may be 1-byte or 2-byte byte data
* format or 2-byte word format.
*
* 3. xx xx is the area/symbol index for the area/symbol be-
* ing referenced. the corresponding area/symbol is found
* in the header area/symbol lists.
*
*
* The groups of 4 bytes are repeated for each item requiring relo-
* cation in the preceeding T line.
*
*
* (8) P Line
*
* P 0 0 nn nn n1 n2 xx xx
*
* The P line provides the paging information to the linker as
* specified by a .setdp directive. The format of the relocation
* information is identical to that of the R line. The correspond-
* ing T line has the following information:
* T xx xx aa aa bb bb
*
* Where aa aa is the area reference number which specifies the
* selected page area and bb bb is the base address of the page.
* bb bb will require relocation processing if the 'n1 n2 xx xx' is
* specified in the P line. The linker will verify that the base
* address is on a 256 byte boundary and that the page length of an
* area defined with the PAG type is not larger than 256 bytes.
*
* The linker defaults any direct page references to the first
* area defined in the input REL file. All ASxxxx assemblers will
* specify the _CODE area first, making this the default page area.
*
*
* asout.c contains the following functions:
* int lobyte()
* int hibyte()
* int thrdbyte()
* int frthbyte()
* VOID out()
* VOID outall()
* VOID outarea()
* VOID outbuf()
* VOID outchk()
* VOID outdp()
* VOID outdot()
* VOID outgsd()
* VOID outsym()
* VOID outab()
* VOID outaw()
* VOID outa3b()
* VOID outa4b()
* VOID outaxb()
* VOID outatxb()
* VOID outrb()
* VOID outrw()
* VOID outr11()
* VOID out_lb()
* VOID out_lw()
* VOID out_l3b()
* VOID out_l4b()
* VOID out_lxb()
* VOID out_txb()
*/
/*)Function VOID outab(v)
*)Function VOID outaw(v)
*)Function VOID outa3b(v)
*)Function VOID outa4b(v)
*
* a_uint v assembler data
*
* Dispatch to output routine of 1 to 4 absolute bytes.
*
* local variables:
* none
*
* global variables:
* none
*
* functions called:
* VOID outaxb() asout.c
*
* side effects:
* Absolute data is processed.
*/
VOID
outab(a_uint v)
{
outaxb(1, v);
}
VOID
outaw(a_uint v)
{
outaxb(2, v);
}
VOID
outa3b(a_uint v)
{
outaxb(3, v);
}
VOID
outa4b(a_uint v)
{
outaxb(4, v);
}
/*)Function VOID outaxb(i, v)
*
* int i output byte count
* a_uint v assembler data
*
* The function outaxb() processes 1 to 4 bytes of
* assembled data in absolute format.
*
* local variables:
* int p_bytes
*
* global variables:
* sym dot defined as sym[0]
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
*
* functions called:
* VOID outatxb() asout.c
* VOID outchk() asout.c
* VOID out_lxb() asout.c
*
* side effects:
* The current assembly address is incremented by i.
*/
VOID
outaxb(int i, a_uint v)
{
int p_bytes;
if (pass == 2) {
out_lxb(i, v, 0);
if (oflag) {
outchk(i, 0);
outatxb(i, v);
}
}
/*
* Update the Program Counter
*/
p_bytes = 1;
dot.s_addr += (i/p_bytes) + (i % p_bytes ? 1 : 0);
}
/* sdas specific */
/*)Function VOID write_rmode(r, n)
*
* int r relocation mode
* int n byte index
*
* write_rmode puts the passed relocation mode into the
* output relp buffer, escaping it if necessary.
*
* global variables:
* char * relp Pointer to R Line Values
*
* functions called:
* VOID rerr() assubr.c
*
* side effects:
* relp is incremented appropriately.
*/
VOID
write_rmode(int r, int n)
{
/* We need to escape the relocation mode if it is greater
* than a byte, or if it happens to look like an escape.
* (I don't think that the latter case is legal, but
* better safe than sorry).
*/
if ((r > 0xff) || ((r & R_ESCAPE_MASK) == R_ESCAPE_MASK))
{
/* Hack in up to an extra 4 bits of flags with escape. */
if (r > 0xfff)
{
/* uh-oh.. we have more than 4 extra bits. */
fprintf(stderr,
"Internal error: relocation mode 0x%X too big.\n",
r);
rerr();
}
/* printf("escaping relocation mode\n"); */
*relp++ = R_ESCAPE_MASK | (r >> 8);
*relp++ = r & 0xff;
}
else
{
*relp++ = r;
}
*relp++ = n;
}
/* end sdas specific */
/*)Function VOID outatxb(i, v)
*
* int i number of bytes to process
* int v assembler data
*
* The function outatxb() outputs i bytes
*
* local variables:
* none
*
* global variables:
* int hilo byte order
* char * txtp Pointer to T Line Values
*
* functions called:
* int lobyte() asout.c
* int hibyte() asout.c
* int thrdbyte() asout.c
* int frthbyte() asout.c
*
* side effects:
* i bytes are placed into the T Line Buffer.
*/
VOID
outatxb(int i, a_uint v)
{
if ((int) hilo) {
if (i >= 4) *txtp++ = frthbyte(v);
if (i >= 3) *txtp++ = thrdbyte(v);
if (i >= 2) *txtp++ = hibyte(v);
if (i >= 1) *txtp++ = lobyte(v);
} else {
if (i >= 1) *txtp++ = lobyte(v);
if (i >= 2) *txtp++ = hibyte(v);
if (i >= 3) *txtp++ = thrdbyte(v);
if (i >= 4) *txtp++ = frthbyte(v);
}
}
/*)Function VOID outrb(esp, r)
*
* expr * esp pointer to expr structure
* int r relocation mode
*
* Dispatch functions for processing relocatable data.
*
* local variables:
* none
*
* global variables:
* none
*
* functions called:
* int outrxb() asout.c
*
* side effects:
* relocatable data processed
*/
VOID
outrb(struct expr *esp, int r)
{
outrxb(1, esp, r);
}
/*)Function VOID outrxb(i, esp, r)
*
* int i output byte count
* expr * esp pointer to expr structure
* int r relocation mode
*
* The function outrxb() processes 1 to 4 bytes of generated code
* in either absolute or relocatable format dependent upon
* the data contained in the expr structure esp. If the
* .REL output is enabled then the appropriate information
* is loaded into the txt and rel buffers.
*
* local variables:
* int m signed value mask
* int n unsigned value mask
* symbol/area reference number
*
* global variables:
* int a_bytes T Line byte count
* sym dot defined as sym[0]
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
* char * relp Pointer to R Line Values
* char * txtp Pointer to T Line Values
*
* functions called:
* VOID outchk() asout.c
* VOID out_lb() asout.c
* VOID out_rb() asout.c
* VOID out_tb() asout.c
*
* side effects:
* R and T Lines updated. Listing updated.
* The current assembly address is incremented by i.
*/
VOID
outrxb(int i, struct expr *esp, int r)
{
a_uint m, n;
int p_bytes;
if (pass == 2) {
if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
/* This is a constant; simply write the
* const byte to the T line and don't
* generate any relocation info.
*/
/*
* Mask Value Selection
*/
#ifdef LONGINT
switch(i) {
default:
case 1: m = (a_uint) ~0x0000007Fl; n = (a_uint) ~0x000000FFl; break; /* 1 byte */
case 2: m = (a_uint) ~0x00007FFFl; n = (a_uint) ~0x0000FFFFl; break; /* 2 bytes */
case 3: m = (a_uint) ~0x007FFFFFl; n = (a_uint) ~0x00FFFFFFl; break; /* 3 bytes */
case 4: m = (a_uint) ~0x7FFFFFFFl; n = (a_uint) ~0xFFFFFFFFl; break; /* 4 bytes */
}
#else
switch(i) {
default:
case 1: m = (a_uint) ~0x0000007F; n = (a_uint) ~0x000000FF; break; /* 1 byte */
case 2: m = (a_uint) ~0x00007FFF; n = (a_uint) ~0x0000FFFF; break; /* 2 bytes */
case 3: m = (a_uint) ~0x007FFFFF; n = (a_uint) ~0x00FFFFFF; break; /* 3 bytes */
case 4: m = (a_uint) ~0x7FFFFFFF; n = (a_uint) ~0xFFFFFFFF; break; /* 4 bytes */
}
#endif
/*
* Signed Range Check
*/
(void)m; //temporary fix warning
/*
* Page0 Range Check
*/
if (((r & (R_SGND | R_USGN | R_PAGX | R_PCR)) == R_PAG0) &&
((n & esp->e_addr) != 0))
err('d');
out_lxb(i,esp->e_addr,0);
if (oflag) {
outchk(i,0);
outatxb(i,esp->e_addr);
}
} else {
if ((i == 1) && (!is_sdas() || !(is_sdas_target_8051_like() || is_sdas_target_stm8()))) {
r |= R_BYTE | R_BYTX | esp->e_rlcf;
if (r & R_MSB) {
out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH);
} else {
out_lb(lobyte(esp->e_addr),r|R_RELOC);
}
if (oflag) {
outchk(a_bytes, 4);
out_txb(a_bytes, esp->e_addr);
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
*relp++ = r;
*relp++ = txtp - txt - a_bytes;
out_rw(n);
}
} else {
/* sdas mcs51 specific */
/* We are generating a single byte of relocatable
* info.
*
* We generate a 24 bit address. The linker will
* select a single byte based on whether R_MSB or
* R_HIB is set.
*/
/* 24 bit mode. */
r |= R_BYTE | R_BYT3 | esp->e_rlcf;
if (r & R_HIB)
{
/* Probably should mark this differently in the
* listing file.
*/
out_lb(thrdbyte(esp->e_addr),r|R_RELOC|R_HIGH);
}
else if (r & R_MSB) {
out_lb(hibyte(esp->e_addr),r|R_RELOC|R_HIGH);
} else {
out_lb(lobyte(esp->e_addr),r|R_RELOC);
}
if (oflag) {
outchk(a_bytes, 5);
out_txb(a_bytes, esp->e_addr);
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
write_rmode(r, txtp - txt - a_bytes);
out_rw(n);
}
/* end sdas mcs51 specific */
}
}
}
/*
* Update the Program Counter
*/
p_bytes = 1;
dot.s_addr += (i/p_bytes) + (i % p_bytes ? 1 : 0);
}
/*)Function VOID outrw(esp, r)
*
* expr * esp pointer to expr structure
* int r relocation mode
*
* The function outrw() processes a word of generated code
* in either absolute or relocatable format dependent upon
* the data contained in the expr structure esp. If the
* .REL output is enabled then the appropriate information
* is loaded into the txt and rel buffers.
*
* local variables:
* int n symbol/area reference number
*
* global variables:
* sym dot defined as sym[0]
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
* char * relp Pointer to R Line Values
* char * txtp Pointer to T Line Values
*
* functions called:
* VOID outchk() asout.c
* VOID out_lw() asout.c
* VOID out_rw() asout.c
* VOID out_txb() asout.c
*
* side effects:
* The current assembly address is incremented by 2.
*/
VOID
outrw(struct expr *esp, int r)
{
int n;
if (pass == 2) {
/* sdas specific */
if (is_sdas() && is_sdas_target_8051_like() && esp->e_addr > 0xffff) {
warnBanner();
fprintf(stderr,
"large constant 0x%x truncated to 16 bits\n",
esp->e_addr);
}
/* end sdas specific */
if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
out_lxb(2,esp->e_addr,0);
if (oflag) {
outchk(2,0);
out_txb(2,esp->e_addr);
}
} else {
r |= R_WORD | esp->e_rlcf;
if (r & R_BYTX) {
rerr();
if (r & R_MSB) {
out_lw(hibyte(esp->e_addr),r|R_RELOC);
} else {
out_lw(lobyte(esp->e_addr),r|R_RELOC);
}
} else {
out_lw(esp->e_addr,r|R_RELOC);
}
if (oflag) {
if (!is_sdas() || !(is_sdas_target_8051_like() || is_sdas_target_stm8())) {
outchk(2, 4);
out_txb(2, esp->e_addr);
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
*relp++ = r;
*relp++ = txtp - txt - 2;
out_rw(n);
} else {
outchk(2, 5);
out_txb(2, esp->e_addr);
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
if (IS_C24(r))
{
/* If this happens, the linker will
* attempt to process this 16 bit field
* as 24 bits. That would be bad.
*/
fprintf(stderr,
"***Internal error: C24 out in "
"outrw()\n");
rerr();
}
write_rmode(r, txtp - txt - 2);
out_rw(n);
}
}
}
}
dot.s_addr += 2;
}
/*)Function VOID outr3b(esp, r)
*
* expr * esp pointer to expr structure
* int r relocation mode
*
* The function outr3b() processes 24 bits of generated code
* in either absolute or relocatable format dependent upon
* the data contained in the expr structure esp. If the
* .REL output is enabled then the appropriate information
* is loaded into the txt and rel buffers.
*
* local variables:
* int n symbol/area reference number
* int esprv merged value
* int p_bytes program counter update temporary
*
* global variables:
* int a_bytes T Line byte count
* sym dot defined as sym[0]
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
* char * relp Pointer to R Line Values
* char * txtp Pointer to T Line Values
*
* functions called:
* VOID outchk() asout.c
* VOID out_lxb() asout.c
* VOID out_rw() asout.c
* VOID out_txb() asout.c
*
* side effects:
* R and T Lines updated. Listing updated.
* The current assembly address is incremented by i.
*/
VOID
outr3b(struct expr *esp, int r)
{
int i = 3;
a_uint esprv;
int n, p_bytes;
if (pass == 2) {
esprv = esp->e_addr;
if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
/* This is a constant expression. */
out_lxb(i,esprv,0);
if (oflag) {
outchk(i,0);
out_txb(i,esprv);
}
} else {
/* This is a symbol. */
r |= R_WORD | esp->e_rlcf;
if (r & R_BYTX) {
/* I have no idea what this case is. */
rerr();
if (r & R_MSB) {
out_lw(hibyte(esprv),r|R_RELOC);
} else {
out_lw(lobyte(esprv),r|R_RELOC);
}
} else {
out_lxb(i,esprv,r|R_RELOC);
}
if (oflag) {
outchk(2*a_bytes, 5);
out_txb(a_bytes, esp->e_addr);
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
if (r & R_BYTE)
{
/* If this occurs, we cannot properly
* code the relocation data with the
* R_C24 flag. This means the linker
* will fail to do the 24 bit relocation.
* Which will suck.
*/
fprintf(stderr,
"***Internal error: BYTE out in 24 "
"bit flat mode unexpected.\n");
rerr();
}
write_rmode(r | R_C24, txtp - txt - a_bytes);
out_rw(n);
}
}
}
/*
* Update the Program Counter
*/
p_bytes = 1;
dot.s_addr += (i/p_bytes) + (i % p_bytes ? 1 : 0);
}
/*)Function VOID outdp(carea, esp, r)
*
* area * carea pointer to current area structure
* expr * esp pointer to expr structure
* int r optional PAGX relocation coding
*
* The function outdp() flushes the output buffer and
* outputs paging information to the .REL file.
*
* local variables:
* int n symbol/area reference number
*
* global variables:
* int a_bytes T Line byte count
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
* char * relp Pointer to R Line Values
* char * txtp Pointer to T Line Values
*
* functions called:
* VOID outbuf() asout.c
* VOID outchk() asout.c
* VOID out_rw() asout.c
* VOID out_txb() asout.c
*
* side effects:
* Output buffer flushed to .REL file.
* Paging information dumped to .REL file.
*/
VOID
outdp(struct area *carea, struct expr *esp, int r)
{
a_uint n;
if (oflag && pass==2) {
outchk(ASXHUGE, ASXHUGE);
out_txb(a_bytes, carea->a_ref);
out_txb(a_bytes, esp->e_addr);
if (esp->e_flag || esp->e_base.e_ap!=NULL) {
if (esp->e_base.e_ap == NULL) {
n = area[1].a_ref;
r |= R_AREA;
fprintf(stderr, "?ASxxxx-OUTDP-NULL-POINTER error.\n\n");
} else
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
r |= R_AREA;
}
write_rmode(r, txtp - txt - a_bytes);
out_rw(n);
}
outbuf("P");
}
}
/*)Function VOID outall()
*
* The function outall() will output any bufferred assembled
* data and relocation information (during pass 2 if the .REL
* output has been enabled).
*
* local variables:
* none
*
* global variables:
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
*
* functions called:
* VOID outbuf() asout.c
*
* side effects:
* assembled data and relocation buffers will be cleared.
*/
VOID
outall(void)
{
if (oflag && pass==2)
outbuf("R");
}
/*)Function VOID outdot()
*
* The function outdot() outputs information about the
* current program counter value (during pass 2 if the .REL
* output has been enabled).
*
* local variables:
* none
*
* global variables:
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
* char rel[] relocation data for code/data array
* char * relp Pointer to R Line Values
* char txt[] assembled code/data array
* char * txtp Pointer to T Line Values
*
* functions called:
* int fprintf() c_library
* VOID out() asout.c
*
* side effects:
* assembled data and relocation buffers will be cleared.
*/
VOID
outdot(void)
{
if (oflag && pass==2) {
fprintf(ofp, "T");
out(txt,(int) (txtp-txt));
fprintf(ofp, "\n");
fprintf(ofp, "R");
out(rel,(int) (relp-rel));
fprintf(ofp, "\n");
txtp = txt;
relp = rel;
}
}
/*)Function outchk(nt, nr)
*
* int nr number of additional relocation words
* int nt number of additional data words
*
* The function outchk() checks the data and relocation buffers
* for space to insert the nt data words and nr relocation words.
* If space is not available then output the current data and
* initialize the data buffers to receive the new data.
*
* local variables:
* area * ap pointer to an area structure
*
* global variables:
* int a_bytes T Line byte count
* sym dot defined as sym[0]
* char rel[] relocation data for code/data array
* char * relp Pointer to R Line Values
* char txt[] assembled code/data array
* char * txtp Pointer to T Line Values
*
* functions called:
* VOID outbuf() asout.c
* VOID out_rw() asout.c
* VOID out_txb() asout.c
*
* side effects:
* Data and relocation buffers may be emptied and initialized.
*/
VOID
outchk(int nt, int nr)
{
struct area *ap;
if (txtp+nt > &txt[NTXT] || relp+nr > &rel[NREL]) {
outbuf("R");
}
if (txtp == txt) {
out_txb(a_bytes, dot.s_addr);
if ((ap = dot.s_area) != NULL) {
write_rmode(R_WORD|R_AREA, 0);
out_rw(ap->a_ref);
}
}
}
/*)Function VOID outbuf(s)
*
* char * s "R" or "P" or ("I" illegal)
*
* The function outbuf() will output any bufferred data
* and relocation information to the .REL file. The output
* buffer pointers and counters are initialized.
*
* local variables:
* none
*
* global variables:
* int a_bytes T Line byte count
* FILE * ofp relocation output file handle
* char rel[] relocation data for code/data array
* char * relp Pointer to R Line Values
* char txt[] assembled code/data array
* char * txtp Pointer to T Line Values
*
* functions called:
* int fprintf() c_library
* VOID out() asout.c
*
* side effects:
* All bufferred data written to .REL file and
* buffer pointers and counters initialized.
*/
VOID
outbuf(char *s)
{
if (txtp > &txt[a_bytes]) {
fprintf(ofp, "T");
out(txt,(int) (txtp-txt));
fprintf(ofp, "\n");
fprintf(ofp, "%s", s);
out(rel,(int) (relp-rel));
fprintf(ofp, "\n");
}
txtp = txt;
relp = rel;
}
VOID
outradix()
{
if (pass < 2)
return;
/*
* Output Radix
*/
if (xflag == 0) {
fprintf(ofp, "X%c%d\n", (int) hilo ? 'H' : 'L', a_bytes);
} else
if (xflag == 1) {
fprintf(ofp, "Q%c%d\n", (int) hilo ? 'H' : 'L', a_bytes);
} else
if (xflag == 2) {
fprintf(ofp, "D%c%d\n", (int) hilo ? 'H' : 'L', a_bytes);
}
}
/*)Function VOID outgsd()
*
* The function outgsd() performs the following:
* (1) outputs the .REL file radix
* (2) outputs the header specifying the number
* of areas and global symbols
* (3) outputs the module name
* (4) set the reference number and output a symbol line
* for all external global variables and absolutes
* (5) output an area name, set reference number and output
* a symbol line for all global relocatables in the area.
* Repeat this proceedure for all areas.
*
* local variables:
* area * ap pointer to an area structure
* sym * sp pointer to a sym structure
* int i loop counter
* int j loop counter
* int c string character value
* int narea number of code areas
* int nglob number of global symbols
* char * ptr string pointer
* int rn symbol reference number
*
* global variables:
* int a_bytes T Line byte count
* area * areap pointer to an area structure
* int hilo byte order
* char module[] module name string
* sym * symhash[] array of pointers to NHASH
* linked symbol lists
* int xflag -x, listing radix flag
*
* functions called:
* int fprintf() c_library
* VOID outarea() asout.c
* VOID outsym() asout.c
*
* side effects:
* All symbols are given reference numbers, all symbol
* and area information is output to the .REL file.
*/
VOID
outgsd(void)
{
struct area *ap;
struct sym *sp;
int i, j;
char *ptr;
int narea, nglob, rn;
/*
* Number of areas
*/
narea = areap->a_ref + 1;
/*
* Number of global references/absolutes
*/
nglob = 0;
for (i = 0; i < NHASH; ++i) {
sp = symhash[i];
while (sp) {
if (sp->s_flag&S_GBL)
nglob += 1;
sp = sp->s_sp;
}
}
outradix();
/*
* Output number of areas and symbols
*/
if (xflag == 0) {
fprintf(ofp, "H %X areas %X global symbols\n", narea, nglob);
} else
if (xflag == 1) {
fprintf(ofp, "H %o areas %o global symbols\n", narea, nglob);
} else
if (xflag == 2) {
fprintf(ofp, "H %u areas %u global symbols\n", narea, nglob);
}
/*
* Module name
*/
if (module[0]) {
fprintf(ofp, "M ");
ptr = &module[0];
fprintf(ofp, "%s\n", ptr);
}
/* sdas specific */
/*
* Sdcc compile options
*/
if (is_sdas() && NULL != optsdcc) fprintf(ofp, "O %s\n", optsdcc);
/* end sdas specific */
/*
* Global references and absolutes.
*/
rn = 0;
for (i=0; is_area==NULL && sp->s_flag&S_GBL) {
sp->s_ref = rn++;
outsym(sp);
}
sp = sp->s_sp;
}
}
/*
* Global relocatables.
*/
for (i=0; ia_ref != i)
ap = ap->a_ap;
outarea(ap);
for (j=0; js_area==ap && sp->s_flag&S_GBL) {
sp->s_ref = rn++;
outsym(sp);
}
sp = sp->s_sp;
}
}
}
}
/*)Function VOID outarea(ap)
*
* area * ap pointer to an area structure
*
* The function outarea() outputs the A line to the .REL
* file. The A line contains the area's name, size,
* and attributes.
*
* local variables:
* char * frmt pointer to format string
*
* global variables:
* FILE * ofp relocation output file handle
* int xflag -x, listing radix flag
*
* functions called:
* int fprintf() c_library
*
* side effects:
* The A line is sent to the .REL file.
*/
VOID
outarea(struct area *ap)
{
char * frmt;
fprintf(ofp, "A ");
fprintf(ofp, "%s", &ap->a_id[0]);
switch(xflag) {
default:
case 0: frmt = " size %X flags %X"; break;
case 1: frmt = " size %o flags %o"; break;
case 2: frmt = " size %u flags %u"; break;
}
fprintf(ofp, frmt, ap->a_size, ap->a_flag);
if (is_sdas()) {
/* sdas specific */
if (xflag == 0) {
fprintf(ofp, " addr %X", ap->a_addr);
} else
if (xflag == 1) {
fprintf(ofp, " addr %o", ap->a_addr);
} else
if (xflag == 2) {
fprintf(ofp, " addr %u", ap->a_addr);
}
/* end sdas specific */
}
fprintf(ofp, "\n");
}
/*)Function VOID outsym(sp)
*
* sym * sp pointer to a sym structure
*
* The function outsym() outputs the S line to the .REL
* file. The S line contains the symbols name and whether the
* the symbol is defined or referenced.
*
* local variables:
* char * frmt pointer to format string
* int s_addr (int) truncated to 2-bytes
*
* global variables:
* int a_bytes argument size in bytes
* FILE * ofp relocation output file handle
* int xflag -x, listing radix flag
*
* functions called:
* int fprintf() c_library
*
* side effects:
* The S line is sent to the .REL file.
*/
VOID
outsym(struct sym *sp)
{
char *frmt;
a_uint s_addr;
s_addr = sp->s_addr;
fprintf(ofp, "S ");
fprintf(ofp, "%s", &sp->s_id[0]);
fprintf(ofp, " %s", sp->s_type==S_NEW ? "Ref" : "Def");
#ifdef LONGINT
switch(xflag) {
default:
case 0:
switch(a_bytes) {
default:
case 2: frmt = "%04lX\n"; break;
case 3: frmt = "%06lX\n"; break;
case 4: frmt = "%08lX\n"; break;
}
break;
case 1:
switch(a_bytes) {
default:
case 2: frmt = "%06lo\n"; break;
case 3: frmt = "%08lo\n"; break;
case 4: frmt = "%011lo\n"; break;
}
break;
case 2:
switch(a_bytes) {
default:
case 2: frmt = "%05lu\n"; break;
case 3: frmt = "%08lu\n"; break;
case 4: frmt = "%010lu\n"; break;
}
break;
}
#else
switch(xflag) {
default:
case 0:
switch(a_bytes) {
default:
case 2: frmt = "%04X\n"; break;
case 3: frmt = "%06X\n"; break;
case 4: frmt = "%08X\n"; break;
}
break;
case 1:
switch(a_bytes) {
default:
case 2: frmt = "%06o\n"; break;
case 3: frmt = "%08o\n"; break;
case 4: frmt = "%011o\n"; break;
}
break;
case 2:
switch(a_bytes) {
default:
case 2: frmt = "%05u\n"; break;
case 3: frmt = "%08u\n"; break;
case 4: frmt = "%010u\n"; break;
}
break;
}
#endif
fprintf(ofp, frmt, s_addr);
}
/*)Function VOID out(p, n)
*
* int n number of words to output
* int * p pointer to data words
*
* The function out() outputs the data words to the .REL file
* in the specified radix.
*
* local variables:
* none
*
* global variables:
* FILE * ofp relocation output file handle
* int xflag -x, listing radix flag
*
* functions called:
* int fprintf() c_library
*
* side effects:
* Data is sent to the .REL file.
*/
VOID
out(char *p, int n)
{
while (n--) {
if (xflag == 0) {
fprintf(ofp, " %02X", (*p++)&0377);
} else
if (xflag == 1) {
fprintf(ofp, " %03o", (*p++)&0377);
} else
if (xflag == 2) {
fprintf(ofp, " %03u", (*p++)&0377);
}
}
}
/*)Function VOID out_lb(v, t)
*
* a_uint v assembled data
* int t relocation type
*
* The function out_lb() copies the assembled data and
* its relocation type to the list data buffers.
*
* local variables:
* none
*
* global variables:
* int * cp pointer to assembler output array cb[]
* int * cpt pointer to assembler relocation type
* output array cbt[]
*
* functions called:
* none
*
* side effects:
* Pointers to data and relocation buffers incremented by 1.
*/
VOID
out_lb(a_uint v, int t)
{
if (cp < &cb[NCODE]) {
*cp++ = (char) v;
*cpt++ = t;
}
}
/*)Function VOID out_lw(v, t)
*)Function VOID out_l3b(v, t)
*)Function VOID out_l4b(v, t)
*
* a_uint v assembled data
* int t relocation type
*
* Dispatch functions for processing listing data.
*
* local variables:
* none
*
* global variables:
* none
*
* functions called:
* none
*
* side effects:
* Listing data processed.
*/
VOID
out_lw(a_uint v, int t)
{
out_lxb(2, v, t);
}
VOID
out_l3b(a_uint v, int t)
{
out_lxb(3, v, t);
}
VOID
out_l4b(a_uint v, int t)
{
out_lxb(4, v, t);
}
/*)Function VOID out_lxb(i, v, t)
*
* int i output byte count
* a_uint v assembled data
* int t relocation type
*
* Dispatch function for list processing.
*
* local variables:
* none
*
* global variables:
* int hilo byte order
*
* functions called:
* VOID out_lb() asout.c
*
* side effects:
* i list bytes are processed.
*/
VOID
out_lxb(int i, a_uint v, int t)
{
if ((int) hilo) {
if (i >= 3) out_lb(thrdbyte(v),t ? t|R_HIGH : 0);
if (i >= 2) out_lb(hibyte(v),t);
if (i >= 1) out_lb(lobyte(v),t);
} else {
if (i >= 1) out_lb(lobyte(v),t);
if (i >= 2) out_lb(hibyte(v),t);
if (i >= 3) out_lb(thrdbyte(v),t ? t|R_HIGH : 0);
}
}
/*)Function VOID out_rw(v)
*
* a_uint v assembled data
*
* The function out_rw() outputs the relocation (R)
* data word as two bytes ordered according to hilo.
*
* local variables:
* none
*
* global variables:
* int hilo byte order
* char * relp Pointer to R Line Values
*
* functions called:
* int lobyte() asout.c
* int hibyte() asout.c
*
* side effects:
* Pointer to relocation buffer incremented by 2.
*/
VOID
out_rw(a_uint v)
{
if ((int) hilo) {
*relp++ = hibyte(v);
*relp++ = lobyte(v);
} else {
*relp++ = lobyte(v);
*relp++ = hibyte(v);
}
}
/*)Function VOID out_txb(i, v)
*
* int i T Line byte count
* a_uint v data word
*
* The function out_txb() outputs the text (T)
* data word as i bytes ordered according to hilo.
*
* local variables:
*
* global variables:
* int hilo byte order
* char * txtp Pointer to T Line Values
*
* functions called:
* int lobyte() asout.c
* int hibyte() asout.c
* int thrdbyte() asout.c
* int frthbyte() asout.c
*
* side effects:
* T Line buffer updated.
*/
VOID
out_txb(int i, a_uint v)
{
if ((int) hilo) {
if (i >= 4) *txtp++ = frthbyte(v);
if (i >= 3) *txtp++ = thrdbyte(v);
if (i >= 2) *txtp++ = hibyte(v);
if (i >= 1) *txtp++ = lobyte(v);
} else {
if (i >= 1) *txtp++ = lobyte(v);
if (i >= 2) *txtp++ = hibyte(v);
if (i >= 3) *txtp++ = thrdbyte(v);
if (i >= 4) *txtp++ = frthbyte(v);
}
}
/*)Function int lobyte(v)
*)Function int hibyte(v)
*)Function int thrdbyte(v)
*)Function int frthbyte(v)
*
* a_uint v assembled data
*
* These functions return the 1st, 2nd, 3rd, or 4th byte
* of integer v.
*
* local variables:
* none
*
* global variables:
* none
*
* functions called:
* none
*
* side effects:
* none
*/
int
lobyte(a_uint v)
{
return ((int) v&0377);
}
int
hibyte(a_uint v)
{
return ((int) (v>>8)&0377);
}
int
thrdbyte(a_uint v)
{
return ((int) (v>>16)&0377);
}
int
frthbyte(a_uint v)
{
return ((int) (v>>24)&0377);
}
/*
* JLH: Output relocatable 11 bit jump/call
*
* This function is derived from outrw(), adding the parameter for the
* 11 bit address. This form of address is used only on the 8051 and 8048.
*/
/*)Function VOID outrwm(esp, r, v)
*
* expr * esp pointer to expr structure
* int r relocation mode
* int v opcode
*
* The function outrwm() processes a word of generated code
* in either absolute or relocatable format dependent upon
* the data contained in the expr structure esp. If the
* .REL output is enabled then the appropriate information
* is loaded into the txt and rel buffers. The code is output
* in a special format to the linker to allow relocation and
* merging of the opcode and an 11 bit paged address as required
* by the 8051 architecture.
*
* This function based on code by
* John L. Hartman
* jhartman@compuserve.com
*
* local variables:
* int n symbol/area reference number
*
* global variables:
* sym dot defined as sym[0]
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
* char * relp Pointer to R Line Values
* char * txtp Pointer to T Line Values
*
* functions called:
* VOID outchk() asout.c
* VOID out_lw() asout.c
* VOID out_rw() asout.c
* VOID out_txb() asout.c
*
* side effects:
* The current assembly address is incremented by 2.
*/
VOID
outrwm(struct expr *esp, int r, a_uint v)
{
int n;
if (pass == 2) {
if (!is_sdas() || !is_sdas_target_8051_like()) {
if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
/*
* Absolute Destination
*
* Use the global symbol '.__.ABS.'
* of value zero and force the assembler
* to use this absolute constant as the
* base value for the relocation.
*/
esp->e_flag = 1;
esp->e_base.e_sp = &sym[1];
}
/*
* Relocatable Destination. Build THREE
* byte output: relocatable word, followed
* by op-code. Linker will combine them.
*/
r |= R_WORD | esp->e_rlcf;
n = ((esp->e_addr & 0x0700) >> 3) | v;
n = (n << 8) | (esp->e_addr & 0xFF);
out_lw(n,r|R_RELOC);
if (oflag) {
outchk(3, 4);
out_txb(2, esp->e_addr);
*txtp++ = v;
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
*relp++ = r;
*relp++ = txtp - txt - 3;
out_rw(n);
}
} else {
if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
/* Absolute destination.
* Listing shows only the address.
*/
out_lw(esp->e_addr,0);
if (oflag) {
outchk(3, 0);
out_txb(2, esp->e_addr);
*txtp++ = v;
write_rmode(r, txtp - txt - 3);
out_rw(0xFFFF);
}
} else {
/* Relocatable destination. Build THREE
* byte output: relocatable word, followed
* by op-code. Linker will combine them.
* Listing shows only the address.
*/
r |= R_WORD | esp->e_rlcf;
out_lw(esp->e_addr,r|R_RELOC);
if (oflag) {
outchk(3, 5);
out_txb(2, esp->e_addr);
*txtp++ = v;
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
write_rmode(r, txtp - txt - 3);
out_rw(n);
}
}
}
}
dot.s_addr += 2;
}
/*
* Output relocatable 19 bit jump/call
*
* This function is derived from outrw(), adding the parameter for the
* 19 bit address. This form of address is used only in the DS80C390.
*/
VOID
outr3bm(struct expr * esp, int r, a_uint v)
{
int n;
if (pass == 2) {
if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
/* Absolute destination.
* Listing shows only the address.
*/
out_lw(esp->e_addr,0);
if (oflag) {
outchk(4, 0);
out_txb(3, esp->e_addr);
*txtp++ = v;
write_rmode(r, txtp - txt - 4);
out_rw(0xFFFF);
}
} else {
/* Relocatable destination. Build FOUR
* byte output: relocatable 24-bit entity, followed
* by op-code. Linker will combine them.
* Listing shows only the address.
*/
r |= R_WORD | esp->e_rlcf;
out_l3b(esp->e_addr,r|R_RELOC);
if (oflag) {
outchk(4, 5);
out_txb(3, esp->e_addr);
*txtp++ = v;
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
write_rmode(r, txtp - txt - 4);
out_rw(n);
}
}
}
dot.s_addr += 3;
}
/*
* PDK: Output relocatable 11 bit goto/call
*
* This function is derived from outrw(), adding the parameter for the
* 11 bit address. This form of address is used only on the pdk.
*/
/*)Function VOID outrwp(esp, op, mask, jump)
*
* expr * esp pointer to expr structure
* a_uint op opcode
* a_uint mask address mask
* int jump call/goto relocation data
*
* The function outrwp() processes a word of generated code
* in either absolute or relocatable format dependent upon
* the data contained in the expr structure esp. If the
* .REL output is enabled then the appropriate information
* is loaded into the txt and rel buffers. The code is output
* in a special format to the linker to allow relocation and
* merging of the opcode.
*
* This function based on code by
* John L. Hartman
* jhartman@compuserve.com
*
* local variables:
* int n symbol/area reference number
* int r relocation information
*
* global variables:
* sym dot defined as sym[0]
* int oflag -o, generate relocatable output flag
* int pass assembler pass number
* char * relp Pointer to R Line Values
* char * txtp Pointer to T Line Values
*
* functions called:
* VOID outchk() asout.c
* VOID out_lw() asout.c
* VOID out_rw() asout.c
* VOID out_txb() asout.c
*
* side effects:
* The current assembly address is incremented by 2.
*/
VOID
outrwp(struct expr *esp, a_uint op, a_uint mask, int jump)
{
int n, r = R_J11;
if (pass == 2) {
if (esp->e_flag==0 && esp->e_base.e_ap==NULL) {
/*
* Absolute Destination
*
* Use the global symbol '.__.ABS.'
* of value zero and force the assembler
* to use this absolute constant as the
* base value for the relocation.
*/
esp->e_flag = 1;
esp->e_base.e_sp = &sym[1];
}
/* We need to select either the MSB or LSB of the address.
* Reset relocation marker so that the linker knows what to do
* with it.
*/
if (esp->e_rlcf & R_BYTX) {
r |= R_BYTE;
/* We might select the MSB/LSB of an address in RAM. In
* that case the linker should not convert the address
* to words.
*/
if (!esp->e_flag && !memcmp(esp->e_base.e_ap->a_id, "DATA", 4)) {
r |= R_USGN;
}
} else {
r |= R_WORD;
}
/* Some (address) marker bits might have been shifted out of
* range. Revert this and put them back where they belong.
*/
if (esp->e_addr & ~0xFFFF) {
int marker = esp->e_addr & 0x10000;
esp->e_addr &= ~0x10000;
esp->e_addr |= marker >> 1;
}
/*
* Relocatable Destination. Build FOUR
* byte output: relocatable word, followed
* by op-code. Linker will combine them.
*/
r |= esp->e_rlcf;
n = op | (esp->e_addr & mask);
out_lw(n,r|R_RELOC);
if (oflag) {
outchk(5, 4);
out_txb(2, esp->e_addr);
out_txb(2, op);
out_txb(1, (int)get_sdas_target());
if (esp->e_flag) {
n = esp->e_base.e_sp->s_ref;
r |= R_SYM;
} else {
n = esp->e_base.e_ap->a_ref;
}
*relp++ = r;
*relp++ = txtp - txt - 5;
out_rw(n);
}
}
dot.s_addr += 2;
}