bankld: initial hackery to create a banking sdldz80
authorAlan Cox <alan@linux.intel.com>
Wed, 31 Dec 2014 22:30:15 +0000 (22:30 +0000)
committerAlan Cox <alan@linux.intel.com>
Wed, 31 Dec 2014 22:30:15 +0000 (22:30 +0000)
The modifications here are

- emit a modified ihx file format giving the bank identifier, so that we can
  split the .ihx files and generate a set of bin files for the overlaid areas.

- spot and output extra inter-bank relocation entries into the modified ihx
  file that can be read and processed by binmunge.

The follow basically is

Link with modified sdldz80
Run bihx

This produces
relocs.dat - relocation between banks
common.ihx - ihx file for the common bank
bank[123].ihx - relocation for the banks

and then reprocesses the ihx files into .bin versions using makebin

binmunge the reads the relocs.dat and patches the resulting binary data
to use RST in place of CALL and stubs for the rest

36 files changed:
Kernel/tools/bankld/Makefile [new file with mode: 0644]
Kernel/tools/bankld/README [new file with mode: 0644]
Kernel/tools/bankld/aslink.h [new file with mode: 0644]
Kernel/tools/bankld/asxxxx_config.h [new file with mode: 0644]
Kernel/tools/bankld/lk_readnl.c [new file with mode: 0644]
Kernel/tools/bankld/lk_readnl.h [new file with mode: 0644]
Kernel/tools/bankld/lkaomf51.c [new file with mode: 0644]
Kernel/tools/bankld/lkar.c [new file with mode: 0644]
Kernel/tools/bankld/lkar.h [new file with mode: 0644]
Kernel/tools/bankld/lkarea.c [new file with mode: 0644]
Kernel/tools/bankld/lkbank.c [new file with mode: 0644]
Kernel/tools/bankld/lkdata.c [new file with mode: 0644]
Kernel/tools/bankld/lkelf.c [new file with mode: 0644]
Kernel/tools/bankld/lkeval.c [new file with mode: 0644]
Kernel/tools/bankld/lkhead.c [new file with mode: 0644]
Kernel/tools/bankld/lkihx.c [new file with mode: 0644]
Kernel/tools/bankld/lklex.c [new file with mode: 0644]
Kernel/tools/bankld/lklib.c [new file with mode: 0644]
Kernel/tools/bankld/lklibr.c [new file with mode: 0644]
Kernel/tools/bankld/lklibr.h [new file with mode: 0644]
Kernel/tools/bankld/lklist.c [new file with mode: 0644]
Kernel/tools/bankld/lkmain.c [new file with mode: 0644]
Kernel/tools/bankld/lkmem.c [new file with mode: 0644]
Kernel/tools/bankld/lknoice.c [new file with mode: 0644]
Kernel/tools/bankld/lkout.c [new file with mode: 0644]
Kernel/tools/bankld/lkrel.c [new file with mode: 0644]
Kernel/tools/bankld/lkrel.h [new file with mode: 0644]
Kernel/tools/bankld/lkrloc.c [new file with mode: 0644]
Kernel/tools/bankld/lkrloc3.c [new file with mode: 0644]
Kernel/tools/bankld/lks19.c [new file with mode: 0644]
Kernel/tools/bankld/lksdcclib.c [new file with mode: 0644]
Kernel/tools/bankld/lksdcdb.c [new file with mode: 0644]
Kernel/tools/bankld/lksym.c [new file with mode: 0644]
Kernel/tools/bankld/readme.390 [new file with mode: 0644]
Kernel/tools/bankld/sdld.c [new file with mode: 0644]
Kernel/tools/bankld/sdld.h [new file with mode: 0644]

diff --git a/Kernel/tools/bankld/Makefile b/Kernel/tools/bankld/Makefile
new file mode 100644 (file)
index 0000000..4d11932
--- /dev/null
@@ -0,0 +1,21 @@
+CFLAGS          = -g -O2 -Wall -Wno-parentheses -DINDEXLIB -DUNIX -I.
+LDFLAGS         = 
+
+SRC = lk_readnl.c lkaomf51.c lkar.c lkarea.c lkdata.c lkelf.c lkeval.c \
+        lkhead.c lklex.c lklib.c lklibr.c lklist.c lkmain.c lkmem.c \
+        lknoice.c lkout.c lkrel.c lkrloc.c lkrloc3.c lks19.c lksdcclib.c \
+        lksym.c sdld.c lksdcdb.c lkbank.c
+
+OBJS = $(SRC:%.c=%.o)
+LKOBJECTS = $(OBJS)
+
+sdldz80: $(LKOBJECTS)
+       $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(LKOBJECTS)
+
+$(LKOBJECTS) : aslink.h
+
+%.o: %.c
+       $(CC) -c $(CFLAGS) -o $@ $<
+
+clean:
+       rm -f $(LKOBJECTS) *~ sdldz80
\ No newline at end of file
diff --git a/Kernel/tools/bankld/README b/Kernel/tools/bankld/README
new file mode 100644 (file)
index 0000000..873f437
--- /dev/null
@@ -0,0 +1,17 @@
+
+This is a lightly hacked sdldz80 that knows about banked Fuzix binary
+formats. It's not currently a particularly clean approach but can be tidied
+up a bit once it is working.
+
+
+
+
+------------------------------------------------
+sdcc/link
+---------
+
+In gbdk the linker and assembler were split into seperate packages.
+
+For now I'm keeping that split, and leaving the mcs51 version as is.
+
+-- Michael
diff --git a/Kernel/tools/bankld/aslink.h b/Kernel/tools/bankld/aslink.h
new file mode 100644 (file)
index 0000000..5c6a988
--- /dev/null
@@ -0,0 +1,1319 @@
+/* aslink.h */
+
+/*
+ *  Copyright (C) 1989-2012  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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ *   With enhancements from
+ *      John L. Hartman (JLH)
+ *      jhartman@compuserve.com
+ */
+
+/*
+ * System Include Files
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "sdld.h"
+
+/*
+ * Local Definitions
+ */
+
+#define VERSION "V03.00 + NoICE + sdld"
+#define        COPYRIGHT "2012"
+
+/*
+ * To include NoICE Debugging set non-zero
+ */
+#define NOICE   1
+
+/*
+ * To include SDCC Debugging set non-zero
+ */
+#define SDCDB   1
+
+/*
+ * The assembler requires certain variables to have
+ * at least 32 bits to allow correct address processing.
+ *
+ * The type INT32 is defined so that compiler dependent
+ * variable sizes may be specified in one place.
+ *
+ * LONGINT is defined when INT32 is 'long' to
+ * select the 'l' forms for format strings.
+ */
+
+/* Turbo C++ 3.0 for DOS */
+/* 'int' is 16-bits, 'long' is 32-bits */
+
+#ifdef  __TURBOC__
+#define         INT32   long
+#define         LONGINT
+#endif
+
+/* Symantec C++ V6.x/V7.x for DOS (not DOSX) */
+/* 'int' is 16-bits, 'long' is 32-bits */
+
+#ifdef  __SC__
+#define         INT32   long
+#define         LONGINT
+#endif
+
+/* The DEFAULT is 'int' is 32 bits */
+#ifndef INT32
+#define         INT32   int
+#endif
+
+
+/*)Module       aslink.h
+ *
+ *      The module aslink.h contains the definitions for constants,
+ *      structures, global variables, and LKxxxx functions
+ *      contained in the LKxxxx.c files.
+ */
+
+/*)BUILD
+        $(PROGRAM) =    ASLINK
+        $(INCLUDE) =    ASLINK.H
+        $(FILES) = {
+                LKMAIN.C
+                LKLEX.C
+                LKAREA.C
+                LKBANK.C
+                LKHEAD.C
+                LKSYM.C
+                LKEVAL.C
+                LKDATA.C
+                LKLIST.C
+                LKNOICE.C
+                LKSDCDB.C
+                LKRLOC.C
+                LKRLOC3.C
+                LKLIBR.C
+                LKOUT.C
+                LKS19.C
+        }
+        $(STACK) = 2000
+*/
+
+#if defined  DECUS
+/* DECUS C void definition */
+/* File/extension seperator */
+
+#define VOID        char
+#define FSEPX       '.'
+
+#elif defined  PDOS
+/* PDOS C void definition */
+/* File/extension seperator */
+
+#define VOID        char
+#define FSEPX       ':'
+
+#elif defined UNIX
+/* UNIX void definition */
+/* File/extension seperator */
+
+#define VOID        void
+#define FSEPX       '.'
+#define LKDIRSEP    '/'
+#define LKDIRSEPSTR "/"
+#define OTHERSYSTEM
+
+#else
+/* DOS/WINDOWS void definition */
+/* File/extension seperator */
+
+#define VOID        void
+#define FSEPX       '.'
+#define LKDIRSEP    '\\'
+#define LKDIRSEPSTR "\\"
+#define OTHERSYSTEM
+
+#endif
+
+/*
+ * PATH_MAX
+ */
+#include <limits.h>
+#ifndef PATH_MAX                /* POSIX, but not required   */
+ #if defined(__BORLANDC__) || defined(_MSC_VER)
+  #include <stdlib.h>
+  #define PATH_MAX      _MAX_PATH
+ #elif defined(__x86_64__)
+  #define PATH_MAX      4096
+ #else
+  #define PATH_MAX      255     /* define a reasonable value */
+ #endif
+#endif
+
+#define LKOBJEXT        "rel"
+
+/*
+ * Global symbol types.
+ */
+#define S_REF   1               /* referenced */
+#define S_DEF   2               /* defined */
+
+/*
+ * File types
+ */
+#define F_OUT   0               /* File.ixx / File.sxx */
+#define F_STD   1               /* stdin */
+#define F_LNK   2               /* File.lnk */
+#define F_REL   3               /* File.rel */
+
+/*
+ * Error definitions
+ */
+#define ER_NONE         0       /* No error */
+#define ER_WARNING      1       /* Warning */
+#define ER_ERROR        2       /* Assembly error */
+#define ER_FATAL        3       /* Fatal error */
+
+/*
+ * This file defines the format of the
+ * relocatable binary file.
+ */
+
+#define NCPS    PATH_MAX        /* characters per symbol */
+#define NINPUT  PATH_MAX        /* Input buffer size */
+#define NHASH   (1 << 6)        /* Buckets in hash table */
+#define HMASK   (NHASH - 1)     /* Hash mask */
+#define NLPP    60              /* Lines per page */
+#define NMAX    78              /* IXX/SXX/DBX Buffer Length */
+#define         IXXMAXBYTES     32      /* NMAX > (2 * IXXMAXBYTES) */
+#define         SXXMAXBYTES     32      /* NMAX > (2 * SXXMAXBYTES) */
+#define         DBXMAXBYTES     64      /* NMAX > (  DBXMAXBYTES  ) */
+#define FILSPC  PATH_MAX        /* File spec length */
+
+#define NDATA   16              /* actual data */
+/*
+ * NTXT must be defined to have the same value in
+ * the ASxxxx assemblers and ASLink.
+ *
+ * The R Line coding allows only 4-bits for coding
+ * the T Line index.  The MAXIMUM value for NTXT
+ * is 16.  It should not be changed.
+ */
+#define NTXT    16              /* T values */
+
+/*
+ * Opcode Cycle definitions (Must Be The Same In ASxxxx / ASLink)
+ */
+#define CYCNT_BGN       '['     /* Cycle count begin delimiter */
+#define CYCNT_END       ']'     /* Cycle count end   delimiter */
+
+/*
+ * Internal ASxxxx Version Variable
+ */
+extern  int     ASxxxx_VERSION;
+
+
+/*
+ *      ASLINK - Version 3 Definitions
+ */
+
+/*
+ *      The "A3_" area constants define values used in
+ *      generating the assembler area output data.
+ *
+ * Area flags
+ *
+ *         7     6     5     4     3     2     1     0
+ *      +-----+-----+-----+-----+-----+-----+-----+-----+
+ *      |     |     |     | PAG | ABS | OVR |     |     |
+ *      +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define A3_CON    000           /* concatenate */
+#define A3_OVR    004           /* overlay */
+#define A3_REL    000           /* relocatable */
+#define A3_ABS    010           /* absolute */
+#define A3_NOPAG  000           /* non-paged */
+#define A3_PAG    020           /* paged */
+
+/* sdld specific */
+/* Additional flags for 8051 address spaces */
+#define A_DATA    0000          /* data space (default)*/
+#define A_CODE    0040          /* code space */
+#define A_XDATA   0100          /* external data space */
+#define A_BIT     0200          /* bit addressable space */
+
+/* Additional flags for hc08 */
+#define A_NOLOAD  0400          /* nonloadable */
+#define A_LOAD    0000          /* loadable (default) */
+/* end sdld specific */
+
+/*
+ *      The "R3_" relocation constants define values used in
+ *      generating the assembler relocation output data for
+ *      areas, symbols, and code.
+ *
+ *
+ *      Relocation types.
+ *
+ *             7     6     5     4     3     2     1     0
+ *          +-----+-----+-----+-----+-----+-----+-----+-----+
+ *          | MSB | PAGn| PAG0| USGN| BYT2| PCR | SYM | BYT |
+ *          +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define R3_WORD  0x00           /* 16 bit */
+#define R3_BYTE  0x01           /*  8 bit */
+
+#define R3_AREA  0x00           /* Base type */
+#define R3_SYM   0x02
+
+#define R3_NORM  0x00           /* PC adjust */
+#define R3_PCR   0x04
+
+#define R3_BYT1  0x00           /* Byte count for R_BYTE = 1 */
+#define R3_BYTX  0x08           /* Byte count for R_BYTE = X */
+
+#define R3_SGND  0x00           /* Signed value */
+#define R3_USGN  0x10           /* Unsigned value */
+
+#define R3_NOPAG 0x00           /* Page Mode */
+#define R3_PAG0  0x20           /* Page '0' */
+#define R3_PAG   0x40           /* Page 'nnn' */
+
+#define R3_LSB   0x00           /* output low byte */
+#define R3_MSB   0x80           /* output high byte */
+
+/*
+ *      Additional "R3_" functionality is required to support
+ *      some microprocesssor architectures.   The 'illegal'
+ *      "R3_" mode of R3_WORD | R3_BYTX is used as a designator
+ *      of the extended R3_ modes.  The extended modes replace
+ *      the PAGING modes and are being added in an adhoc manner
+ *      as follows:
+ *
+ * Extended Mode relocation flags
+ *
+ *         7     6     5     4     3     2     1     0
+ *      +-----+-----+-----+-----+-----+-----+-----+-----+
+ *      | MSB |  x  |  x  | USGN|  1  | PCR | SYM |  0  |
+ *      +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define R3_ECHEK        0011            /* Extended Mode Check Bits */
+#define R3_EXTND        0010            /* Extended Mode Code */
+#define R3_EMASK        0151            /* Extended Mode Mask */
+
+/* #define R3_AREA 0000 */      /* Base type */
+/* #define R3_SYM  0002 */
+
+/* #define R3_NORM 0000 */      /* PC adjust */
+/* #define R3_PCR  0004 */
+
+/* #define R3_SGND 0000 */      /* Signed value */
+/* #define R3_USGN 0020 */      /* Unsigned value */
+
+/* #define R3_LSB  0000 */      /* output low byte */
+/* #define R3_MSB  0200 */      /* output high byte */
+
+#define R3_J11     (R3_WORD|R3_BYTX)        /* JLH: 11 bit JMP and CALL (8051) */
+#define R3_J19     (R3_WORD|R3_BYTX|R3_MSB) /* BM:  19 bit JMP and CALL (DS80C390) */
+#define R_C24      (R3_WORD|R3_BYT1|R3_MSB) /* 24 bit address (DS80C390) */
+#define R_J19_MASK (R3_BYTE|R3_BYTX|R3_MSB)
+
+#define IS_R_J19(x) (((x) & R_J19_MASK) == R3_J19)
+#define IS_R_J11(x) (((x) & R_J19_MASK) == R3_J11)
+#define IS_C24(x) (((x) & R_J19_MASK) == R_C24)
+
+/* sdld specific */
+#define R_BYT3  0x100           /* if R3_BYTE is set, this is a
+                                 * 3 byte address, of which
+                                 * the linker must select one byte.
+                                 */
+#define R_HIB   0x200           /* If R3_BYTE & R_BYT3 are set, linker
+                                 * will select byte 3 of the relocated
+                                 * 24 bit address.
+                                 */
+
+#define R_BIT   0x400           /* Linker will convert from byte-addressable
+                                 * space to bit-addressable space.
+                                 */
+
+#define R_ESCAPE_MASK   0xf0    /* Used to escape relocation modes
+                                 * greater than 0xff in the .rel
+                                 * file.
+                                 */
+/* end sdld specific */
+
+
+/*
+ *      ASLINK - Version 4 Definitions
+ */
+
+/*
+ *      The "A4_" area constants define values used in
+ *      generating the assembler area output data.
+ *
+ * Area flags
+ *
+ *         7     6     5     4     3     2     1     0
+ *      +-----+-----+-----+-----+-----+-----+-----+-----+
+ *      | BNK | SEG |     | PAG | ABS | OVR | WL1 | WL0 |
+ *      +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define A4_BYTE         0x0000          /*  8 bit */
+#define A4_WORD         0x0001          /* 16 bit */
+
+#define A4_1BYTE        0x0000          /* 1 Byte Word Length */
+#define A4_2BYTE        0x0001          /* 2 Byte Word Length */
+#define A4_3BYTE        0x0002          /* 3 Byte Word Length */
+#define A4_4BYTE        0x0003          /* 4 Byte Word Length */
+#define A4_WLMSK        0x0003          /* Word Length Mask */
+
+#define A4_CON          0x0400          /* Concatenating */
+#define A4_OVR          0x0404          /* Overlaying */
+#define A4_REL          0x0800          /* Relocatable */
+#define A4_ABS          0x0808          /* absolute */
+#define A4_NOPAG        0x1000          /* Non-Paged */
+#define A4_PAG          0x1010          /* Paged */
+
+#define A4_CSEG         0x4000          /* CSEG */
+#define A4_DSEG         0x4040          /* DSEG */
+#define A4_NOBNK        0x8000          /* Non-Banked */
+#define A4_BNK          0x8080          /* Banked */
+
+#define A4_OUT          0x0100          /* Output Code Flag */
+
+/*
+ *      The "R4_" relocation constants define values used in
+ *      generating the assembler relocation output data for
+ *      areas, symbols, and code.
+ *
+ * Note:  The PAGE modes, PCR modes, Signed, Unsigned,
+ *        and MSB codes are mutually exclusive !!!
+ *
+ *
+ * Relocation flags
+ *
+ *         7     6     5     4     3     2     1     0
+ *      +-----+-----+-----+-----+-----+-----+-----+-----+
+ *      | SYM | PCR | PAGn| PAG0| USGN| SGND| BYT1| BYT0|
+ *      +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define R4_BYTE         0x0000          /*  8 bit */
+#define R4_WORD         0x0001          /* 16 bit */
+
+#define R4_1BYTE        0x0000          /* 1 Byte */
+#define R4_2BYTE        0x0001          /* 2 Byte */
+#define R4_3BYTE        0x0002          /* 3 Byte */
+#define R4_4BYTE        0x0003          /* 4 Byte */
+#define R4_BYTES        0x0003          /* Data Size */
+
+#define R4_SGND         0x0004          /* Signed */
+#define R4_USGN         0x0008          /* Unsigned */
+#define R4_OVRF         0x0008          /* Overflow */
+
+#define R4_MBRS         0x0004          /* Merge Bit Range Signed */
+                                        /* An alias for Signed */
+#define R4_MBRU         0x0008          /* Merge Bit Range Unsigned */
+                                        /* An alias for Unsigned */
+#define R4_MBRO         0x0008          /* Merge Bit Range Overflow */
+                                        /* An alias for Unsigned */
+
+#define R4_MSB          0x000C          /* MSB */
+                                        /* Mutually exclusive with Signed / Unsigned */
+
+#define R4_AREA         0x0000          /* Base type */
+#define R4_SYM          0x0080
+
+/*
+ * Paging Modes:
+ */
+
+#define R4_NOPAG        0x0000          /* Page Mode */
+#define R4_PBITS        0x003C          /* Paging Bits */
+#define R4_PAGE         0x0030          /* Paged Addressing */
+#define R4_PAG0         0x0010          /* Page '0'    .setdp */
+#define R4_PAGN         0x0020          /* Page 'nnn'  .setdp */
+#define R4_PAGX         0x0030          /* Page 'x', Extended Relocation Mode */
+#define R4_PAGX0        0x0030          /* Page 'x', pc + 0 */
+#define R4_PAGX1        0x0034          /* Page 'x', pc + 1 */
+#define R4_PAGX2        0x0038          /* Page 'x', pc + 2 */
+#define R4_PAGX3        0x003C          /* Page 'x', pc + 3 */
+
+/*
+ * PCR Modes:
+ */
+
+#define R4_PCR          0x0040          /* PC adjust (default)    */
+#define R4_PCRN         0x0050          /* PC adjust (default) no range check */
+
+#define R4_PCR0         0x0054          /* PC adjust (offset = 0) */
+#define R4_PCR1         0x0060          /* PC adjust (offset = 1) */
+#define R4_PCR2         0x0064          /* PC adjust (offset = 2) */
+#define R4_PCR3         0x0068          /* PC adjust (offset = 3) */
+#define R4_PCR4         0x006C          /* PC adjust (offset = 4) */
+
+#define R4_PCR0N        0x0058          /* PC adjust (offset = 0) no range check */
+#define R4_PCR1N        0x0070          /* PC adjust (offset = 1) no range check */
+#define R4_PCR2N        0x0074          /* PC adjust (offset = 2) no range check */
+#define R4_PCR3N        0x0078          /* PC adjust (offset = 3) no range check */
+#define R4_PCR4N        0x007C          /* PC adjust (offset = 4) no range check */
+
+/*
+ * Basic Relocation Modes
+ */
+
+#define R4_NORM         0x0000          /* No Bit Positioning */
+
+
+/*
+ *      The defined type 'a_uint' is used for all address and
+ *      unsigned variable value calculations.  Its size is
+ *      required to be at least 32-bits to allow upto
+ *      32-bit addressing or 32-bit value manipulation.
+ */
+typedef unsigned INT32 a_uint;
+
+/*
+ *      The defined type 'v_sint' is used for address and
+ *      variable value calculations requiring a sign.
+ *      Its size is required to be at least 32-bits to allow
+ *      upto 32-bit addressing or 32-bit value manipulation.
+ */
+typedef signed INT32 v_sint;
+
+/*
+ *      The structures of head, mode, bank, area, areax, and sym
+ *      are created as the REL files are read during the first
+ *      pass of the linker.  The struct head is created upon
+ *      encountering a H directive in the REL file.  The
+ *      structure contains a link to a link file structure
+ *      (struct lfile) which describes the file containing the H
+ *      directive, a pointer to an array of merge mode
+ *      definition pointers, the number of data/code areas
+ *      contained in this header segment, the number of
+ *      symbols referenced/defined in this header segment, a pointer
+ *      to an array of pointers to areax structures (struct areax)
+ *      created as each A directive is read, a pointer to an
+ *      array of pointers to symbol structures (struct sym) for
+ *      all referenced/defined symbols and a pointer to an array
+ *      of pointers to bank structures (struct bank) referenced
+ *      by this module.  As H directives are read
+ *      from the REL files a linked list of head structures is
+ *      created by placing a link to the new head structure
+ *      in the previous head structure.
+ */
+struct  head
+{
+        struct  head  *h_hp;    /* Header link */
+        struct  lfile *h_lfile; /* Associated file */
+        int     h_narea;        /* # of areas */
+        struct  areax **a_list; /* Area list */
+        int     h_nsym; /* # of symbols */
+        struct  sym   **s_list; /* Symbol list */
+        int     h_nbank;        /* # of banks */
+        struct  bank  **b_list; /* Bank list */
+        int     h_nmode;        /* # of modes */
+        struct  mode  **m_list; /* Mode list */
+        char *  m_id;           /* Module name */
+};
+
+/*
+ *      The MODE structure contains the specification of one of the
+ *      assemblers' relocation modes.  Each assembler must specify
+ *      at least one relocation mode.  The relocation specification
+ *      allows arbitrarily defined active bits and bit positions.
+ *      The 32 element arrays are indexed from 0 to 31.
+ *      Index 0 corresponds to bit 0, ..., and 31 corresponds to bit 31
+ *      of a normal integer value.
+ *
+ *      The value an array element defines if the normal integer bit is
+ *      active (bit <7> is set, 0x80) and what destination bit
+ *      (bits <4:0>, 0 - 31) should be loaded with this normal
+ *      integer bit.
+ *
+ *      The specification for a 32-bit integer:
+ *
+ *      char mode_[32] = {
+ *              0x80,   0x81,   0x82,   0x83,   0x84,   0x85,   0x86,   0x87,
+ *              0x88,   0x89,   0x8A,   0x8B,   0x8C,   0x8D,   0x8E,   0x8F,
+ *              0x90,   0x91,   0x92,   0x93,   0x94,   0x95,   0x96,   0x97,
+ *              0x98,   0x99,   0x9A,   0x9B,   0x9C,   0x9D,   0x9E,   0x9F
+ *      };
+ *
+ *
+ *      The specification for the 11-bit 8051 addressing mode:
+ *
+ *      char mode_[32] = {
+ *              0x80,   0x81,   0x82,   0x83,   0x84,   0x85,   0x86,   0x87,
+ *              0x8D,   0x8E,   0x8F,   0x0B,   0x0C,   0x0D,   0x0E,   0x0F,
+ *              0x10,   0x11,   0x12,   0x13,   0x14,   0x15,   0x16,   0x17,
+ *              0x18,   0x19,   0x1A,   0x1B,   0x1C,   0x1D,   0x1E,   0x1F
+ *      };
+ *
+ *
+ *      m_def is the bit relocation definition array.
+ *      m_flag indicates that bit position swapping is required.
+ *      m_dbits contains the active bit positions for the output.
+ *      m_sbits contains the active bit positions for the input.
+ */
+struct  mode
+{
+        char    m_def[32];      /* Bit Relocation Definition */
+        int     m_flag;         /* Bit Swapping Flag */
+        a_uint  m_dbits;        /* Destination Bit Mask */
+        a_uint  m_sbits;        /* Source Bit Mask */
+};
+
+/*
+ *      The bank structure contains the parameter values for a
+ *      specific program or data bank.  The bank structure
+ *      is a linked list of banks.  The initial default bank
+ *      is unnamed and is defined in lkdata.c, the next bank structure
+ *      will be linked to this structure through the structure
+ *      element 'struct bank *b_bp'.  The structure contains the
+ *      bank name, the bank base address (default = 0), the bank size
+ *      (default = 0, whole addressing space), the bank mapping,
+ *      and the file name suffix. (default is none)  These optional
+ *      parameters are from  the .bank assembler directive.
+ *      The bank structure also contains the bank data output
+ *      file specification, file handle pointer and the
+ *      bank first output flag.
+ */
+struct  bank
+{
+        struct  bank *b_bp;     /* Bank link */
+        char *  b_id;           /* Bank Name */
+        char *  b_fsfx;         /* Bank File Suffix / File Specification */
+        a_uint  b_base;         /* Bank base address */
+        a_uint  b_size;         /* Bank size */
+        a_uint  b_map;          /* Bank mapping */
+        int     b_flag;         /* Bank flags */
+        char *  b_fspec;        /* Bank File Specification */
+        FILE *  b_ofp;          /* Bank File Handle */
+        char *  b_ofspec;       /* Bank Output File Specification */
+        int     b_oflag;        /* Bank has output flag */
+        int     b_rtaflg;       /* Bank First Output flag */
+};
+
+#define B_BASE  0001            /* 'base' address specified */
+#define B_SIZE  0002            /* 'size' of bank specified */
+#define B_FSFX  0004            /* File suffix specified */
+#define B_MAP   0010            /* Mapped Bank Flag */
+
+/*
+ *      A structure area is created for each 'unique' data/code
+ *      area definition found as the REL files are read.  The
+ *      struct area contains the name of the area, a flag byte
+ *      which contains the area attributes (REL/CON/OVR/ABS),
+ *      the area base address set flag byte (-b option), and the
+ *      area base address and total size which will be filled
+ *      in at the end of the first pass through the REL files.
+ *      The area structure also contains a link to the bank
+ *      this area is a part of and a data output file handle
+ *      pointer which is loaded from from the bank structure.
+ *      As A directives are read from the REL files a linked
+ *      list of unique area structures is created by placing a
+ *      link to the new area structure in the previous area structure.
+ */
+struct  area
+{
+        struct  area    *a_ap;  /* Area link */
+        struct  areax   *a_axp; /* Area extension link */
+        struct  bank    *a_bp;  /* Bank link */
+        FILE *  a_ofp;          /* Area File Handle */
+        a_uint  a_addr;         /* Beginning address of area */
+        a_uint  a_size;         /* Total size of the area */
+        int     a_bset;         /* Area base address set */
+/* sdld specific */
+        a_uint  a_unaloc;       /* Total number of unallocated bytes, for error reporting */
+/* end sdld specific */
+        int     a_flag;         /* Flags */
+        char *  a_id;           /* Name */
+/* sdld specific */
+        char    *a_image;       /* Something for hc08/lkelf */
+        char    *a_used;        /* Something for hc08/lkelf */
+        a_uint  a_imagesize;    /* Something for hc08/lkelf */
+/* end sdld specific */
+};
+
+/*
+ *      An areax structure is created for every A directive found
+ *      while reading the REL files.  The struct areax contains a
+ *      link to the 'unique' area structure referenced by the A
+ *      directive and to the head structure this area segment is
+ *      a part of.  The size of this area segment as read from the
+ *      A directive is placed in the areax structure.  The beginning
+ *      address of this segment will be filled in at the end of the
+ *      first pass through the REL files.  As A directives are read
+ *      from the REL files a linked list of areax structures is
+ *      created for each unique area.  The final areax linked
+ *      list has at its head the 'unique' area structure linked
+ *      to the linked areax structures (one areax structure for
+ *      each A directive for this area).
+ */
+struct  areax
+{
+        struct  areax   *a_axp; /* Area extension link */
+        struct  area    *a_bap; /* Base area link */
+        struct  head    *a_bhp; /* Base header link */
+        a_uint  a_addr;         /* Beginning address of section */
+        a_uint  a_size;         /* Size of the area in section */
+};
+
+/*
+ *      A sym structure is created for every unique symbol
+ *      referenced/defined while reading the REL files.  The
+ *      struct sym contains the symbol's name, a flag value
+ *      (not used in this linker), a symbol type denoting
+ *      referenced/defined, and an address which is loaded
+ *      with the relative address within the area in which
+ *      the symbol was defined.  The sym structure also
+ *      contains a link to the area where the symbol was defined.
+ *      The sym structures are linked into linked lists using
+ *      the symbol link element.
+ */
+struct  sym
+{
+        struct  sym     *s_sp;  /* Symbol link */
+        struct  areax   *s_axp; /* Symbol area link */
+        char    s_type;         /* Symbol subtype */
+        char    s_flag;         /* Flag byte */
+        a_uint  s_addr;         /* Address */
+        char    *s_id;          /* Name (JLH) */
+        char    *m_id;          /* Module symbol define in */
+};
+
+/*
+ *      The structure lfile contains a pointer to a
+ *      file specification string, an index which points
+ *      to the file name (past the 'path'), the file type,
+ *      an object output flag, and a link to the next
+ *      lfile structure.
+ */
+struct  lfile
+{
+        struct  lfile   *f_flp; /* lfile link */
+        int     f_type;         /* File type */
+        char    *f_idp;         /* Pointer to file spec */
+        int     f_idx;          /* Index to file name */
+        int     f_obj;          /* Object output flag */
+};
+
+/*
+ *      The struct base contains a pointer to a
+ *      base definition string and a link to the next
+ *      base structure.
+ */
+struct  base
+{
+        struct  base  *b_base;  /* Base link */
+        char          *b_strp;  /* String pointer */
+};
+
+/*
+ *      The struct globl contains a pointer to a
+ *      global definition string and a link to the next
+ *      global structure.
+ */
+struct  globl
+{
+        struct  globl *g_globl; /* Global link */
+        char          *g_strp;  /* String pointer */
+};
+
+/*
+ *      A structure sdp is created for each 'unique' paged
+ *      area definition found as the REL files are read.
+ *      As P directives are read from the REL files a linked
+ *      list of unique sdp structures is created by placing a
+ *      link to the new sdp structure in the previous area structure.
+ */
+struct  sdp
+{
+        struct  area  *s_area;  /* Paged Area link */
+        struct  areax *s_areax; /* Paged Area Extension Link */
+        a_uint  s_addr;         /* Page address offset */
+};
+
+/*
+ *      The structure rerr is loaded with the information
+ *      required to report an error during the linking
+ *      process.  The structure contains an index value
+ *      which selects the areax structure from the header
+ *      areax structure list, a mode value which selects
+ *      symbol or area relocation, the base address in the
+ *      area section, an area/symbol list index value, and
+ *      an area/symbol offset value.
+ */
+struct  rerr
+{
+        int     aindex;         /* Linking area */
+        int     mode;           /* Relocation mode */
+        a_uint  rtbase;         /* Base address in section */
+        int     rindex;         /* Area/Symbol reloaction index */
+        a_uint  rval;           /* Area/Symbol offset value */
+};
+
+/*
+ *      The structure lbpath is created for each library
+ *      path specification input by the -k option.  The
+ *      lbpath structures are linked into a list using
+ *      the next link element.
+ */
+struct lbpath {
+        struct  lbpath  *next;
+        char            *path;
+};
+
+/*
+ *      The structure lbname is created for all combinations of the
+ *      library path specifications (input by the -k option) and the
+ *      library file specifications (input by the -l option) that
+ *      lead to an existing file.  The element path points to
+ *      the path string, element libfil points to the library
+ *      file string, and the element libspc is the concatenation
+ *      of the valid path and libfil strings.
+ *
+ *      The lbpath structures are linked into a list
+ *      using the next link element.
+ *
+ *      Each library file contains a list of object files
+ *      that are contained in the particular library. e.g.:
+ *
+ *              \iolib\termio
+ *              \inilib\termio
+ *
+ *      Only one specification per line is allowed.
+ */
+struct lbname {
+        struct  lbname  *next;
+        char            *path;
+        char            *libfil;
+        char            *libspc;
+        int             f_obj;
+};
+
+/*
+ *      The function fndsym() searches through all combinations of the
+ *      library path specifications (input by the -k option) and the
+ *      library file specifications (input by the -l option) that
+ *      lead to an existing file for a symbol definition.
+ *
+ *      The structure lbfile is created for the first library
+ *      object file which contains the definition for the
+ *      specified undefined symbol.
+ *
+ *      The element libspc points to the library file path specification
+ *      and element relfil points to the object file specification string.
+ *      The element filspc is the complete path/file specification for
+ *      the library file to be imported into the linker.  The f_obj
+ *      flag specifies if the object code from this file is
+ *      to be output by the linker.  The file specification
+ *      may be formed in one of two ways:
+ *
+ *      (1)     If the library file contained an absolute
+ *              path/file specification then this becomes filspc.
+ *              (i.e. C:\...)
+ *
+ *      (2)     If the library file contains a relative path/file
+ *              specification then the concatenation of the path
+ *              and this file specification becomes filspc.
+ *              (i.e. \...)
+ *
+ *      The lbpath structures are linked into a list
+ *      using the next link element.
+ */
+struct lbfile {
+        struct  lbfile  *next;
+        char            *libspc;
+        char            *relfil;
+        char            *filspc;
+        int             f_obj;
+/* sdld specific */
+        long            offset;
+        unsigned int    type;
+/* end sdld specific */
+};
+
+/*
+ *      External Definitions for all Global Variables
+ */
+
+extern  char    *_abs_;         /*      = { ".  .ABS." };
+                                 */
+extern  int     lkerr;          /*      ASLink error flag
+                                 */
+extern  char    *ip;            /*      pointer into the REL file
+                                 *      text line in ib[]
+                                 */
+extern  char    ib[NINPUT];     /*      REL file text line
+                                 */
+extern  char    *rp;            /*      pointer into the LST file
+                                 *      text line in rb[]
+                                 */
+extern  char    rb[NINPUT];     /*      LST file text line being
+                                 *      address relocated
+                                 */
+extern  char    ctype[];        /*      array of character types, one per
+                                 *      ASCII character
+                                 */
+
+/*
+ *      Character Type Definitions
+ */
+#define SPACE   '\000'
+#define ETC     '\000'
+#define LETTER  '\001'
+#define DIGIT   '\002'
+#define BINOP   '\004'
+#define RAD2    '\010'
+#define RAD8    '\020'
+#define RAD10   '\040'
+#define RAD16   '\100'
+#define ILL     '\200'
+
+#define DGT2    DIGIT|RAD16|RAD10|RAD8|RAD2
+#define DGT8    DIGIT|RAD16|RAD10|RAD8
+#define DGT10   DIGIT|RAD16|RAD10
+#define LTR16   LETTER|RAD16
+
+extern  char    afspec[];       /*      The filespec created by afile()
+                                 */
+extern  char    ccase[];        /*      an array of characters which
+                                 *      perform the case translation function
+                                 */
+
+extern  struct  lfile   *filep; /*      The pointers (lfile *) filep,
+                                 *      (lfile *) cfp, and (FILE *) sfp
+                                 *      are used in conjunction with
+                                 *      the routine nxtline() to read
+                                 *      aslink commands from
+                                 *      (1) the standard input or
+                                 *      (2) or a command file
+                                 *      and to read the REL files
+                                 *      sequentially as defined by the
+                                 *      aslink input commands.
+                                 *
+                                 *      The pointer *filep points to the
+                                 *      beginning of a linked list of
+                                 *      lfile structures.
+                                 */
+extern  struct  lfile   *cfp;   /*      The pointer *cfp points to the
+                                 *      current lfile structure
+                                 */
+extern  struct  lfile   *startp;/*      aslink startup file structure
+                                 */
+extern  struct  lfile   *linkp; /*      pointer to first lfile structure
+                                 *      containing an input REL file
+                                 *      specification
+                                 */
+extern  struct  lfile   *lfp;   /*      pointer to current lfile structure
+                                 *      being processed by parse()
+                                 */
+extern  struct  head    *headp; /*      The pointer to the first
+                                 *      head structure of a linked list
+                                 */
+extern  struct  head    *hp;    /*      Pointer to the current
+                                 *      head structure
+                                 */
+extern  struct  bank    *bankp; /*      The pointer to the first
+                                 *      bank structure of a linked list
+                                 */
+extern  struct  bank    *bp;    /*      Pointer to the current
+                                 *      bank structure
+                                 */
+extern  struct  area    *areap; /*      The pointer to the first
+                                 *      area structure of a linked list
+                                 */
+extern  struct  area    *ap;    /*      Pointer to the current
+                                 *      area structure
+                                 */
+extern  struct  areax   *axp;   /*      Pointer to the current
+                                 *      areax structure
+                                 */
+extern  struct  sym *symhash[NHASH]; /* array of pointers to NHASH
+                                      * linked symbol lists
+                                      */
+extern  struct  base    *basep; /*      The pointer to the first
+                                 *      base structure
+                                 */
+extern  struct  base    *bsp;   /*      Pointer to the current
+                                 *      base structure
+                                 */
+extern  struct  globl   *globlp;/*      The pointer to the first
+                                 *      globl structure
+                                 */
+extern  struct  globl   *gsp;   /*      Pointer to the current
+                                 *      globl structure
+                                 */
+extern  struct  sdp     sdp;    /*      Base Paged structure
+                                 */
+extern  struct  rerr    rerr;   /*      Structure containing the
+                                 *      linker error information
+                                 */
+extern  FILE    *nbofp;         /*      Non Banked Linker Output
+                                 *      File Handle
+                                 */
+extern  FILE    *ofp;           /*      Linker Output file handle
+                                 */
+
+#if NOICE
+extern  FILE    *jfp;           /*      NoICE output file handle
+                                 */
+#endif
+
+extern  FILE    *mfp;           /*      Map output file handle
+                                 */
+extern  FILE    *rfp;           /*      File handle for output
+                                 *      address relocated ASxxxx
+                                 *      listing file
+                                 */
+extern  FILE    *sfp;           /*      The file handle sfp points to the
+                                 *      currently open file
+                                 */
+extern  FILE    *tfp;           /*      File handle for input
+                                 *      ASxxxx listing file
+                                 */
+
+#if SDCDB
+extern  FILE    *yfp;           /*      SDCDB output file handle
+                                 */
+#endif
+
+extern  int     oflag;          /*      Output file type flag
+                                 */
+extern  int     objflg;         /*      Linked file/library object output flag
+                                 */
+
+#if NOICE
+extern  int     jflag;          /*      -j, enable NoICE Debug output
+                                 */
+#endif
+
+extern  int     mflag;          /*      Map output flag
+                                 */
+extern  int     xflag;          /*      Map file radix type flag
+                                 */
+
+#if SDCDB
+extern  int     yflag;          /*      -y, enable SDCC Debug output
+                                 */
+#endif
+
+extern  int     pflag;          /*      print linker command file flag
+                                 */
+extern  int     uflag;          /*      Listing relocation flag
+                                 */
+extern  int     wflag;          /*      Enable wide format listing
+                                 */
+extern  int     zflag;          /*      Disable symbol case sensitivity
+                                 */
+extern  int     radix;          /*      current number conversion radix:
+                                 *      2 (binary), 8 (octal), 10 (decimal),
+                                 *      16 (hexadecimal)
+                                 */
+extern  int     line;           /*      current line number
+                                 */
+extern  int     page;           /*      current page number
+                                 */
+extern  int     lop;            /*      current line number on page
+                                 */
+extern  int     pass;           /*      linker pass number
+                                 */
+extern  a_uint  pc;             /*      current relocation address
+                                 */
+extern  int     pcb;            /*      current bytes per pc word
+                                 */
+extern  int     rtcnt;          /*      count of elements in the
+                                 *      rtval[] and rtflg[] arrays
+                                 */
+extern  a_uint  rtval[];        /*      data associated with relocation
+                                 */
+extern  int     rtflg[];        /*      indicates if rtval[] value is
+                                 *      to be sent to the output file.
+                                 */
+extern  int     rterr[];        /*      indicates if rtval[] value should
+                                 *      be flagged as a relocation error.
+                                 */
+extern  char    rtbuf[];        /*      S19/IHX output buffer
+                                 */
+extern  struct  bank *rtabnk;   /*      rtbuf[] processing
+                                 */
+extern  int     rtaflg;         /*      rtbuf[] processing
+                                 */
+extern  a_uint  rtadr0;         /*
+                                 */
+extern  a_uint  rtadr1;         /*
+                                 */
+extern  a_uint  rtadr2;         /*
+                                 */
+extern  int     obj_flag;       /*      Linked file/library object output flag
+                                 */
+extern  int     a_bytes;        /*      REL file T Line address length
+                                 */
+extern  int     hilo;           /*      REL file byte ordering
+                                 */
+extern  a_uint  a_mask;         /*      Address Mask
+                                 */
+extern  a_uint  s_mask;         /*      Sign Mask
+                                 */
+extern  a_uint  v_mask;         /*      Value Mask
+                                 */
+extern  int     gline;          /*      LST file relocation active
+                                 *      for current line
+                                 */
+extern  int     gcntr;          /*      LST file relocation active
+                                 *      counter
+                                 */
+extern  struct lbpath *lbphead; /*      pointer to the first
+                                 *      library path structure
+                                 */
+extern  struct lbname *lbnhead; /*      pointer to the first
+                                 *      library name structure
+                                 */
+extern  struct lbfile *lbfhead; /*      pointer to the first
+                                 *      library file structure
+                                 */
+/* sdld specific */
+extern  int     sflag;          /*      JCF: Memory usage output flag
+                                 */
+extern  int     packflag;       /*      Pack data memory flag
+                                 */
+extern  int     stacksize;      /*      Stack size
+                                 */
+extern int      rflag;          /*      Extended linear address record flag.
+                                */
+extern  a_uint iram_size;       /*      internal ram size
+                                 */
+extern  long xram_size;         /*      external ram size
+                                 */
+extern  long code_size;         /*      code size
+                                 */
+extern  char *sdld_output;      /*      output file name, --output argument
+                                 */
+extern char *optsdcc;
+extern char *optsdcc_module;
+/* sdld 8015 specific */
+extern  char idatamap[256];     /*      space is unused
+                                 */
+/* end sdld 8051 specific */
+/* end sdld specific */
+
+
+
+/* C Library function definitions */
+/* for reference only
+extern  VOID            exit();
+extern  int             fclose();
+extern  char *          fgets();
+extern  FILE *          fopen();
+extern  int             fprintf();
+extern  VOID            free();
+extern  VOID *          malloc();
+extern  char            putc();
+extern  char *          sprintf();
+extern  char *          strcpy();
+extern  int             strlen();
+extern  char *          strncpy();
+extern  char *          strrchr();
+*/
+
+/* Program function definitions */
+
+#ifdef  OTHERSYSTEM
+
+/* lkmain.c */
+extern  FILE *          afile(char *fn, char *ft, int wf);
+extern  VOID            bassav(void);
+extern  int             fndidx(char *str);
+extern  int             fndext(char *str);
+extern  VOID            gblsav(void);
+extern  int             intsiz(void);
+extern  VOID            iramsav(void);
+extern  VOID            xramsav(void);
+extern  VOID            codesav(void);
+extern  VOID            iramcheck(void);
+extern  VOID            link_main(void);
+extern  VOID            lkexit(int i);
+extern  int             main(int argc, char *argv[]);
+extern  VOID            map(void);
+extern  VOID            sym(void);
+extern  int             parse(void);
+extern  VOID            doparse(void);
+extern  VOID            setarea(void);
+extern  VOID            setgbl(void);
+extern  VOID            usage(int n);
+extern  VOID            copyfile (FILE *dest, FILE *src);
+
+/* lklex.c */
+extern  VOID            chopcrlf(char *str);
+extern  char            endline(void);
+extern  int             get(void);
+extern  VOID            getfid(char *str, int c);
+extern  VOID            getid(char *id, int c);
+extern  VOID            getSid(char *id);
+extern  int             getmap(int d);
+extern  int             getnb(void);
+extern  int             more(void);
+extern  int             nxtline(void);
+extern  VOID            skip(int c);
+extern  VOID            unget(int c);
+
+/* lkarea.c */
+extern  VOID            lkparea(char *id);
+extern  VOID            lnkarea(void);
+extern  VOID            lnkarea2(void);
+extern  VOID            newarea(void);
+
+/* lkbank.c */
+extern  VOID            chkbank(FILE *fp);
+extern  VOID            lkfclose(void);
+extern  VOID            lkfopen(void);
+extern  VOID            lkpbank(char * id);
+extern  VOID            newbank(void);
+extern  VOID            setbank(void);
+
+/* lkhead.c */
+extern  VOID            module(void);
+extern  VOID            newhead(void);
+extern  VOID            newmode(void);
+
+/* lksym.c */
+extern  int             hash(char *p, int cflag);
+extern  struct  sym *   lkpsym(char *id, int f);
+extern  char *          new(unsigned int n);
+extern  struct  sym *   newsym(void);
+extern  char *          strsto(char *str);
+extern  VOID            symdef(FILE *fp);
+extern  int             symeq(char *p1, char *p2, int cflag);
+extern  VOID            syminit(void);
+extern  VOID            symmod(FILE *fp, struct sym *tsp);
+extern  a_uint          symval(struct sym *tsp);
+
+/* lkeval.c */
+extern  int             digit(int c, int r);
+extern  a_uint          eval(void);
+extern  a_uint          expr(int n);
+extern  int             oprio(int c);
+extern  a_uint          term(void);
+
+/* lklist.c */
+extern  int             dgt(int rdx, char *str, int n);
+extern  VOID            newpag(FILE *fp);
+extern  VOID            slew(struct area *xp, struct bank *yp);
+extern  VOID            lstarea(struct area *xp, struct bank *yp);
+extern  VOID            lkulist(int i);
+extern  VOID            lkalist(a_uint cpc);
+extern  VOID            lkglist(a_uint cpc, int v, int err);
+
+/* lknoice.c */
+extern  VOID            NoICEfopen(void);
+extern  VOID            NoICEmagic(void);
+extern  VOID            DefineNoICE(char *name, a_uint value, struct bank *yp);
+extern  VOID            DefineGlobal(char *name, a_uint value, struct bank *yp);
+extern  VOID            DefineScoped(char *name, a_uint value, struct bank *yp);
+extern  VOID            DefineFile(char *name, a_uint value, struct bank *yp);
+extern  VOID            DefineFunction(char *name, a_uint value, struct bank *yp);
+extern  VOID            DefineStaticFunction(char *name, a_uint value, struct bank *yp);
+extern  VOID            DefineEndFunction(a_uint value, struct bank *yp);
+extern  VOID            DefineLine(char *lineString, a_uint value, struct bank *yp);
+extern  VOID            PagedAddress(a_uint value, struct bank *yp);
+
+/* lksdcdb.c */
+extern  VOID            SDCDBfopen(void);
+extern  VOID            SDCDBcopy(char * str);
+extern  VOID            DefineSDCDB(char *name, a_uint value);
+
+/* lkrloc.c */
+extern  a_uint          adb_1b(a_uint v, int i);
+extern  a_uint          adb_2b(a_uint v, int i);
+extern  a_uint          adb_3b(a_uint v, int i);
+extern  a_uint          adb_4b(a_uint v, int i);
+extern  a_uint          adb_xb(a_uint v, int i);
+extern  a_uint          evword(void);
+extern  VOID            prntval(FILE *fptr, a_uint v);
+extern  VOID            reloc(int c);
+
+/* lkrloc3.c */
+extern  a_uint          adb_bit(a_uint v, int i);
+extern  a_uint          adb_24_bit(a_uint v, int i);
+extern  a_uint          adb_24_hi(a_uint v, int i);
+extern  a_uint          adb_24_mid(a_uint v, int i);
+extern  a_uint          adb_24_lo(a_uint v, int i);
+extern  a_uint          adb_hi(a_uint  v, int i);
+extern  a_uint          adb_lo(a_uint  v, int i);
+extern  char *          errmsg3[];
+extern  VOID            errdmp3(FILE *fptr, char *str);
+extern  VOID            erpdmp3(FILE *fptr, char *str);
+extern  VOID            rele3(void);
+extern  VOID            reloc3(int c);
+extern  VOID            relt3(void);
+extern  VOID            relr3(void);
+extern  VOID            relp3(void);
+extern  VOID            relerr3(char *str);
+extern  VOID            relerp3(char *str);
+
+/* lklibr.c */
+extern  int             addfile(char *path, char *libfil);
+extern  VOID            addlib(void);
+extern  VOID            addpath(void);
+extern  int             fndsym(char *name);
+extern  VOID            library(void);
+extern  VOID            loadfile(char *filspc);
+extern  VOID            search(void);
+
+/* lkout.c */
+extern  VOID            lkout(int i, int b);
+extern  VOID            lkflush(void);
+extern  VOID            ixx(int i, int b);
+extern  VOID            iflush(void);
+extern  VOID            dbx(int i);
+extern  VOID            dflush(void);
+
+/* lks19.c */
+extern  VOID            s19(int i);
+extern  VOID            sflush(void);
+
+/* EEP: lkelf.c */
+extern  VOID            elf();
+
+/* JCF: lkmem.c */
+extern int summary(struct area * xp);
+extern int summary2(struct area * xp);
+
+/* JCF: lkaomf51.c */
+extern void SaveLinkedFilePath(char * filepath);
+extern void CreateAOMF51(void);
+
+/* lkgb.h */
+VOID gb(int in);
+VOID gg(int in);
+
+/* strcmpi.h */
+extern int as_strcmpi(const char *s1, const char *s2);
+extern int as_strncmpi(const char *s1, const char *s2, size_t n);
+
+#else
+
+#endif
diff --git a/Kernel/tools/bankld/asxxxx_config.h b/Kernel/tools/bankld/asxxxx_config.h
new file mode 100644 (file)
index 0000000..a5637d3
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __ASXXXX_CONFIG_H
+#define __ASXXXX_CONFIG_H
+
+#define TYPE_BYTE char
+#define TYPE_WORD short
+#define TYPE_DWORD int
+#define TYPE_UBYTE unsigned char
+#define TYPE_UWORD unsigned short
+#define TYPE_UDWORD unsigned int
+
+#endif  /* __ASXXXX_CONFIG_H */
diff --git a/Kernel/tools/bankld/lk_readnl.c b/Kernel/tools/bankld/lk_readnl.c
new file mode 100644 (file)
index 0000000..5eecf9d
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+  lk_readnl.c - read a line from file into a buffer
+  version 1.0.0, April 25th, 2008
+
+  Copyright (c) 2008 Borut Razem
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Borut Razem
+  borut.razem@siol.net
+*/
+
+#include "lk_readnl.h"
+
+/*******************************************************************************
+
+                                lk_readnl
+
+lk_readnl() reads in at most one less than size characters from stream and stores
+them into the buffer pointed to by s. Reading stops after an EOF or a newline.
+The newline character is not stored into the buffer. A '\0' is stored after the
+last character in the buffer. All the characters between size and the newline or
+EOF are skipped.
+
+lk_readnl() return s on success, and NULL on error or when end of file occurs
+while no characters have been read.
+
+*******************************************************************************/
+
+char *
+lk_readnl (char *s, int size, FILE * stream)
+{
+  static char eof_f = 0;
+  int c = '\0';
+  char *s_o;
+  char prev_c;
+
+  if (eof_f)
+    {
+      eof_f = 0;
+      return NULL;
+    }
+
+  s_o = s;
+  --size;                       /* for null terminator */
+  while (size > 0)
+    {
+      prev_c = c;
+      if ((c = getc (stream)) == '\n' || c == EOF)
+        break;
+
+      if (prev_c == '\r')
+        {
+          *s++ = prev_c;
+          if (--size <= 0)
+            break;
+        }
+
+      if (c != '\r')
+        {
+          *s++ = c;
+          --size;
+        }
+    }
+  *s = '\0';
+
+  while (c != '\n' && c != EOF)
+    c = getc (stream);
+
+  if (c == EOF)
+    {
+      if (s == s_o)
+        return NULL;
+
+      eof_f = 1;
+    }
+
+  return s_o;
+}
diff --git a/Kernel/tools/bankld/lk_readnl.h b/Kernel/tools/bankld/lk_readnl.h
new file mode 100644 (file)
index 0000000..b02cffb
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+  lk_readnl.h - read a line from file into a buffer
+  version 1.0.0, Aprile 25th, 2008
+
+  Copyright (c) 2008 Borut Razem
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+
+  Borut Razem
+  borut.razem@siol.net
+*/
+
+
+#ifndef __LK_READNL_H
+#define __LK_READNL_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  char *lk_readnl (char *s, int size, FILE * stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                          /* __LK_READNL_H */
diff --git a/Kernel/tools/bankld/lkaomf51.c b/Kernel/tools/bankld/lkaomf51.c
new file mode 100644 (file)
index 0000000..d88732f
--- /dev/null
@@ -0,0 +1,1119 @@
+/* lkaomf51.c - Create an absolute object memory format 51 file
+
+   Copyright (C) 2002 Jesus Calvino-Fraga, jesusc at ieee dot org
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "aslink.h"
+
+#define EQ(A,B) !strcmp((A),(B))
+#define MEMSIZE 0x1000000
+#ifndef DODUMP
+#define DODUMP 0
+#endif
+
+typedef struct
+{
+    char PathName[PATH_MAX];
+    char ModuleName[PATH_MAX];
+} _infn;
+
+int numin=0;
+_infn * infn=NULL;
+
+typedef struct
+{
+    char name[0x100];
+    int FileNameNumber;
+    int Procedure;//If the symbol belongs to a function
+    int Static; //If the symbol is only public on its file
+    int Address;
+    int UsageType;
+} _symbol;
+
+int numsym=0;
+_symbol * symbol=NULL;
+
+typedef struct
+{
+    char name[0x100];
+    int FileNameNumber;
+    int BeginAdd;
+    int EndAdd;
+    int RegBank;
+} _procedure;
+
+int numproc=0;
+_procedure * procedure=NULL;
+
+typedef struct
+{
+    int Number;
+    int Address;
+    int Procedure;
+    int FileNameNumber;
+} _linenum;
+
+int numlinenum=0;
+_linenum * linenum=NULL;
+#if 0
+typedef struct
+{
+    char * name;
+    int usage;
+}
+_UsageType;
+
+_UsageType UsageType[]=
+{
+    {"CSEG",        0},
+    {"GSINIT",      0},
+    {"GSINIT0",     0},
+    {"GSINIT1",     0},
+    {"GSINIT2",     0},
+    {"GSINIT3",     0},
+    {"GSINIT4",     0},
+    {"GSINIT5",     0},
+    {"GSFINAL",     0},
+    {"HOME",        0},
+    {"XINIT",       0},
+    {"XSEG",        1},
+    {"XISEG",       1},
+    {"REG_BANK_0",  2},
+    {"REG_BANK_1",  2},
+    {"REG_BANK_2",  2},
+    {"REG_BANK_3",  2},
+    {"DSEG",        2},
+    {"OSEG",        2},
+    {"SSEG",        2},
+    {"ISEG",        3},
+    {"BSEG",        4},
+    {"",            5} /*A typeless number?*/
+};
+#endif
+char * UsageTypeName[]={"CODE", "XDATA", "DATA", "IDATA", "BIT", "NUMBER"};
+int AddNumber;
+short * ihxBuff=NULL;
+FILE * aomf51out;
+int GlobalChkSum=0;
+int HexSize, HexBegin=0x1000000;
+
+
+int GetName(char * filepath, char * name)
+{
+  int j, k;
+  for(j=strlen(filepath); j>0; j--)
+      if( (filepath[j-1]=='/')||(filepath[j-1]=='\\') ) break;
+  for(k=0; (filepath[j]!=0)&&(filepath[j]!='.'); j++, k++)
+      name[k]=filepath[j];
+  name[k]=0;
+  return j;
+}
+
+void SaveLinkedFilePath(char * filepath)
+{
+  int j;
+
+  if((yflag) && (!rflag))
+    {
+      int ext;
+
+      infn = realloc(infn, sizeof(_infn)*(numin+1));
+
+      /*Get the module name=filename, no drive, no dir, no ext*/
+      ext = GetName(filepath, infn[numin].ModuleName);
+      //printf("%s, %s\n", infn[numin].PathName, infn[numin].ModuleName);
+
+      strcpy(infn[numin].PathName, filepath);
+
+      /*If there is an extension remove it*/
+      if (infn[numin].PathName[ext] == '.')
+        infn[numin].PathName[ext] = '\0';
+
+      /*Check if this filename is already in*/
+      for (j=0; j<numin; j++)
+        {
+          if (EQ(infn[numin].PathName, infn[j].PathName))
+            break;
+        }
+      if (j==numin)
+        numin++;
+    }
+}
+
+void FreeAll(void)
+{
+  if(infn!=NULL)
+    {
+      free(infn);
+      numin=0;
+      infn=NULL;
+    }
+
+  if(symbol!=NULL)
+    {
+      free(symbol);
+      numsym=0;
+      symbol=NULL;
+    }
+
+  if(procedure!=NULL)
+    {
+      free(procedure);
+      numproc=0;
+      procedure=NULL;
+    }
+
+  if(linenum!=NULL)
+    {
+      free(linenum);
+      numlinenum=0;
+      linenum=NULL;
+    }
+
+  if(ihxBuff!=NULL)
+    {
+      free(ihxBuff);
+      ihxBuff=NULL;
+    }
+}
+
+void OutputByte(unsigned char value)
+{
+  GlobalChkSum+=value;
+  fwrite( &value, 1, 1, aomf51out );
+}
+
+void OutputWord(int value)
+{
+  OutputByte((unsigned char)(value%0x100));
+  OutputByte((unsigned char)(value/0x100));
+}
+
+void OutputName(char * name)
+{
+  int k;
+  OutputByte((unsigned char)strlen(name));
+  for(k=0; name[k]!=0; k++)
+      OutputByte((unsigned char)toupper(name[k]));
+}
+
+void OutputChkSum(void)
+{
+  OutputByte((unsigned char)(0x100-(GlobalChkSum%0x100)));
+  GlobalChkSum=0;
+}
+
+void DumpForDebug (void)
+{
+  char DumpFileName[PATH_MAX];
+  FILE * DumpFile;
+  int j, k;
+
+  strcpy(DumpFileName, infn[0].PathName);
+  strcat(DumpFileName, ".d51");
+
+  DumpFile=fopen(DumpFileName, "wb");
+  if(DumpFile==NULL)
+    {
+      printf("Couldn't create file %s\n", DumpFileName);
+      return;
+    }
+
+  fprintf(DumpFile,"SYMBOLS:\n");
+
+  for(j=0; j<numsym; j++)
+    {
+      k=symbol[j].UsageType&0xf;
+      fprintf(DumpFile, "%s, %s, %s, 0x%04x, %s\n",
+              symbol[j].name,
+              infn[symbol[j].FileNameNumber].PathName,
+              (symbol[j].Procedure>=0)?procedure[symbol[j].Procedure].name:"GLOBAL",
+              symbol[j].Address,
+              k<6?UsageTypeName[k]:"???");
+    }
+
+  fprintf(DumpFile,"\nPROCEDURES:\n");
+  for(j=0; j<numproc; j++)
+    {
+      fprintf(DumpFile, "%s, %s, 0x%04x-0x%04x, %c\n",
+              procedure[j].name,
+              infn[procedure[j].FileNameNumber].PathName,
+              procedure[j].BeginAdd,
+              procedure[j].EndAdd,
+              procedure[j].RegBank + '0');
+    }
+
+  fprintf(DumpFile,"\nLINE NUMBERS:\n");
+  for(j=0; j<numlinenum; j++)
+    {
+      fprintf(DumpFile, "%d:0x%04x, %s -> %s\n",
+              linenum[j].Number,
+              linenum[j].Address,
+              infn[linenum[j].FileNameNumber].PathName,
+              (linenum[j].Procedure>=0)?procedure[linenum[j].Procedure].name:"I don't know");
+    }
+
+  fclose(DumpFile);
+}
+
+void ParseRegisters(_symbol * symbol, const char * Registers)
+{
+  char c;
+  int i;
+  char regs[0x100][4];
+  int address[4];
+  int nRegs = sscanf(Registers, "[ %[^,] %c %[^,] %c %[^,] %c %[^,] ]",
+                     regs[0], &c, regs[1], &c,  regs[2], &c, regs[3]);
+  nRegs = (nRegs + 1) / 2;
+  for (i=0; i<nRegs; i++)
+    {
+      if ((regs[i][0] == 'r') && isdigit(regs[i][1]))
+        {
+          address[i] = regs[i][1] - '0';
+        }
+    }
+  for (i=1; i<nRegs; i++)
+    {
+      if (address[i] != address[i-1] + 1)
+        {// we need strict ascending registers
+          return;
+        }
+    }
+  if (0 <= symbol->Procedure && symbol->Procedure < numproc)
+    symbol->Address = address[0] + procedure[symbol->Procedure].RegBank * 8;
+}
+
+void OutputAOEMF51(void)
+{
+  int i, j, k, recsize;
+  char MHRname[0x100], Mname[0x100];
+  char aomf51FileName[PATH_MAX];
+
+  strcpy(aomf51FileName, infn[0].PathName);
+  strcat(aomf51FileName, ".omf");
+
+  aomf51out=fopen(aomf51FileName, "wb");
+  if(aomf51out==NULL)
+    {
+      printf("Couldn't create file %s\n", aomf51FileName);
+      return;
+    }
+
+  GetName(infn[0].PathName, MHRname);
+  GlobalChkSum=0;
+
+  /*Module header record*/
+  OutputByte(0x02);/*REC TYPE*/
+  OutputWord((strlen(MHRname)+1)+3);/*Record Length*/
+  OutputName(MHRname);/*Module Name*/
+  OutputByte(0xff);/*TRN ID: RL51?*/
+  OutputByte(0x00);
+  OutputChkSum();
+
+  for(j=0; j<numin; j++)
+    {
+      GetName(infn[j].PathName, Mname);
+
+      /*Scope Definition record: begin module block*/
+      OutputByte(0x10);/*REC TYPE*/
+      OutputWord((strlen(Mname)+1)+2);/*Record Length*/
+      OutputByte(0x00);/*BLK TYP: module block*/
+      OutputName(Mname);/*Module Name*/
+      OutputChkSum();
+
+      /*Public symbols defined in this module*/
+      recsize=2;
+      for(k=0; k<numsym; k++)/*Compute the record length*/
+        {
+          if ( (symbol[k].FileNameNumber==j) &&
+               (symbol[k].Address!=-1) &&
+               (symbol[k].Procedure==-1) &&
+               (symbol[k].Static==-1) )
+            {
+              recsize+=((strlen(symbol[k].name)+1)+5);
+            }
+        }
+
+      if(recsize>2) /*If there are any symbols*/
+        {
+          OutputByte(0x12);       /*REC TYPE*/
+          OutputWord(recsize);    /*Record Length*/
+          OutputByte(0x01);       /*DEF TYPE: Public symbols*/
+          for(k=0; k<numsym; k++)
+            {
+              if ( (symbol[k].FileNameNumber==j) &&
+                   (symbol[k].Address!=-1) &&
+                   (symbol[k].Procedure==-1) &&
+                   (symbol[k].Static==-1) )
+                {
+                  OutputByte(0x00);/*SEG ID*/
+                  OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
+                  OutputWord(symbol[k].Address);/*Offset*/
+                  OutputByte(0x00);
+                  OutputName(symbol[k].name);/*Symbol name*/
+                }
+            }
+          OutputChkSum();
+        }
+
+      /*Local symbols defined in this module*/
+      recsize=2;
+      for(k=0; k<numsym; k++)/*Compute the record length*/
+        {
+          if ( (symbol[k].FileNameNumber==j) &&
+               (symbol[k].Address!=-1) &&
+               (symbol[k].Procedure==-1) &&
+               (symbol[k].Static==j) )
+            {
+              recsize+=((strlen(symbol[k].name)+1)+5);
+            }
+        }
+
+      if(recsize>2) /*If there are any symbols*/
+        {
+          OutputByte(0x12);       /*REC TYPE*/
+          OutputWord(recsize);    /*Record Length*/
+          OutputByte(0x00);       /*DEF TYPE: Local symbols*/
+          for(k=0; k<numsym; k++)
+            {
+              if ( (symbol[k].FileNameNumber==j) &&
+                   (symbol[k].Address!=-1) &&
+                   (symbol[k].Procedure==-1) &&
+                   (symbol[k].Static==j) )
+                {
+                  OutputByte(0x00);/*SEG ID*/
+                  OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
+                  OutputWord(symbol[k].Address);/*Offset*/
+                  OutputByte(0x00);
+                  OutputName(symbol[k].name);/*Symbol name*/
+                }
+            }
+          OutputChkSum();
+        }
+
+      /*Output the procedures of this module*/
+
+      for(k=0; k<numproc; k++)
+        {
+          if(procedure[k].FileNameNumber==j)
+            {
+              /*Scope Definition record: begin PROCEDURE block*/
+              OutputByte(0x10);/*REC TYPE*/
+              OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
+              OutputByte(0x02);/*BLK TYP: PROCEDURE block*/
+              OutputName(procedure[k].name);/*Module Name*/
+              OutputChkSum();
+
+              /*Content Record*/
+              OutputByte(0x06);/*REC TYPE*/
+              if (procedure[k].EndAdd==-1)
+                  procedure[k].EndAdd=HexSize;
+              recsize=procedure[k].EndAdd-procedure[k].BeginAdd+1+4;
+              OutputWord(recsize);/*Record Length*/
+              OutputByte(0x00);/*SEG ID*/
+              OutputWord(procedure[k].BeginAdd); /*Offset*/
+              for (i=procedure[k].BeginAdd; i<=procedure[k].EndAdd; i++)
+                {
+                  OutputByte((unsigned char)ihxBuff[i]);
+                  ihxBuff[i] -= 0x200;
+                }
+              OutputChkSum();
+
+              /*Local Symbols*/
+
+              recsize=2;
+              for(i=0; i<numsym; i++)/*Get the record length*/
+                {
+                  if( (symbol[i].Procedure==k) &&
+                      (symbol[i].Address!=-1) )
+                    {
+                      recsize+=((strlen(symbol[i].name)+1)+5);
+                    }
+                }
+
+              if(recsize>2) /*If there are any symbols*/
+                {
+                  OutputByte(0x12);       /*REC TYPE*/
+                  OutputWord(recsize);    /*Record Length*/
+                  OutputByte(0x00);       /*DEF TYPE: Local symbols*/
+                  for(i=0; i<numsym; i++)
+                    {
+                      if ( (symbol[i].Procedure==k) &&
+                           (symbol[i].Address!=-1) )
+                        {
+                          OutputByte(0x00);/*SEG ID*/
+                          OutputByte((unsigned char)symbol[i].UsageType);/*SYM INFO*/
+                          OutputWord(symbol[i].Address);/*Offset*/
+                          OutputByte(0x00);
+                          OutputName(symbol[i].name);/*Symbol name*/
+                        }
+                    }
+                  OutputChkSum();
+                }
+
+              /*Line Numbers*/
+              recsize=2;
+              for(i=0; i<numlinenum; i++)/*Get the record length*/
+                  if(linenum[i].Procedure==k)
+                      recsize+=5;
+
+              if(recsize>2) /*If there are any line numbers*/
+                {
+                  OutputByte(0x12);       /*REC TYPE*/
+                  OutputWord(recsize);    /*Record Length*/
+                  OutputByte(0x03);       /*DEF TYPE: Line numbers*/
+                  for(i=0; i<numlinenum; i++)
+                    {
+                      if ( (linenum[i].Procedure==k) )
+                        {
+                          OutputByte(0x00);/*SEG ID*/
+                          OutputWord(linenum[i].Address);/*Offset*/
+                          OutputWord(linenum[i].Number);/*Line Number*/
+                        }
+                    }
+                  OutputChkSum();
+                }
+
+              /*Scope Definition record: end PROCEDURE block*/
+              OutputByte(0x10);/*REC TYPE*/
+              OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
+              OutputByte(0x05);/*BLK TYP: PROCEDURE end block*/
+              OutputName(procedure[k].name);/*Module Name*/
+              OutputChkSum();
+            }
+        }
+
+      /*Scope Definition record: end module block*/
+      OutputByte(0x10);/*REC TYPE*/
+      OutputWord((strlen(Mname)+1)+2);/*Record Length*/
+      OutputByte(0x03);/*BLK TYP: module end*/
+      OutputName(Mname);/*Module Name*/
+      OutputChkSum();
+    }
+
+  /*Content records for everything that is not in the above procedures*/
+  strcpy(Mname, "OTHER_SDCC_STUFF");
+
+  /*Scope Definition record: begin module block*/
+  OutputByte(0x10);/*REC TYPE*/
+  OutputWord((strlen(Mname)+1)+2);/*Record Length*/
+  OutputByte(0x00);/*BLK TYP: module block*/
+  OutputName(Mname);/*Module Name*/
+  OutputChkSum();
+
+  for (i=HexBegin; i<HexSize; )
+    {
+      for (k=i; k<HexSize; k++)
+        {
+          if (ihxBuff[k] < 0)
+            break;
+        }
+      if (k > i)
+        {
+          /*Content Record*/
+          OutputByte(0x06);/*REC TYPE*/
+          OutputWord(k-i+4);/*Record Length*/
+          OutputByte(0x00);/*SEG ID*/
+          OutputWord(i); /*Offset*/
+          for ( ; i<k; i++)
+            {
+              OutputByte((unsigned char)ihxBuff[i]);
+              ihxBuff[i] -= 0x200;
+            }
+          OutputChkSum();
+        }
+      for ( ; i<HexSize; i++)
+        {
+          if (ihxBuff[i] >= 0)
+            break;
+        }
+    }
+
+  /*Scope Definition record: end module block*/
+  OutputByte(0x10);/*REC TYPE*/
+  OutputWord((strlen(Mname)+1)+2);/*Record Length*/
+  OutputByte(0x03);/*BLK TYP: module end*/
+  OutputName(Mname);/*Module Name*/
+  OutputChkSum();
+
+  /*Module end record*/
+  OutputByte(0x04);/*REC TYPE*/
+  OutputWord((strlen(MHRname)+1)+5);/*Record Length*/
+  OutputName(MHRname);/*Module Name*/
+  OutputWord(0x00);
+  OutputByte(0x0f);/*REG MSK: All the register banks?*/
+  OutputByte(0x00);
+  OutputChkSum();
+
+  fclose(aomf51out);
+}
+
+void CollectInfoFromCDB(void)
+{
+  int i, j, k, CurrentModule;
+  FILE * CDBin;
+  char buff[0x1000];
+  char SourceName[PATH_MAX];
+
+  //"S:{G|F<filename>|L<filename>.<functionName>}$<name>$<level>$<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>"
+  char Sfmt[]="%[^$] %c %[^$] %c %[^$] %c %s";
+  char c;
+  char module[0x100];
+  char scope[0x100];
+  char name[0x100];
+  char level[0x100];
+  char block[0x100];
+  char TypeInfo[0x100];
+  char AddressSpace;
+  int OnStack;
+  int StackOffset;
+  int IsISR;
+  int IntNr;
+  int RegBank;
+  char Registers[0x100];
+  int Address, CLine;
+
+  if(numin==0) return;
+
+  if (yfp != NULL)
+    {
+      fclose(yfp);
+      yfp=NULL;
+    }
+
+  /*Build the source filename*/
+  strcpy(SourceName, infn[0].PathName);
+  strcat(SourceName, ".cdb");
+  CDBin=fopen(SourceName, "r");
+  if(CDBin==NULL)
+    {
+      printf("Couldn't open file '%s'\n", SourceName);
+      lkexit(1);
+    }
+
+  CurrentModule=0; /*Set the active module as the first one*/
+  while(!feof(CDBin))
+    {
+      if(NULL==fgets(buff, sizeof(buff)-1, CDBin))
+        {
+          if(ferror(CDBin))
+            {
+              perror("Can't read file");
+              lkexit(1);
+            }
+          else if(!feof(CDBin))
+            {
+              fprintf(stderr, "Unknown error while reading file '%s'\n", SourceName);
+              lkexit(1);
+            }
+        }
+
+      if(!feof(CDBin)) switch(buff[0])
+        {
+          /*Example: "M:adq"*/
+          case 'M':
+            sscanf(&buff[2], "%s", name);
+            for(j=0; j<numin; j++)
+                if(EQ(infn[j].ModuleName, name)) break;
+            if(j<numin) CurrentModule=j;
+          break;
+
+          /* Example:
+          "S:G$actual$0$0({7}ST__00010000:S),E,0,0"
+          "S:Lfile.main$j$1$1({2}SI:S),E,0,0"
+          "S:Lfile.main$k$1$1({2}DG,SI:S),R,0,0,[r2,r3]"
+          "S:G$DS1306_Reset_SPI$0$0({2}DF,SV:S),C,0,0"
+          "S:G$main$0$0({2}DF,SV:S),C,0,0"
+          */
+
+          case 'S':
+            sscanf(buff, Sfmt,
+                   scope, &c,
+                   name, &c,
+                   level, &c,
+                   block);
+
+            /*<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>*/
+            sscanf(block, "%[^)] %c %c %c %c %d %c %d %c %s",
+                   TypeInfo, &c, &c,
+                   &AddressSpace, &c,
+                   &OnStack, &c,
+                   &StackOffset, &c,
+                   Registers);
+
+            i=-1; k=-1;
+            switch(scope[2])
+              {
+                case 'G': /*Global symbol*/
+                break;
+                case 'F': /*Local symbol to a module*/
+                  for(j=0; j<numin; j++)
+                    {
+                      if (EQ(&scope[3], infn[j].ModuleName))
+                        {
+                          i = j;
+                          break;
+                        }
+                    }
+                break;
+                case 'L': /*Local symbol of a procedure*/
+                  for(j=0; j<numproc; j++)
+                    {
+                      size_t mlen = strlen(infn[procedure[j].FileNameNumber].ModuleName);
+                      if ((!strncmp (&scope[3], infn[procedure[j].FileNameNumber].ModuleName, mlen)) &&
+                          (scope[mlen+3] == '.') &&
+                          (EQ(&scope[mlen+4], procedure[j].name)))
+                        {
+                          k = j; /*Local symbol*/
+                          break;
+                        }
+                    }
+                break;
+              }
+
+            /*This symbol may have been already defined*/
+            for (j=0; j<numsym; j++)
+              {
+                if (EQ(name, symbol[j].name) &&
+                    (symbol[j].Procedure == k) &&
+                    (symbol[j].Static == i) ) break;
+              }
+            if(j==numsym) /*New symbol*/
+              {
+                symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
+                symbol[numsym].FileNameNumber=CurrentModule;
+                strcpy(symbol[numsym].name, name);
+                symbol[numsym].Procedure=k;
+                symbol[numsym].Static=i;
+                symbol[numsym].Address=-1;/*Collected later*/
+
+                switch(AddressSpace)
+                  {
+                    case 'C': /*Code*/
+                    case 'D': /*Code/static segment*/
+                    case 'Z': /*Functions and undefined code space*/
+                      symbol[numsym].UsageType=0x40;
+                    break;
+
+                    case 'F': /*External ram*/
+                    case 'A': /*External stack*/
+                    case 'P': /*External Pdata*/
+                      symbol[numsym].UsageType=0x41;
+                    break;
+
+                    case 'E': /*Internal ram (lower 128) bytes*/
+                    case 'I': /*SFR space*/
+                      symbol[numsym].UsageType=0x42;
+                    break;
+
+                    case 'R': /*Register Space*/
+                      ParseRegisters(&symbol[numsym], Registers);
+                      symbol[numsym].UsageType=0x42;
+                    break;
+
+                    case 'B': /*Internal stack*/
+                    case 'G': /*Internal ram*/
+                      symbol[numsym].UsageType=0x43;
+                    break;
+
+                    case 'H': /*Bit addressable*/
+                    case 'J': /*SBIT space*/
+                      symbol[numsym].UsageType=0x44;
+                    break;
+
+                    default:
+                      printf("Unknown scope information for: %s, AddressSpace:%c\n", symbol[numsym].name, AddressSpace);
+                    break;
+                  }
+                numsym++;
+              }
+          break;
+
+          /*Examples:
+          F:G$AsciiToHex$0$0({2}DF,SC:U),C,0,0,0,0,0
+          F:G$main$0$0({2}DF,SV:S),C,0,0,0,0,0
+          F:Fbug1627975$f2$0$0({2}DF,DG,SI:U),C,0,0,0,0,0 */
+
+          case 'F':
+            sscanf(buff, "%[^$] %c %[^$] %c %[^$] %c %s",
+                   scope, &c,
+                   name, &c,
+                   level, &c,
+                   block);
+
+            /*<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>,<isr?>,<int nr>,<regbank> */
+            sscanf(block, "%[^)] %c %c %c %c %d %c %d %c %d %c %d %c %d",
+                   TypeInfo, &c, &c,
+                   &AddressSpace, &c,
+                   &OnStack, &c,
+                   &StackOffset, &c,
+                   &IsISR, &c,
+                   &IntNr, &c,
+                   &RegBank);
+            /*The same may have been already defined */
+            for(j=0; j<numproc; j++)
+              {
+                if (EQ(name, procedure[j].name) &&
+                    (procedure[j].FileNameNumber == CurrentModule))
+                  {
+                    break;
+                  }
+              }
+            if (j==numproc)
+              {
+                procedure=realloc(procedure, sizeof(_procedure)*(numproc+1));
+                strcpy(procedure[numproc].name, name);
+                procedure[numproc].FileNameNumber=CurrentModule;
+                procedure[numproc].BeginAdd=-1;/*To be collected latter*/
+                procedure[numproc].EndAdd=-1;/*To be collected latter*/
+                procedure[numproc].RegBank=RegBank;
+                numproc++;
+              }
+
+            /*This function name is also a global symbol*/
+            for(j=0; j<numsym; j++)/*A global symbol may have been already defined*/
+              {
+                if (EQ(name, symbol[j].name) &&
+                    (symbol[j].Procedure==-1) &&
+                    (symbol[j].FileNameNumber == CurrentModule))
+                  {
+                    break;
+                  }
+              }
+            if (j==numsym)
+              {
+                symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
+                symbol[numsym].FileNameNumber=CurrentModule;
+                strcpy(symbol[numsym].name, name);
+                symbol[numsym].UsageType=0x00;/*A procedure name symbol*/
+                symbol[numsym].Procedure=-1; /*Global symbol*/
+                symbol[numsym].Address=-1;/*Collected later*/
+                symbol[numsym].Static= buff[2]=='F' ? CurrentModule : -1; // o_gloom
+                numsym++;
+              }
+          break;
+
+          case 'L':
+            switch(buff[2])
+              {
+                case 'G': /*Example L:G$P0$0$0:80*/
+                  sscanf(buff, "%[^$] %c %[^$] %c %[^:] %c %x",
+                         scope, &c, name, &c, level, &c, &Address);
+
+                  for(j=0; j<numsym; j++)
+                    {
+                      if(EQ(symbol[j].name, name))
+                        {
+                          if( (symbol[j].Address==-1) && (symbol[j].Procedure==-1) )
+                            {
+                              symbol[j].Address=Address;
+                            }
+
+                          /*If the symbol is the name of a procedure, the address is also
+                          the begining of such procedure*/
+                          if ((symbol[j].UsageType & 0x0f) == 0x00)
+                            {
+                              for (k=0; k<numproc; k++)
+                                {
+                                  if (EQ(symbol[j].name, procedure[k].name))
+                                    {
+                                      if (procedure[k].BeginAdd == -1)
+                                          procedure[k].BeginAdd = Address;
+                                      break;
+                                    }
+                                }
+                            }
+
+                          break;
+                        }
+                    }
+                break;
+
+                case 'F': /*Example L:Fadq$_str_2$0$0:57A*/
+                  sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
+                         scope, &c, name, &c, level, &c, &Address);
+
+                  for (j=0; j<numsym; j++)
+                    {
+                      if (EQ(symbol[j].name, name) &&
+                          EQ(infn[symbol[j].FileNameNumber].ModuleName, scope))
+                        {
+                          if( (symbol[j].Address == -1) )
+                            {
+                              symbol[j].Address = Address;
+                            }
+                          break;
+                        }
+                    }
+
+                  /*It could be also a static function*/
+                  for (j=0; j<numproc; j++)
+                    {
+                      if (EQ(procedure[j].name, name) &&
+                          EQ(infn[procedure[j].FileNameNumber].ModuleName, scope))
+                        {
+                          if( (procedure[j].BeginAdd == -1) )
+                            {
+                              procedure[j].BeginAdd = Address;
+                            }
+                          break;
+                        }
+                    }
+
+                break;
+
+                case 'L': /*Example L:Lmain$j$1$1:29*/
+
+                  /*
+                  L:Lds1306.DS1306_Write$Value$1$1:34
+                  L:Lds1306.DS1306_Burst_Read$count$1$1:35
+                  L:Lds1306.DS1306_Burst_Read$address$1$1:36
+                  L:Lds1306.DS1306_Burst_Write$count$1$1:37
+                  L:Lds1306.DS1306_Burst_Write$address$1$1:38
+                  */
+                  sscanf(&buff[3], "%[^.] %c %[^$] %c %[^$] %c %[^:] %c %x",
+                         module, &c, scope, &c, name, &c, level, &c, &Address);
+
+                  for (k=0; k<numproc; k++)
+                    {
+                      if (EQ(procedure[k].name, scope) &&
+                          EQ(infn[procedure[k].FileNameNumber].ModuleName, module))
+                        {
+                          for (j=0; j<numsym; j++)
+                            {
+                              if ((symbol[j].FileNameNumber == procedure[k].FileNameNumber) &&
+                                  (symbol[j].Procedure == k) &&
+                                  (EQ(symbol[j].name, name)))
+                                {
+                                  if (symbol[j].Address == -1)
+                                    symbol[j].Address = Address;
+                                  break;
+                                }
+                            }
+                          if (j<numsym)
+                            break;
+                        }
+                    }
+                break;
+
+                /*Line Numbers*/
+                case 'C': /*Example L:C$adq.c$38$1$1:3E*/  /*L:C$hwinit.c$29$1$1:7AD*/
+                  sscanf(&buff[4], "%[^.] %[^$] %c %d %[^:] %c %x",
+                         name, level, &c, &CLine, level, &c, &Address);
+
+                  for(j=0; j<numin; j++)
+                      if(EQ(infn[j].ModuleName, name)) break;
+                  if(j<numin)
+                    {
+                      /*Check if this line is already defined*/
+                      for(k=0; k<numlinenum; k++)
+                        {
+                          if( (linenum[k].Number==CLine) &&
+                              (linenum[k].FileNameNumber==j) )break;
+                        }
+                      if(k==numlinenum) /*New line number*/
+                        {
+                          linenum=realloc(linenum, sizeof(_linenum)*(numlinenum+1));
+                          linenum[numlinenum].Number=CLine;
+                          linenum[numlinenum].FileNameNumber=j;
+                          linenum[numlinenum].Procedure=-1;/*To be asigned later*/
+                          linenum[numlinenum].Address=Address;
+                          numlinenum++;
+                        }
+                    }
+                break;
+
+                case 'A': /*Example L:A$adq$424:40*/
+                        /*No use for this one*/
+                break;
+
+                /*The end of a procedure*/
+                case 'X': /*Example L:XG$AsciiToHex$0$0:88*/
+                  sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
+                         scope, &c, name, &c, level, &c, &Address);
+
+                  for(k=0; k<numproc; k++)
+                    {
+                      if (EQ(procedure[k].name, name) &&
+                          (scope[0] == 'G' ||
+                           EQ(infn[procedure[k].FileNameNumber].ModuleName, &scope[1])))
+                        {
+                          if( (procedure[k].EndAdd == -1) )
+                            {
+                              procedure[k].EndAdd = Address;
+                            }
+                          break;
+                        }
+                    }
+                break;
+              }
+          break;
+
+          default:
+          break;
+        }
+    }
+
+  /*Make sure each procedure has an end*/
+  for(k=0; k<(numproc-1); k++)
+    {
+      if (procedure[k].EndAdd==-1) procedure[k].EndAdd=procedure[k+1].BeginAdd-1;
+    }
+  /*Assign each line number to a procedure*/
+  for(j=0; j<numlinenum; j++)
+    {
+      for(k=0; k<numproc; k++)
+        {
+          if ( (linenum[j].Address>=procedure[k].BeginAdd) &&
+               (linenum[j].Address<=procedure[k].EndAdd) &&
+               (linenum[j].FileNameNumber==procedure[k].FileNameNumber) )
+            {
+              linenum[j].Procedure=k;
+            }
+        }
+    }
+
+  fclose(CDBin);
+}
+
+int hex2dec (unsigned char hex_digit)
+{
+   if (isdigit (hex_digit))
+      return hex_digit-'0';
+   else
+      return toupper (hex_digit)-'A'+10;
+}
+
+unsigned char GetByte(char * buffer)
+{
+    return hex2dec(buffer[0])*0x10+hex2dec(buffer[1]);
+}
+
+unsigned short GetWord(char * buffer)
+{
+  return  hex2dec(buffer[0])*0x1000+
+          hex2dec(buffer[1])*0x100+
+          hex2dec(buffer[2])*0x10+
+          hex2dec(buffer[3]);
+}
+
+int ReadHexFile(int * Begin)
+{
+  char ihxFileName[PATH_MAX];
+  char buffer[1024];
+  FILE * filein;
+  int j;
+  unsigned char linesize, recordtype, rchksum, value;
+  int address, hi_addr = 0;
+  int MaxAddress = 0;
+  int chksum;
+
+  /*If the hexfile is already open, close it*/
+  if(ofp!=NULL)
+    {
+      fclose(ofp);
+      ofp=NULL;
+    }
+
+  strcpy(ihxFileName, infn[0].PathName);
+  strcat(ihxFileName, ".ihx");
+
+  if ( (filein=fopen(ihxFileName, "r")) == NULL )
+    {
+      printf("Error: Can't open file `%s`.\r\n", ihxFileName);
+      return 0;
+    }
+
+  ihxBuff = calloc(MEMSIZE, sizeof(short));
+  if (ihxBuff==NULL)
+    {
+      printf("Insufficient memory\n");
+      fclose(filein);
+      return -1;
+    }
+
+  for (j=0; j<MEMSIZE; j++) ihxBuff[j]=-1;
+
+  while(1)
+    {
+      if(fgets(buffer, sizeof(buffer), filein)==NULL)
+        {
+          printf("Error reading file '%s'\n", ihxFileName);
+          break;
+        }
+      if(buffer[0]==':')
+        {
+          linesize = GetByte(&buffer[1]);
+          address = hi_addr | GetWord(&buffer[3]);
+          recordtype = GetByte(&buffer[7]);
+          rchksum = GetByte(&buffer[9]+(linesize*2));
+          chksum=linesize+(address/0x100)+(address%0x100)+recordtype+rchksum;
+
+          switch (recordtype)
+            {
+              case 0:
+                for (j=0; j<linesize; j++)
+                  {
+                    value = GetByte(&buffer[9]+(j*2));
+                    chksum += value;
+                    ihxBuff[address+j] = value;
+                  }
+                if (MaxAddress < (address+linesize-1))
+                  MaxAddress = (address+linesize-1);
+                if (address < *Begin)
+                  *Begin = address;
+                break;
+
+              case 4:
+                hi_addr = (GetWord(&buffer[9]) << 16) & 0x00FFFFFF; //upto 24 bit address space
+                break;
+
+              default:
+                break;
+            }
+
+          if ((chksum % 0x100) != 0)
+            {
+              printf("ERROR: Bad checksum in file %s\n", ihxFileName);
+              fclose(filein);
+              return -1;
+            }
+
+          if (recordtype==1)  /*End of record*/
+            break;
+        }
+    }
+  fclose(filein);
+
+  return MaxAddress;
+}
+
+void CreateAOMF51(void)
+{
+  if((yflag) && (!rflag))
+    {
+      CollectInfoFromCDB();
+#if DODUMP
+      DumpForDebug();
+#endif
+      HexSize=ReadHexFile(&HexBegin)+1;
+      OutputAOEMF51();
+      FreeAll();
+    }
+}
diff --git a/Kernel/tools/bankld/lkar.c b/Kernel/tools/bankld/lkar.c
new file mode 100644 (file)
index 0000000..c900303
--- /dev/null
@@ -0,0 +1,954 @@
+/* lkar.c - ar library format handling
+
+   Copyright (C) 1989-1995 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+   Copyright (C) 2008-2009 Borut Razem, borut dot razem at gmail dot com
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <assert.h>
+
+#include "aslink.h"
+#include "lklibr.h"
+#include "lkrel.h"
+#include "lkar.h"
+
+
+#ifndef max
+# define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef min
+# define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+static int
+is_ar (FILE * libfp)
+{
+  char buf[SARMAG];
+  int ret;
+
+  if (!(ret = fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, ARMAG, SARMAG) == 0))
+    rewind (libfp);
+
+  return ret;
+}
+
+static char *str_tab;     /* string table */
+static int str_tab_size;  /* string table size */
+
+static char *
+get_long_name (const char *name)
+{
+  assert ('/' == name[0]);
+
+  if (NULL != str_tab)
+    {
+      char *p;
+
+      int name_offset = strtol (++name, &p, 0);
+      if (p != name && name_offset < str_tab_size)
+        {
+          int len = p - name + 1;
+          while (len < AR_NAME_LEN && name[len++] == ' ')
+            ;
+          if (len == AR_NAME_LEN)
+            {
+              const char *n;
+
+              /* long name: get it from the symbol table */
+              name = &str_tab[name_offset];
+              for (n = name; *n != '/' && *n != '\n'; ++n)
+                assert (n < &str_tab[str_tab_size]);
+
+              if (n[0] != '/' || n[1] != '\n')
+                while (*++n != '\n')
+                  assert (n < &str_tab[str_tab_size]);
+
+              return strndup (name, n - name);
+            }
+        }
+    }
+  return NULL;
+}
+
+static char *
+get_member_name (char *name, size_t *p_size, int allocate, FILE * libfp)
+{
+  if (p_size != NULL)
+    *p_size = 0;
+
+  if (0 == memcmp (name, "#1/", 3))
+    {
+      char *p;
+      size_t len = strtoul (&name [3], &p, 10);
+      if (p > &name [3])
+        {
+          /* BSD appends real file name to the file header */
+          if (p_size != NULL)
+            *p_size = len;
+
+          if (allocate)
+            {
+              char *n = (char *) malloc (len);
+              if (fread (n, 1, len, libfp) != len)
+                {
+                  /* not an ar archive or broken ar archive */
+                  free (n);
+                  return NULL;
+                }
+              else
+                return n;
+            }
+          else
+            {
+              /* just advance the file pointer */
+              fseek (libfp, len, SEEK_CUR);
+              return NULL;
+            }
+        }
+      else
+        {
+          /* not an ar archive or broken ar archive */
+          return NULL;
+        }
+    }
+  else if (allocate)
+    {
+      if (name[0] == '/')
+        {
+          char *n = get_long_name (name);
+          if (NULL != n)
+            return n;
+        }
+      else
+        {
+          const char *p = strrchr (name + 1, '/');
+
+          if (NULL != p)
+            {
+              int len = p - name;
+              while (name[++len] == ' ')
+                ;
+              if (len == AR_NAME_LEN)
+                return strndup (name, p - name);
+            }
+          else
+            {
+              /* BSD formed member name:
+                 trim trailing spaces */
+              p = name + AR_NAME_LEN;
+              while (*--p == ' ' && p >= name)
+                ;
+              return strndup (name, p - name + 1);
+            }
+        }
+
+      /* bad formed member name or long name not found:
+       just return it */
+
+      return strdup (name);
+    }
+  else
+    return NULL;
+}
+
+static size_t
+ar_get_header (struct ar_hdr *hdr, FILE * libfp, char **p_obj_name)
+{
+  char header[ARHDR_LEN];
+  char buf[AR_DATE_LEN + 1];
+  char *obj_name;
+  size_t size;
+
+  if (fread (header, 1, sizeof (header), libfp) != sizeof (header)
+      || memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
+    {
+      /* not an ar archive */
+      return 0;
+    }
+
+  memcpy (hdr->ar_name, &header[AR_NAME_OFFSET], AR_NAME_LEN);
+  hdr->ar_name[AR_NAME_LEN] = '\0';
+
+  memcpy (buf, &header[AR_DATE_OFFSET], AR_DATE_LEN);
+  buf[AR_DATE_LEN] = '\0';
+  hdr->ar_date = strtol (buf, NULL, 0);
+
+  memcpy (buf, &header[AR_UID_OFFSET], AR_GID_LEN);
+  buf[AR_GID_LEN] = '\0';
+  hdr->ar_uid = (uid_t) strtol (buf, NULL, 0);
+
+  memcpy (buf, &header[AR_GID_OFFSET], AR_DATE_LEN);
+  buf[AR_DATE_LEN] = '\0';
+  hdr->ar_gid = (gid_t) strtol (buf, NULL, 0);
+
+  memcpy (buf, &header[AR_MODE_OFFSET], AR_MODE_LEN);
+  buf[AR_MODE_LEN] = '\0';
+  hdr->ar_mode = (mode_t) strtoul (buf, NULL, 0);
+
+  memcpy (buf, &header[AR_SIZE_OFFSET], AR_SIZE_LEN);
+  buf[AR_SIZE_LEN] = '\0';
+  hdr->ar_size = strtol (buf, NULL, 0);
+
+  obj_name = get_member_name (hdr->ar_name, &size, p_obj_name != NULL, libfp);
+
+  if (p_obj_name != NULL)
+    *p_obj_name = obj_name;
+
+  /* treat BSD appended real file name as a part of the header */
+  hdr->ar_size -= size;
+
+  return size + ARHDR_LEN;
+}
+
+#ifdef INDEXLIB
+static char *
+get_member_name_by_offset (FILE * fp, long offset)
+{
+  struct ar_hdr hdr;
+  char *name;
+
+  fseek (fp, offset, SEEK_SET);
+  return (ar_get_header (&hdr, fp, &name) != 0) ? name : NULL;
+}
+
+static pmlibraryfile
+find_member_by_offset (const char *libspc, long offset)
+{
+  pmlibraryfile p;
+
+  /* walk trough all archive members */
+  for (p = libr; p; p = p->next)
+    {
+      if (0 == strcmp (libspc, p->libspc) && p->offset == offset)
+        return p;
+    }
+
+  return NULL;
+}
+
+static pmlibraryfile
+buildlibraryindex_ar (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
+{
+  struct ar_hdr hdr;
+  char *obj_name;
+  size_t hdr_size;
+  int sym_found = 0;
+
+  /* walk trough all archive members */
+  while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
+    {
+      long pos = ftell (libfp);
+
+      if (AR_IS_SYMBOL_TABLE (obj_name))
+        {
+          char *buf, *po, *ps;
+          int i;
+          long nsym;
+
+          /* duplicated symbol table */
+          assert (!sym_found);
+
+          free (obj_name);
+
+          buf = (char *) new (hdr.ar_size);
+
+          if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
+            {
+              free (buf);
+              return This;
+            }
+
+          nsym = sgetl (buf);
+
+          po = buf + 4;
+          ps = po + nsym * 4;
+
+          for (i = 0; i < nsym; ++i)
+            {
+              pmlibrarysymbol ThisSym;
+              char *sym;
+              long offset;
+              pmlibraryfile entry;
+
+              offset = sgetl (po);
+              po += 4;
+
+              sym = strdup (ps);
+              ps += strlen (ps) + 1;
+
+              if ((entry = find_member_by_offset (lbnh->libspc, offset)) != NULL)
+                {
+                  for (ThisSym = entry->symbols; ThisSym->next != NULL; ThisSym = ThisSym->next)
+                    ;
+                }
+              else
+                {
+                  /* Opened OK - create a new libraryfile object for it */
+                  if (This == NULL)
+                    {
+                      assert (libr == NULL);
+                      libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+                    }
+                  else
+                    {
+                      This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+                      This = This->next;
+                    }
+                  This->next = NULL;
+                  This->loaded = 0;
+                  This->libspc = lbnh->libspc;
+                  This->offset = offset;
+                  This->relfil = get_member_name_by_offset (libfp, offset);     /* member name */
+                  This->filspc = strdup (This->relfil); /* member file name */
+                  This->type = type;
+
+                  /* start a new linked list of symbols for this module. */
+                  This->symbols = ThisSym = NULL;
+                }
+
+              if (ThisSym == NULL)
+                ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+              else
+                {
+                  ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+                  ThisSym = ThisSym->next;
+                }
+              ThisSym->next = NULL;
+              ThisSym->name = sym;
+            }
+          free (buf);
+
+          sym_found = 1;
+
+          /* string table already found: finish */
+          if (str_tab)
+            break;
+        }
+      else if (AR_IS_BSD_SYMBOL_TABLE (obj_name))
+        {
+          char *buf, *po, *ps;
+          int i;
+          long nsym, tablesize;
+
+          /* duplicated symbol table */
+          assert (!sym_found);
+
+          free (obj_name);
+
+          buf = (char *) new (hdr.ar_size);
+
+          if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
+            {
+              free (buf);
+              return This;
+            }
+
+          tablesize = sgetl (buf);
+          nsym = tablesize / 8;
+
+          po = buf + 4;
+
+          ps = po + tablesize + 4;
+
+          for (i = 0; i < nsym; ++i)
+            {
+              pmlibrarysymbol ThisSym;
+              char *sym;
+              long offset;
+              pmlibraryfile entry;
+
+              sym = ps + sgetl (po);
+              po += 4;
+              offset = sgetl (po);
+              po += 4;
+
+              sym = strdup (ps);
+
+              if ((entry = find_member_by_offset (lbnh->libspc, offset)) != NULL)
+                {
+                  for (ThisSym = entry->symbols; ThisSym->next != NULL; ThisSym = ThisSym->next)
+                    ;
+                }
+              else
+                {
+                  /* Opened OK - create a new libraryfile object for it */
+                  if (This == NULL)
+                    {
+                      assert (libr == NULL);
+                      libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+                    }
+                  else
+                    {
+                      This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+                      This = This->next;
+                    }
+                  This->next = NULL;
+                  This->loaded = 0;
+                  This->libspc = lbnh->libspc;
+                  This->offset = offset;
+                  This->relfil = get_member_name_by_offset (libfp, offset);     /* member name */
+                  This->filspc = strdup (This->relfil); /* member file name */
+                  This->type = type;
+
+                  /* start a new linked list of symbols for this module. */
+                  This->symbols = ThisSym = NULL;
+                }
+
+              if (ThisSym == NULL)
+                ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+              else
+                {
+                  ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+                  ThisSym = ThisSym->next;
+                }
+              ThisSym->next = NULL;
+              ThisSym->name = sym;
+            }
+          free (buf);
+
+          sym_found = 1;
+
+          /* string table already found: finish */
+          if (str_tab)
+            break;
+        }
+      else if (AR_IS_STRING_TABLE (obj_name))
+        {
+          free (obj_name);
+
+          /* duplicated string table */
+          assert (NULL == str_tab);
+
+          str_tab = (char *) new (hdr.ar_size);
+
+          if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
+            {
+              free (str_tab);
+              str_tab_size = 0;
+              return This;
+            }
+          str_tab_size = hdr.ar_size;
+
+          /* sybol table already found: finish */
+          if (sym_found)
+            break;
+        }
+      else
+        {
+          if (NULL == libr)
+            {
+              /* Opened OK - create a new libraryfile object for it */
+              if (This == NULL)
+                {
+                  assert (libr == NULL);
+                  libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+                }
+              else
+                {
+                  This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+                  This = This->next;
+                }
+              This->next = NULL;
+              This->loaded = -1;
+              This->libspc = lbnh->libspc;
+              This->offset = pos - hdr_size;
+
+              This->relfil = obj_name;              /* member name */
+              This->filspc = strdup (This->relfil); /* member file name */
+
+              D ("  Indexing module: %s\n", This->relfil);
+
+              This->type = type;
+
+              /* start a new linked list of symbols for this module. */
+              This->symbols = NULL;
+
+              add_rel_index (libfp, hdr.ar_size, This);
+            }
+        }
+      fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
+    }
+
+  if (NULL != str_tab)
+    {
+      /* has a symbol table: walk through modules and replace offsets with names */
+      pmlibraryfile lfp;
+
+      for (lfp = libr; lfp; lfp = lfp->next)
+        {
+          char *name = lfp->relfil;
+          if (name[0] == '/')
+            {
+              char *p = get_long_name (name);
+              if (NULL != p)
+                {
+                  free (lfp->relfil);
+                  lfp->relfil = p;
+                  free (lfp->filspc);
+                  lfp->filspc = strdup (p);
+                }
+            }
+        }
+
+
+      free (str_tab);
+      str_tab = NULL;
+      str_tab_size = 0;
+    }
+
+  return This;
+}
+
+#else
+
+#if 0
+static int
+load_adb (FILE * libfp, struct lbfile *lbfh)
+{
+  struct ar_hdr hdr;
+  char *adb_name;
+  char *obj_name;
+  size_t hdr_size;
+
+  /* check if it is a .rel file */
+  if (0 != stricmp (&lbfh->relfil[strlen (lbfh->relfil) - 4], ".rel"))
+    return 0;
+
+
+  adb_name = (char *) new (strlen (lbfh->relfil) + 1);
+  memcpy (adb_name, lbfh->relfil, strlen (lbfh->relfil) - 4);
+  memcpy (&adb_name[strlen (lbfh->relfil) - 4], ".adb", 5);
+
+  if (!is_ar (libfp))
+    {
+      fprintf (stderr, "?ASlink-Error-%s is not an archive\n", lbfh->libspc);
+      fclose (libfp);
+      lkexit (1);
+    }
+
+  /* walk trough all archive members */
+  while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
+    {
+      if (AR_IS_STRING_TABLE (obj_name))
+        {
+          free (obj_name);
+
+          if (str_tab)
+            free (str_tab);
+
+          str_tab = (char *) new (hdr.ar_size);
+
+          if ((off_t) fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
+            {
+              free (str_tab);
+              str_tab_size = 0;
+              return 0;
+            }
+          str_tab_size = hdr.ar_size;
+        }
+      if (AR_IS_SYMBOL_TABLE (obj_name) || 0 != stricmp (obj_name, adb_name))
+        {
+          free (obj_name);
+
+          /* skip the mamber */
+          fseek (libfp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
+        }
+      else
+        {
+          long left = hdr.ar_size;
+          char buf[4096];
+
+          free (obj_name);
+
+          while (left)
+            {
+              size_t n = min (left, sizeof buf);
+
+              if (fread (buf, 1, n, libfp) != n)
+                {
+                  assert (0);
+                }
+
+              fwrite (buf, 1, n, yfp);
+
+              left -= n;
+            }
+
+          if (hdr.ar_size & 1)
+            getc (libfp);
+
+          free (adb_name);
+          return 1;
+        }
+    }
+
+  free (adb_name);
+  return 0;
+}
+#endif
+
+static void
+load_str_tab (FILE * libfp)
+{
+  struct ar_hdr hdr;
+  char *obj_name;
+  size_t hdr_size;
+
+  /* walk trough all archive members */
+  while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
+    {
+      long pos = ftell (libfp);
+
+      if (AR_IS_STRING_TABLE (obj_name))
+        {
+          free (obj_name);
+
+          /* duplicated string table */
+          assert (NULL == str_tab);
+
+          str_tab = (char *) new (hdr.ar_size);
+
+          if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
+            {
+              free (str_tab);
+              str_tab_size = 0;
+              return;
+            }
+          str_tab_size = hdr.ar_size;
+          return;
+
+        }
+      fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
+    }
+}
+
+static int
+fndsym_ar (const char *name, struct lbname *lbnh, FILE * libfp, int type)
+{
+  struct ar_hdr hdr;
+  int ret = 0;
+  size_t hdr_size;
+  char *obj_name;
+  long pos;
+
+  pos = ftell (libfp);
+  load_str_tab (libfp);
+  fseek (libfp, pos, SEEK_SET);
+
+  /* walk trough all archive members */
+  while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
+    {
+      char filspc[PATH_MAX] = { 0 };
+
+      if (lbnh->path != NULL)
+        {
+          strcpy (filspc, lbnh->path);
+          if (*filspc != '\0' && (filspc[strlen (filspc) - 1] != '/') && (filspc[strlen (filspc) - 1] != LKDIRSEP))
+            {
+              strcat (filspc, LKDIRSEPSTR);
+            }
+        }
+
+      if (AR_IS_SYMBOL_TABLE (obj_name))
+        {
+          char *buf, *po, *ps;
+          int i;
+          long nsym;
+
+          free (obj_name);
+
+          buf = (char *) new (hdr.ar_size);
+
+          if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
+            {
+              free (buf);
+              return 0;
+            }
+
+          nsym = sgetl (buf);
+
+          po = buf + 4;
+          ps = po + nsym * 4;
+
+          for (i = 0; i < nsym; ++i)
+            {
+              char *sym;
+              long offset;
+
+              offset = sgetl (po);
+              po += 4;
+
+              sym = ps;
+              while (*ps++ != '\0')
+                ;
+
+              if (0 == strcmp (name, sym))
+                {
+                  fseek (libfp, offset, SEEK_SET);
+                  if (ar_get_header (&hdr, libfp, &obj_name))
+                    {
+                      sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
+
+                      /* If this module has been loaded already don't load it again. */
+                      if (!is_module_loaded (filspc))
+                        {
+                          struct lbfile *lbfh, *lbf;
+
+                          lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+                          lbfh->libspc = strdup (lbnh->libspc);
+                          lbfh->relfil = obj_name;
+                          lbfh->filspc = strdup (filspc);
+                          lbfh->offset = offset;
+                          lbfh->type = type;
+
+                          if (lbfhead == NULL)
+                            {
+                              lbfhead = lbfh;
+                            }
+                          else
+                            {
+                              for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
+                                ;
+
+                              lbf->next = lbfh;
+                            }
+
+                          D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
+                          load_rel (libfp, hdr.ar_size);
+                          ///* if cdb information required & .adb file present */
+                          //if (yflag && yfp)
+                          //  {
+                          //    if (load_adb(FILE *libfp, struct lbfile *lbfh))
+                          //      SaveLinkedFilePath (filspc);
+                          //  }
+                          ret = 1;
+                          break;
+                        }
+                    }
+                  else
+                    {
+                      fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh->libspc, name);
+                      fclose (libfp);
+                      lkexit (1);
+                    }
+                }
+            }
+          free (buf);
+
+          break;
+        }
+      else if (AR_IS_BSD_SYMBOL_TABLE (obj_name))
+        {
+          char *buf, *po, *ps;
+          int i;
+          long nsym, tablesize;
+
+          free (obj_name);
+
+          buf = (char *) new (hdr.ar_size);
+
+          if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
+            {
+              free (buf);
+              return 0;
+            }
+
+          tablesize = sgetl (buf);
+          nsym = tablesize / 8;
+
+          po = buf + 4;
+
+          ps = po + tablesize + 4;
+
+          for (i = 0; i < nsym; ++i)
+            {
+              char *sym;
+              long offset;
+
+              sym = ps + sgetl (po);
+              po += 4;
+              offset = sgetl (po);
+              po += 4;
+
+              if (0 == strcmp (name, sym))
+                {
+                  fseek (libfp, offset, SEEK_SET);
+                  if (ar_get_header (&hdr, libfp, &obj_name))
+                    {
+                      sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
+
+                      /* If this module has been loaded already don't load it again. */
+                      if (!is_module_loaded (filspc))
+                        {
+                          struct lbfile *lbfh, *lbf;
+
+                          lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+                          lbfh->libspc = strdup (lbnh->libspc);
+                          lbfh->relfil = obj_name;
+                          lbfh->filspc = strdup (filspc);
+                          lbfh->offset = offset;
+                          lbfh->type = type;
+
+                          if (lbfhead == NULL)
+                            {
+                              lbfhead = lbfh;
+                            }
+                          else
+                            {
+                              for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
+                                ;
+
+                              lbf->next = lbfh;
+                            }
+
+                          D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
+                          load_rel (libfp, hdr.ar_size);
+                          ///* if cdb information required & .adb file present */
+                          //if (yflag && yfp)
+                          //  {
+                          //    if (load_adb(FILE *libfp, struct lbfile *lbfh))
+                          //      SaveLinkedFilePath (filspc);
+                          //  }
+                          ret = 1;
+                          break;
+                        }
+                    }
+                  else
+                    {
+                      fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh->libspc, name);
+                      fclose (libfp);
+                      lkexit (1);
+                    }
+                }
+            }
+          free (buf);
+
+          break;
+        }
+      else if (AR_IS_STRING_TABLE (obj_name))
+        {
+          free (obj_name);
+
+          if (str_tab)
+            free (str_tab);
+
+          str_tab = (char *) new (hdr.ar_size);
+
+          if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
+            {
+              free (str_tab);
+              str_tab = NULL;
+              str_tab_size = 0;
+              return 0;
+            }
+          str_tab_size = hdr.ar_size;
+        }
+      else
+        {
+          long pos = ftell (libfp);
+
+          free (obj_name);
+
+          D ("  Module: %s\n", hdr.ar_name);
+
+          sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
+
+          /* Opened OK - create a new libraryfile object for it */
+          ret = add_rel_file (name, lbnh, hdr.ar_name, filspc, pos - hdr_size, libfp, hdr.ar_size, type);
+          ///* if cdb information required & .adb file present */
+          //if (yflag && yfp)
+          //  {
+          //    if (load_adb(FILE *libfp, struct lbfile *lbfh))
+          //      SaveLinkedFilePath (filspc);
+          //  }
+          if (ret)
+            break;
+
+          fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
+        }
+    }
+
+  if (NULL != str_tab)
+    {
+      free (str_tab);
+      str_tab = NULL;
+      str_tab_size = 0;
+    }
+
+  return ret;
+}
+#endif
+
+static void
+loadfile_ar (struct lbfile *lbfh)
+{
+  FILE *fp;
+
+#ifdef __CYGWIN__
+  char posix_path[PATH_MAX];
+  void cygwin_conv_to_full_posix_path (char *win_path, char *posix_path);
+  cygwin_conv_to_full_posix_path (lbfh->libspc, posix_path);
+  fp = fopen (posix_path, "rb");
+#else
+  fp = fopen (lbfh->libspc, "rb");
+#endif
+
+  if (fp != NULL)
+    {
+      struct ar_hdr hdr;
+
+      fseek (fp, lbfh->offset, SEEK_SET);
+      if (ar_get_header (&hdr, fp, NULL) != 0)
+        {
+          D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
+          load_rel (fp, hdr.ar_size);
+          fclose (fp);
+        }
+      else
+        {
+          fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, lbfh->relfil);
+          fclose (fp);
+          lkexit (1);
+        }
+    }
+  else
+    {
+      fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->libspc);
+      lkexit (1);
+    }
+}
+
+struct aslib_target aslib_target_ar = {
+  &is_ar,
+#ifdef INDEXLIB
+  &buildlibraryindex_ar,
+#else
+  &fndsym_ar,
+#endif
+  &loadfile_ar,
+};
diff --git a/Kernel/tools/bankld/lkar.h b/Kernel/tools/bankld/lkar.h
new file mode 100644 (file)
index 0000000..717ed78
--- /dev/null
@@ -0,0 +1,89 @@
+/* lkar.h - ar library format handling
+
+   Copyright (C) 2008-2012 Borut Razem, borut dot razem at siol dot net
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+#ifndef __LKAR_H
+#define __LKAR_H
+
+#include <sys/types.h>
+#include <string.h>
+
+
+#ifdef _WIN32
+typedef unsigned short mode_t;
+typedef short uid_t;
+typedef short gid_t;
+typedef _off_t off_t;
+#endif
+
+#define sgetl(buf)  (((((((unsigned char)(buf)[0] << 8) + (unsigned char)(buf)[1]) << 8) + (unsigned char)(buf)[2]) << 8) + (unsigned char)(buf)[3])
+#define sputl(value, buf)  ((buf)[0] = (value) >> 24, (buf)[1] = (value) >> 16, (buf)[2] = (value) >> 8, (buf)[3] = (value))
+
+/* Note that the usual '\n' in magic strings may translate to different
+   characters, as allowed by ANSI.  '\012' has a fixed value, and remains
+   compatible with existing BSDish archives. */
+
+#define ARMAG   "!<arch>\012"         /* magic string */
+#define SARMAG  (sizeof (ARMAG) - 1)  /* length of magic string */
+
+#define ARFMAG  "`\012"               /* header trailer string */
+
+#define AR_NAME_OFFSET  0
+#define AR_NAME_LEN     16
+
+#define AR_DATE_OFFSET  16
+#define AR_DATE_LEN     12
+
+#define AR_UID_OFFSET   28
+#define AR_UID_LEN      6
+
+#define AR_GID_OFFSET   34
+#define AR_GID_LEN      6
+
+#define AR_MODE_OFFSET  40
+#define AR_MODE_LEN     8
+
+#define AR_SIZE_OFFSET  48
+#define AR_SIZE_LEN     10
+
+#define AR_FMAG_OFFSET  58
+#define AR_FMAG_LEN     (sizeof (ARFMAG) - 1)
+
+#define ARHDR_LEN (AR_NAME_LEN + AR_DATE_LEN + AR_UID_LEN + AR_GID_LEN + AR_MODE_LEN + AR_SIZE_LEN + AR_FMAG_LEN)
+
+#define AR_SYMBOL_TABLE_NAME            "/               "
+#define AR_STRING_TABLE_NAME            "//              "
+
+#define AR_BSD_SYMBOL_TABLE_NAME        "__.SYMDEF       "
+#define AR_BSD_SORTED_SYMBOL_TABLE_NAME "__.SYMDEF SORTED"
+
+#define AR_IS_SYMBOL_TABLE(name) (0 == strcmp((name), AR_SYMBOL_TABLE_NAME))
+#define AR_IS_STRING_TABLE(name) (0 == strcmp((name), AR_STRING_TABLE_NAME))
+
+#define AR_IS_BSD_SYMBOL_TABLE(name) (0 == strcmp((name), AR_BSD_SYMBOL_TABLE_NAME) || 0 == strcmp((name), AR_BSD_SORTED_SYMBOL_TABLE_NAME))
+
+
+struct ar_hdr                     /* archive member header */
+{
+  char ar_name[AR_NAME_LEN + 1];  /* archive member name */
+  time_t ar_date;                 /* archive member date */
+  uid_t ar_uid;                   /* archive member user identification */
+  gid_t ar_gid;                   /* archive member group identification */
+  mode_t ar_mode;                 /* archive member mode (octal) */
+  size_t ar_size;                 /* archive member size */
+};
+
+#endif /* __LKAR_H */
diff --git a/Kernel/tools/bankld/lkarea.c b/Kernel/tools/bankld/lkarea.c
new file mode 100644 (file)
index 0000000..314f13d
--- /dev/null
@@ -0,0 +1,1299 @@
+/* lkarea.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ */
+
+/*
+ * 02-Apr-98 JLH: add code to link 8051 data spaces
+ */
+
+#include "aslink.h"
+
+/*)Module       lkarea.c
+ *
+ *      The module lkarea.c contains the functions which
+ *      create and link together all area definitions read
+ *      from the .rel file(s).
+ *
+ *      lkarea.c contains the following functions:
+ *              VOID    lnkarea()
+ *              VOID    lnksect()
+ *              VOID    lkparea()
+ *              VOID    newarea()
+ *              VOID    setarea()
+ *
+ *      lkarea.c contains no global variables.
+ */
+
+/*)Function VOID        newarea()
+ *
+ *      The function newarea() creates and/or modifies area
+ *      and areax structures for each A directive read from
+ *      the .rel file(s).  The function lkparea() is called
+ *      to find the area structure associated with this name.
+ *      If the area does not yet exist then a new area
+ *      structure is created and linked to any existing
+ *      linked area structures. The area flags are copied
+ *      into the area flag variable.  For each occurence of
+ *      an A directive an areax structure is created and
+ *      linked to the areax structures associated with this
+ *      area.  The size of this area section is placed into
+ *      the areax structure.  The flag value for all subsequent
+ *      area definitions for the same area are compared and
+ *      flagged as an error if they are not identical.
+ *      The areax structure created for every occurence of
+ *      an A directive is loaded with a pointer to the base
+ *      area structure and a pointer to the associated
+ *      head structure.  And finally, a pointer to this
+ *      areax structure is loaded into the list of areax
+ *      structures in the head structure.  Refer to lkdata.c
+ *      for details of the structures and their linkage.
+ *
+ *      local variables:
+ *              areax **halp            pointer to an array of pointers
+ *              a_uint  i               value
+ *              char    id[]            id string
+ *              int     k               counter, loop variable
+ *              int     narea           number of areas in this head structure
+ *              areax * taxp            pointer to an areax structure
+ *                                      to areax structures
+ *
+ *      global variables:
+ *              area    *ap             Pointer to the current
+ *                                      area structure
+ *              areax   *axp            Pointer to the current
+ *                                      areax structure
+ *              head    *hp             Pointer to the current
+ *                                      head structure
+ *              int     lkerr           error flag
+ *
+ *      functions called:
+ *              a_uint  eval()          lkeval.c
+ *              VOID    exit()          c_library
+ *              int     fprintf()       c_library
+ *              VOID    getid()         lklex.c
+ *              VOID    lkparea()       lkarea.c
+ *              VOID    skip()          lklex.c
+ *
+ *      side effects:
+ *              The area and areax structures are created and
+ *              linked with the appropriate head structures.
+ *              Failure to allocate area or areax structure
+ *              space will terminate the linker.  Other internal
+ *              errors most likely caused by corrupted .rel
+ *              files will also terminate the linker.
+ */
+
+/*
+ * Create an area entry.
+ *
+ * A xxxxxx size nnnn flags mm bank n
+ *   |           |          |       |
+ *   |           |          |       `--  ap->a_bank
+ *   |           |          `----------  ap->a_flag
+ *   |           `--------------------- axp->a_size
+ *   `---------------------------------  ap->a_id
+ *
+ */
+VOID
+newarea(void)
+{
+        a_uint i;
+        int k, narea;
+        struct areax *taxp;
+        struct areax **halp;
+        char id[NCPS];
+
+        if (headp == NULL) {
+                fprintf(stderr, "No header defined\n");
+                lkexit(ER_FATAL);
+        }
+        /*
+         * Create Area entry
+         */
+        getid(id, -1);
+        lkparea(id);
+        /*
+         * Evaluate area size
+         */
+        skip(-1);
+        axp->a_size = eval();
+        /*
+         * Evaluate flags
+         */
+        skip(-1);
+        i = 0;
+        taxp = ap->a_axp;
+        while (taxp->a_axp) {
+                ++i;
+                taxp = taxp->a_axp;
+        }
+        if (i == 0) {
+                ap->a_flag = eval();
+        } else {
+                i = eval();
+                if ((!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB) &&
+                        i && (ap->a_flag != i)) {
+                        fprintf(stderr, "Conflicting flags in area %8s\n", id);
+                        lkerr++;
+                }
+        }
+        if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)) {
+                /*
+                 * Evaluate area address
+                 */
+                skip(-1);
+                axp->a_addr = eval();
+        }
+        /*
+         * Place pointer in header area list
+         */
+        narea = hp->h_narea;
+        halp = hp->a_list;
+        for (k=0; k < narea ;++k) {
+                if (halp[k] == NULL) {
+                        halp[k] = taxp;
+                        return;
+                }
+        }
+        fprintf(stderr, "Header area list overflow\n");
+        lkexit(ER_FATAL);
+}
+
+/*)Function     VOID    lkparea(id)
+ *
+ *              char *  id              pointer to the area name string
+ *
+ *      The function lkparea() searches the linked area structures
+ *      for a name match.  If the name is not found then an area
+ *      structure is created.  An areax structure is created and
+ *      appended to the areax structures linked to the area structure.
+ *      The associated base area and head structure pointers are
+ *      loaded into the areax structure.
+ *
+ *      local variables:
+ *              area *  tap             pointer to an area structure
+ *              areax * taxp            pointer to an areax structure
+ *
+ *      global variables:
+ *              area    *ap             Pointer to the current
+ *                                      area structure
+ *              area    *areap          The pointer to the first
+ *                                      area structure of a linked list
+ *              areax   *axp            Pointer to the current
+ *                                      areax structure
+ *
+ *      functions called:
+ *              VOID *  new()           lksym()
+ *              char *  strsto()        lksym.c
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              Area and/or areax structures are created.
+ *              Failure to allocate space for created structures
+ *              will terminate the linker.
+ */
+
+VOID
+lkparea(char *id)
+{
+        struct area *tap;
+        struct areax *taxp;
+
+        ap = areap;
+        axp = (struct areax *) new (sizeof(struct areax));
+        if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB))
+                axp->a_addr = -1; /* default: no address yet */
+        while (ap) {
+                if (symeq(id, ap->a_id, 1)) {
+                        taxp = ap->a_axp;
+                        while (taxp->a_axp)
+                                taxp = taxp->a_axp;
+                        taxp->a_axp = axp;
+                        axp->a_bap = ap;
+                        axp->a_bhp = hp;
+                        return;
+                }
+                ap = ap->a_ap;
+        }
+        ap = (struct area *) new (sizeof(struct area));
+        if (areap == NULL) {
+                areap = ap;
+        } else {
+                tap = areap;
+                while (tap->a_ap)
+                        tap = tap->a_ap;
+                tap->a_ap = ap;
+        }
+        ap->a_axp = axp;
+        axp->a_bap = ap;
+        axp->a_bhp = hp;
+        ap->a_id = strsto(id);
+        if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB))
+                ap->a_addr = 0;
+}
+
+/*)Function     VOID    lnkarea()
+ *
+ *      The function lnkarea() resolves all area addresses.
+ *      The function evaluates each area structure (and all
+ *      the associated areax structures) in sequence.  The
+ *      linking process supports four (4) possible area types:
+ *
+ *      ABS/OVR -       All sections (each individual areax
+ *                      section) starts at the identical base
+ *                      area address overlaying all other
+ *                      areax sections for this area.  The
+ *                      size of the area is largest of the area
+ *                      sections.
+ *
+ *      ABS/CON -       All sections (each individual areax
+ *                      section) are concatenated with the
+ *                      first section starting at the base
+ *                      area address.  The size of the area
+ *                      is the sum of the section sizes.
+ *
+ *      NOTE:           Multiple absolute (ABS) areas are
+ *                      never concatenated with each other,
+ *                      thus absolute area A and absolute area
+ *                      B will overlay each other if they begin
+ *                      at the same location (the default is
+ *                      always address 0 for absolute areas).
+ *
+ *      REL/OVR -       All sections (each individual areax
+ *                      section) starts at the identical base
+ *                      area address overlaying all other
+ *                      areax sections for this area.  The
+ *                      size of the area is largest of the area
+ *                      sections.
+ *
+ *      REL/CON -       All sections (each individual areax
+ *                      section) are concatenated with the
+ *                      first section starting at the base
+ *                      area address.  The size of the area
+ *                      is the sum of the section sizes.
+ *
+ *              NOTE:   Relocatable (REL) areas are always concatenated
+ *                      with each other, thus relocatable area B
+ *                      (defined after area A) will follow
+ *                      relocatable area A independent of the
+ *                      starting address of area A.  Within a
+ *                      specific area each areax section may be
+ *                      overlayed or concatenated with other
+ *                      areax sections.
+ *
+ *
+ *      If a base address for an area is specified then the
+ *      area will start at that address.  Any relocatable
+ *      areas defined subsequently will be concatenated to the
+ *      previous relocatable area if it does not have a base
+ *      address specified.
+ *
+ *      The names s_<areaname> and l_<areaname> are created to
+ *      define the starting address and length of each area.
+ *
+ *      local variables:
+ *              a_uint  rloc            ;current relocation address
+ *              char    temp[]          ;temporary string
+ *              struct symbol   *sp     ;symbol structure
+ *
+ *      global variables:
+ *              area    *ap             Pointer to the current
+ *                                      area structure
+ *              area    *areap          The pointer to the first
+ *                                      area structure of a linked list
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    lnksect()       lkarea.c
+ *              symbol *lkpsym()        lksysm.c
+ *              char *  strncpy()       c_library
+ *              int     symeq()         lksysm.c
+ *
+ *      side effects:
+ *              All area and areax addresses and sizes are
+ *              determined and saved in their respective
+ *              structures.
+ */
+
+/* sdld6808 specific */
+unsigned long codemap6808[2048];
+/* end sdld6808 specific */
+/* sdld specific */
+VOID lnksect(struct area *tap);
+/* end sdld specific */
+/*
+ * Resolve all bank/area addresses.
+ */
+VOID
+lnkarea(void)
+{
+        /* sdld specific */
+        a_uint rloc[4] = { 0, 0, 0, 0 };
+        int  locIndex;
+        /* end sdld specific */
+        /* sdld8051 & sdld6808 specific */
+        /*JCF: used to save the REG_BANK_[0-3] and SBIT_BYTES area pointers*/
+        struct area *ta[5];
+        int j;
+        /* end sdld8051 & sdld6808 specific */
+        /* sdld6800 specific */
+        a_uint gs_size = 0;
+        struct area *abs_ap = NULL;
+        struct area *gs0_ap = NULL;
+        /* end sdld6800 specific */
+        char temp[NCPS+2];
+        struct sym *sp;
+
+        if (TARGET_IS_6808) {
+                memset(codemap6808, 0, sizeof(codemap6808));
+
+                /* first sort all absolute areas to the front */
+                ap = areap;
+                /* no need to check first area, it's in front anyway */
+                while (ap && ap->a_ap) {
+                        if (ap->a_ap->a_flag & A3_ABS)
+                        {/* next area is absolute, move it to front,
+                                reversed sequence is no problem for absolutes */
+                                abs_ap = ap->a_ap;
+                                ap->a_ap = abs_ap->a_ap;
+                                abs_ap->a_ap = areap;
+                                areap = abs_ap;
+                        }
+                        else {
+                                ap = ap->a_ap;
+                        }
+                }
+
+                /* next accumulate all GSINITx/GSFINAL area sizes
+                   into GSINIT so they stay together */
+                ap = areap;
+                while (ap) {
+                        if (!strncmp(ap->a_id, "GS", 2))
+                        {/* GSxxxxx area */
+                                if (ap->a_size == 0)
+                                {
+                                        axp = ap->a_axp;
+                                        while (axp)
+                                        {
+                                                ap->a_size += axp->a_size;
+                                                axp = axp->a_axp;
+                                        }
+                                }
+                                gs_size += ap->a_size;
+                                if (!strcmp(ap->a_id, "GSINIT0"))
+                                {/* GSINIT0 area */
+                                        gs0_ap = ap;
+                                }
+                        }
+                        ap = ap->a_ap;
+                }
+                if (gs0_ap)
+                        gs0_ap->a_size = gs_size;
+        }
+
+        ap = areap;
+        while (ap) {
+                if (ap->a_flag & A3_ABS) {
+                        /*
+                         * Absolute sections
+                         */
+                        lnksect(ap);
+                } else {
+                        /* sdld specific */
+                        /* Determine memory space */
+                        locIndex = 0;
+                        if ((TARGET_IS_8051)) {
+                                if (ap->a_flag & A_CODE) {
+                                        locIndex = 1;
+                                }
+                                if (ap->a_flag & A_XDATA) {
+                                        locIndex = 2;
+                                }
+                                if (ap->a_flag & A_BIT) {
+                                        locIndex = 3;
+                                }
+                        }
+                        /*
+                         * Relocatable sections
+                         */
+                        if (!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB) {
+                                if (ap->a_addr == 0)
+                                        ap->a_addr = rloc[locIndex];
+                        }
+                        else if (ap->a_bset == 0) {
+                                if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD) {
+                                        locIndex = 2;
+                                        ap->a_addr = 0;
+                                }
+                                else {
+                                        ap->a_addr = rloc[locIndex];
+                                }
+                                ap->a_bset = 1;
+                        }
+                        lnksect(ap);
+                        rloc[ locIndex ] = ap->a_addr + ap->a_size;
+                        /* end sdld specific */
+                }
+
+                /*
+                 * Create symbols called:
+                 *      s_<areaname>    the start address of the area
+                 *      l_<areaname>    the length of the area
+                 */
+
+                if (! symeq(ap->a_id, _abs_, 1)) {
+                        strcpy(temp+2, ap->a_id);
+                        *(temp+1) = '_';
+
+                        *temp = 's';
+                        sp = lkpsym(temp, 1);
+                        sp->s_addr = ap->a_addr;
+                        if (!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)
+                                sp->s_axp = NULL;
+                        sp->s_type |= S_DEF;
+
+                        *temp = 'l';
+                        sp = lkpsym(temp, 1);
+                        sp->s_addr = ap->a_size;
+                        sp->s_axp = NULL;
+                        sp->s_type |= S_DEF;
+                }
+
+                if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)) {
+                        /*JCF: Since area BSEG is defined just before BSEG_BYTES, use the bit size of BSEG
+                        to compute the byte size of BSEG_BYTES: */
+                        if (!strcmp(ap->a_id, "BSEG")) {
+                                if (TARGET_IS_8051)
+                                        ap->a_ap->a_axp->a_size += ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/
+                                else
+                                        ap->a_ap->a_axp->a_size=(ap->a_addr/8)+((ap->a_size+7)/8); /*Bits to bytes*/
+                        }
+                        else if (!strcmp(ap->a_id, "REG_BANK_0")) ta[0]=ap;
+                        else if (!strcmp(ap->a_id, "REG_BANK_1")) ta[1]=ap;
+                        else if (!strcmp(ap->a_id, "REG_BANK_2")) ta[2]=ap;
+                        else if (!strcmp(ap->a_id, "REG_BANK_3")) ta[3]=ap;
+                        else if (!strcmp(ap->a_id, "BSEG_BYTES"))
+                        {
+                                ta[4]=ap;
+                                for(j=4; j>1; j--)
+                                {
+                                        /*If upper register banks are not used roll back the relocation counter*/
+                                        if ( (ta[j]->a_size==0) && (ta[j-1]->a_size==0) )
+                                        {
+                                                rloc[0]-=8;
+                                        }
+                                        else break;
+                                }
+                        }
+                }
+                ap = ap->a_ap;
+        }
+}
+
+/* sdld specific */
+static
+a_uint find_empty_space(a_uint start, a_uint size, char *id, unsigned long *map, unsigned int map_size)
+{
+        a_uint i, j, k;
+        unsigned long mask, b;
+        map_size /= sizeof(*map); /* Convert from bytes to number of elements */
+
+        while (1) {
+                a_uint a = start;
+                i = start >> 5;
+                j = (start + size) >> 5;
+                mask = -(1 << (start & 0x1F));
+
+                if (j > map_size) {
+                        fprintf(stderr, "internal memory limit is exceeded for %s; memory size = 0x%06X, address = 0x%06X\n", id, map_size << 5, start + size - 1);
+                        break;
+                }
+                else {
+                        while (i < j) {
+                                if (map[i] & mask) {
+                                        k = 32;
+                                        for (b=0x80000000; b!=0; b>>=1, k--) {
+                                                if (map[i] & b)
+                                                        break;
+                                        }
+                                        start = a + k;
+                                        break;
+                                }
+                                i++;
+                                mask = 0xFFFFFFFF;
+                                a += 32;
+                        }
+                        if (start > a)
+                                continue;
+
+                        mask &= (1 << ((start + size) & 0x1F)) - 1;
+                        if (i < map_size && map[i] & mask) {
+                                k = 32;
+                                for (b=0x80000000; b!=0; b>>=1, k--) {
+                                        if (map[i] & b)
+                                                break;
+                                }
+                                start = (a & ~0x1F) + k;
+                        }
+                        if (start <= a)
+                                break;
+                }
+        }
+        return start;
+}
+
+static
+a_uint allocate_space(a_uint start, a_uint size, char *id, unsigned long *map,  unsigned int map_size)
+{
+        a_uint i, j;
+        unsigned long mask;
+        a_uint a = start;
+        i = start >> 5;
+        j = (start + size) >> 5;
+        mask = -(1 << (start & 0x1F));
+        map_size /= sizeof(*map); /* Convert from bytes to number of elements */
+
+        if (j > map_size) {
+                fprintf(stderr, "internal memory limit is exceeded for %s; memory size = 0x%06X, address = 0x%06X\n", id, map_size << 5, start + size - 1);
+        }
+        else {
+                while (i < j) {
+                        if (map[i] & mask) {
+                                fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
+                        }
+                        map[i++] |= mask;
+                        mask = 0xFFFFFFFF;
+                        a += 32;
+                }
+                mask &= (1 << ((start + size) & 0x1F)) - 1;
+                if (i < map_size && map[i] & mask) {
+                        fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
+                }
+                map[i] |= mask;
+        }
+        return start;
+}
+/* end sdld specific */
+
+/*)Function VOID        lnksect(tap)
+ *
+ *              area *  tap                     pointer to an area structure
+ *
+ *      The function lnksect() is the function called by
+ *      lnkarea() to resolve the areax addresses.  Refer
+ *      to the function lnkarea() for more detail. Pageing
+ *      boundary and length errors will be reported by this
+ *      function.
+ *
+ *      local variables:
+ *              a_uint  size            size of area
+ *              a_uint  addr            address of area
+ *              areax * taxp            pointer to an areax structure
+ *
+ *      global variables:
+ *              int             lkerr           error flag
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              All area and areax addresses and sizes are determined
+ *              and linked into the structures.
+ */
+
+VOID
+lnksect(struct area *tap)
+{
+        a_uint size, addr;
+        struct areax *taxp;
+
+        size = 0;
+        addr = tap->a_addr;
+        taxp = tap->a_axp;
+        if (tap->a_flag & A3_OVR) {
+                /*
+                 * Overlayed sections
+                 */
+                while (taxp) {
+                        taxp->a_addr = addr;
+                        if (taxp->a_size > size)
+                                size = taxp->a_size;
+                        taxp = taxp->a_axp;
+                }
+        } else if (TARGET_IS_6808 && tap->a_flag & A3_ABS) {
+                /*
+                 * Absolute sections
+                 */
+                while (taxp) {
+                        allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808));
+                        taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */
+                        size += taxp->a_size;
+                        taxp = taxp->a_axp;
+                }
+        } else {
+                /*
+                 * Concatenated sections
+                 */
+                if (TARGET_IS_6808 && tap->a_size && !(ap->a_flag & A_NOLOAD)) {
+                        addr = find_empty_space(addr, tap->a_size, tap->a_id, codemap6808, sizeof (codemap6808));
+                }
+                while (taxp) {
+                        /* find next unused address now */
+                        if (TARGET_IS_6808 && taxp->a_size && !(ap->a_flag & A_NOLOAD)) {
+                                addr = find_empty_space(addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808));
+                                allocate_space(addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808));
+                        }
+                        taxp->a_addr = addr;
+                        addr += taxp->a_size;
+                        size += taxp->a_size;
+                        taxp = taxp->a_axp;
+                }
+        }
+        tap->a_size = size;
+        tap->a_addr = tap->a_axp->a_addr;
+        for (taxp = tap->a_axp; taxp && !taxp->a_size; taxp = taxp->a_axp)
+        {
+        }
+        if (taxp)
+        {
+                tap->a_addr = taxp->a_addr;
+        }
+
+        if ((tap->a_flag & A3_PAG) && (size > 256)) {
+                fprintf(stderr,
+                        "\n?ASlink-Warning-Paged Area %s Length Error\n",
+                        tap->a_id);
+                lkerr++;
+        }
+        if (TARGET_IS_8051 &&
+                (tap->a_flag & A3_PAG) && (tap->a_size) &&
+                ((tap->a_addr & 0xFFFFFF00) != ((addr-1) & 0xFFFFFF00)))
+        {
+                fprintf(stderr,
+                        "\n?ASlink-Warning-Paged Area %s Boundary Error\n",
+                        tap->a_id);
+                lkerr++;
+        }
+}
+
+
+/*)Function     VOID    setarea()
+ *
+ *      The function setarea() scans the base address lines in the
+ *      basep structure, evaluates the arguments, and sets the beginning
+ *      address of the specified areas.
+ *
+ *      local variables:
+ *              a_uint  v               expression value
+ *              char    id[]            base id string
+ *
+ *      global variables:
+ *              area    *ap             Pointer to the current
+ *                                      area structure
+ *              area    *areap          The pointer to the first
+ *                                      area structure of a linked list
+ *              base    *basep          The pointer to the first
+ *                                      base structure
+ *              base    *bsp            Pointer to the current
+ *                                      base structure
+ *              char    *ip             pointer into the REL file
+ *                                      text line in ib[]
+ *              int     lkerr           error flag
+ *
+ *       functions called:
+ *              a_uint  expr()          lkeval.c
+ *              int     fprintf()       c_library
+ *              VOID    getid()         lklex.c
+ *              int     getnb()         lklex.c
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              The base address of an area is set.
+ */
+
+VOID
+setarea(void)
+{
+        a_uint v;
+        char id[NCPS];
+
+        bsp = basep;
+        while (bsp) {
+                ip = bsp->b_strp;
+                getid(id, -1);
+                if (getnb() == '=') {
+                        v = expr(0);
+                        for (ap = areap; ap != NULL; ap = ap->a_ap) {
+                                if (symeq(id, ap->a_id, 1))
+                                        break;
+                        }
+                        if (ap == NULL) {
+                                fprintf(stderr,
+                                "ASlink-Warning-No definition of area %s\n", id);
+                                lkerr++;
+                        } else {
+                                ap->a_addr = v;
+                                ap->a_bset = 1;
+                        }
+                } else {
+                        fprintf(stderr, "ASlink-Warning-No '=' in base expression");
+                        lkerr++;
+                }
+                bsp = bsp->b_base;
+        }
+}
+
+
+
+/* sdld specific */
+a_uint lnksect2 (struct area *tap, int locIndex);
+unsigned long codemap8051[524288];
+unsigned long xdatamap[131216];
+struct area *dseg_ap = NULL;
+a_uint dram_start = 0;
+a_uint iram_start = 0;
+
+/*Modified version of the functions for packing variables in internal data memory*/
+VOID lnkarea2 (void)
+{
+        a_uint rloc[4]={0, 0, 0, 0};
+        a_uint gs_size = 0;
+        int  locIndex;
+        char temp[NCPS+2];
+        struct sym *sp;
+        int j;
+        struct area *bseg_ap = NULL;
+        struct area *abs_ap = NULL;
+        struct area *gs0_ap = NULL;
+        struct sym *sp_dseg_s=NULL, *sp_dseg_l=NULL;
+
+        memset(idatamap, ' ', 256);
+        memset(codemap8051, 0, sizeof(codemap8051));
+        memset(xdatamap, 0, sizeof(xdatamap));
+
+        /* first sort all absolute areas to the front */
+        ap = areap;
+        /* no need to check first area, it's in front anyway */
+        while (ap && ap->a_ap)
+        {
+                if (ap->a_ap->a_flag & A3_ABS)
+                {/* next area is absolute, move it to front,
+                        reversed sequence is no problem for absolutes */
+                        abs_ap = ap->a_ap;
+                        ap->a_ap = abs_ap->a_ap;
+                        abs_ap->a_ap = areap;
+                        areap = abs_ap;
+                }
+                else
+                {
+                        ap = ap->a_ap;
+                }
+        }
+
+        /* next accumulate all GSINITx/GSFINAL area sizes
+           into GSINIT so they stay together */
+        ap = areap;
+        abs_ap = areap;
+        while (ap)
+        {
+                if (ap->a_flag & A3_ABS)
+                {
+                        abs_ap = ap; /* Remember the last abs area */
+                }
+                if (!strncmp(ap->a_id, "GS", 2))
+                {/* GSxxxxx area */
+                        if (ap->a_size == 0)
+                        {
+                                axp = ap->a_axp;
+                                while (axp)
+                                {
+                                        ap->a_size += axp->a_size;
+                                        axp = axp->a_axp;
+                                }
+                        }
+                        gs_size += ap->a_size;
+                        if (!strcmp(ap->a_id, "GSINIT0"))
+                        {/* GSINIT0 area */
+                                gs0_ap = ap;
+                        }
+                }
+                /*Since area BSEG is defined just before BSEG_BYTES, use the bit size of BSEG
+                to compute the byte size of BSEG_BYTES: */
+                else if (!strcmp(ap->a_id, "BSEG"))
+                {
+                        bseg_ap = ap->a_ap;                        //BSEG_BYTES
+                        for (axp=ap->a_axp; axp; axp=axp->a_axp)
+                                ap->a_size += axp->a_size;
+                        bseg_ap->a_axp->a_size = ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/
+                        ap->a_ap = bseg_ap->a_ap;                  //removed BSEG_BYTES from list
+                        bseg_ap->a_ap = abs_ap->a_ap;
+                        abs_ap->a_ap = bseg_ap;                    //inserted BSEG_BYTES after abs
+                        bseg_ap = ap;                              //BSEG
+                }
+                else if (!strcmp(ap->a_id, "DSEG"))
+                {
+                        dseg_ap = ap; /*Need it later*/
+                        dram_start = ap->a_addr;
+                }
+                else if (!strcmp(ap->a_id, "ISEG"))
+                {
+                        iram_start = ap->a_addr;
+                }
+                ap = ap->a_ap;
+        }
+        if (gs0_ap)
+                gs0_ap->a_size = gs_size;
+
+        ap = areap;
+        while (ap)
+        {
+                /* Determine memory space */
+                     if (ap->a_flag & A_CODE)  locIndex = 1;
+                else if (ap->a_flag & A_XDATA) locIndex = 2;
+                else if (ap->a_flag & A_BIT)   locIndex = 3;
+                else locIndex = 0;
+
+                if (ap->a_flag & A3_ABS) /* Absolute sections */
+                {
+                        lnksect2(ap, locIndex);
+                }
+                else /* Relocatable sections */
+                {
+                        if (ap->a_bset == 0)
+                        {
+                                ap->a_addr = rloc[locIndex];
+                                ap->a_bset = 1;
+                        }
+
+                        rloc[locIndex] = lnksect2(ap, locIndex);
+                }
+
+                if (!strcmp(ap->a_id, "BSEG_BYTES") && (ap->a_axp->a_addr >= 0x20))
+                {
+                        bseg_ap->a_addr += (ap->a_axp->a_addr - 0x20) * 8; /*Bytes to bits*/
+                }
+                /*
+                 * Create symbols called:
+                 *      s_<areaname>    the start address of the area
+                 *      l_<areaname>    the length of the area
+                 */
+
+                if (! symeq(ap->a_id, _abs_, 1))
+                {
+                        strcpy(temp+2,ap->a_id);
+                        *(temp+1) = '_';
+
+                        *temp = 's';
+                        sp = lkpsym(temp, 1);
+                        sp->s_addr = ap->a_addr;
+                        sp->s_type |= S_DEF;
+                        if (!strcmp(ap->a_id, "DSEG")) sp_dseg_s=sp;
+
+                        *temp = 'l';
+                        sp = lkpsym(temp, 1);
+                        sp->s_addr = ap->a_size;
+                        sp->s_axp = NULL;
+                        sp->s_type |= S_DEF;
+                        if (!strcmp(ap->a_id, "DSEG")) sp_dseg_l=sp;
+                }
+
+                ap = ap->a_ap;
+        }
+
+        /*Compute the size of DSEG*/
+        if(dseg_ap!=NULL)
+        {
+                dseg_ap->a_addr=0;
+                dseg_ap->a_size=0;
+                for(j=0; j<0x80; j++) if(idatamap[j]!=' ') dseg_ap->a_size++;
+        }
+        if(sp_dseg_s!=NULL) sp_dseg_s->s_addr=0;
+        if(sp_dseg_l!=NULL) sp_dseg_l->s_addr=dseg_ap->a_size;
+}
+
+a_uint lnksect2 (struct area *tap, int locIndex)
+{
+        a_uint size, addr;
+        struct areax *taxp;
+        int j, k, ramlimit, ramstart;
+        char fchar=' ', dchar='a';
+        char ErrMsg[]="?ASlink-Error-Could not get %d consecutive byte%s"
+                                  " in internal RAM for area %s.\n";
+
+        tap->a_unaloc=0;
+
+        /*Notice that only ISEG and SSEG can be in the indirectly addressable internal RAM*/
+        if( (!strcmp(tap->a_id, "ISEG")) || (!strcmp(tap->a_id, "SSEG")) )
+        {
+                ramstart = iram_start;
+
+                if ((iram_size <= 0) || (ramstart + iram_size > 0x100))
+                        ramlimit = 0x100;
+                else
+                        ramlimit = ramstart + iram_size;
+        }
+        else
+        {
+                ramstart = dram_start;
+
+                if ((iram_size <= 0) || (ramstart + iram_size > 0x80))
+                        ramlimit = 0x80;
+                else
+                        ramlimit = ramstart + iram_size;
+        }
+
+        size = 0;
+        addr = tap->a_addr;
+        taxp = tap->a_axp;
+
+        /*Use a letter to identify each area in the internal RAM layout map*/
+        if (locIndex==0)
+        {
+                /**/ if(!strcmp(tap->a_id, "DSEG"))
+                        fchar='D'; /*It will be converted to letters 'a' to 'z' later for each areax*/
+                else if(!strcmp(tap->a_id, "ISEG"))
+                        fchar='I';
+                else if(!strcmp(tap->a_id, "SSEG"))
+                        fchar='S';
+                else if(!strcmp(tap->a_id, "OSEG"))
+                        fchar='Q';
+                else if(!strcmp(tap->a_id, "REG_BANK_0"))
+                        fchar='0';
+                else if(!strcmp(tap->a_id, "REG_BANK_1"))
+                        fchar='1';
+                else if(!strcmp(tap->a_id, "REG_BANK_2"))
+                        fchar='2';
+                else if(!strcmp(tap->a_id, "REG_BANK_3"))
+                        fchar='3';
+                else if(!strcmp(tap->a_id, "BSEG_BYTES"))
+                        fchar='B';
+                else if(!strcmp(tap->a_id, "BIT_BANK"))
+                        fchar='T';
+                else
+                        fchar=' ';/*???*/
+        }
+        else if (locIndex == 1)
+        {
+                /**/ if(!strcmp(tap->a_id, "GSINIT"))
+                        fchar='G';
+        }
+        else if (locIndex == 2)
+        {
+                /**/ if(!strcmp(tap->a_id, "XSTK"))
+                        fchar='K';
+        }
+
+        if (tap->a_flag & A3_OVR) /* Overlayed sections */
+        {
+                while (taxp)
+                {
+                        if(taxp->a_size == 0)
+                        {
+                                taxp = taxp->a_axp;
+                                continue;
+                        }
+
+                        if ( (fchar=='0')||(fchar=='1')||(fchar=='2')||(fchar=='3') ) /*Reg banks*/
+                        {
+                                addr=(fchar-'0')*8;
+                                taxp->a_addr=addr;
+                                size=taxp->a_size;
+                                for(j=addr; (j<(int)(addr+size)) && (j<ramlimit); j++)
+                                        idatamap[j]=fchar;
+                        }
+                        else if( (fchar=='S') || (fchar=='Q') ) /*Overlay and stack in internal RAM*/
+                        {
+                                /*Find the size of the space currently used for this areax overlay*/
+                                for(j=ramstart, size=0; j<ramlimit; j++)
+                                        if(idatamap[j]==fchar) size++;
+
+                                if( (fchar=='S') && (stacksize==0) )
+                                {
+                                   /*Search for the largest space available and use it for stack*/
+                                        for(j=ramstart, k=0, taxp->a_size=0; j<ramlimit; j++)
+                                        {
+                                                if(idatamap[j]==' ')
+                                                {
+                                                        if((++k)>(int)taxp->a_size)
+                                                                taxp->a_size=k;
+                                                }
+                                                else
+                                                {
+                                                        k=0;
+                                                }
+                                        }
+                                        stacksize=taxp->a_size;
+                                }
+
+                                /*If more space required, release the previously allocated areax in
+                                internal RAM and search for a bigger one*/
+                                if((int)taxp->a_size>size)
+                                {
+                                        size=(int)taxp->a_size;
+
+                                        for(j=ramstart; j<ramlimit; j++)
+                                                if(idatamap[j]==fchar) idatamap[j]=' ';
+
+                                        /*Search for a space large enough in data memory for this overlay areax*/
+                                        for(j=ramstart, k=0; j<ramlimit; j++)
+                                        {
+                                                if(idatamap[j]==' ')
+                                                        k++;
+                                                else
+                                                        k=0;
+                                        if(k==(int)taxp->a_size)
+                                                        break;
+                                        }
+
+                                        /*Mark the memory used for overlay*/
+                                        if(k==(int)taxp->a_size)
+                                        {
+                                                addr = j-k+1;
+                                                for(j=addr; (j<(int)(addr+size)); j++)
+                                                        idatamap[j]=fchar;
+                                        }
+                                        else /*Couldn't find a chunk big enough: report the problem.*/
+                                        {
+                                                tap->a_unaloc=taxp->a_size;
+                                                fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+                                                lkerr++;
+                                        }
+                                }
+                        }
+                        else if (fchar=='T') /*Bit addressable bytes in internal RAM*/
+                        {
+                                /*Find the size of the space currently used for this areax overlay*/
+//                              for(j=0x20, size=0; j<0x30; j++)
+//                                      if(idatamap[j]==fchar) size++;
+
+                                /*If more space required, release the previously allocated areax in
+                                internal RAM and search for a bigger one*/
+                                if((int)taxp->a_size>size)
+                                {
+                                        size=(int)taxp->a_size;
+
+                                        for(j=0x20; j<0x30; j++)
+                                                if(idatamap[j]==fchar) idatamap[j]=' ';
+
+                                        /*Search for a space large enough in data memory for this overlay areax*/
+                                        for(j=0x20, k=0; j<0x30; j++)
+                                        {
+                                                if(idatamap[j]==' ')
+                                                        k++;
+                                                else
+                                                        k=0;
+                                                if(k==(int)taxp->a_size)
+                                                        break;
+                                        }
+
+                                        /*Mark the memory used for overlay*/
+                                        if(k==(int)size)
+                                        {
+                                                addr = j-k+1;
+                                                for(j=addr; (j<(int)(addr+size)); j++)
+                                                        idatamap[j]=fchar;
+                                        }
+                                        else /*Couldn't find a chunk big enough: report the problem.*/
+                                        {
+                                                tap->a_unaloc=taxp->a_size;
+                                                fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+                                                lkerr++;
+                                        }
+                                }
+                        }
+                        else /*Overlay areas not in internal ram*/
+                        {
+                                taxp->a_addr = addr;
+                                if (taxp->a_size > size) size = taxp->a_size;
+                        }
+                        taxp = taxp->a_axp;
+                }
+                /*Now set all overlayed areax to the same start address*/
+                taxp = tap->a_axp;
+                while (taxp)
+                {
+                        taxp->a_addr = addr;
+                        taxp = taxp->a_axp;
+                }
+        }
+        else if (tap->a_flag & A3_ABS) /* Absolute sections */
+        {
+                while (taxp)
+                {
+                        if (locIndex == 0)
+                        {
+                                for (j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<256); j++)
+                                {
+                                        if (idatamap[j] == ' ')
+                                                idatamap[j] = 'A';
+                                        else
+                                                fprintf(stderr, "memory overlap at 0x%X for %s\n", j, tap->a_id);
+                                }
+                        }
+                        else if (locIndex == 1)
+                        {
+                                allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051));
+                        }
+                        else if (locIndex == 2)
+                        {
+                                allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap));
+                        }
+                        taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */
+                        size += taxp->a_size;
+                        taxp = taxp->a_axp;
+                }
+        }
+        else /* Concatenated sections */
+        {
+                if ((locIndex == 1) && tap->a_size)
+                {
+                        addr = find_empty_space(addr, tap->a_size, tap->a_id, codemap8051, sizeof (codemap8051));
+                }
+                if ((locIndex == 2) && tap->a_size)
+                {
+                        addr = find_empty_space(addr, tap->a_size, tap->a_id, xdatamap, sizeof (xdatamap));
+                }
+                while (taxp)
+                {
+                        if (taxp->a_size)
+                        {
+                                if( (fchar=='D') || (fchar=='I') )
+                                {
+                                        /*Search for a space large enough in internal RAM for this areax*/
+                                        for(j=ramstart, k=0; j<ramlimit; j++)
+                                        {
+                                                if(idatamap[j]==' ')
+                                                        k++;
+                                                else
+                                                        k=0;
+                                                if(k==(int)taxp->a_size)
+                                                        break;
+                                        }
+
+                                        if(k==(int)taxp->a_size)
+                                        {
+                                                taxp->a_addr = j-k+1;
+
+                                                size += taxp->a_size;
+
+                                                for(j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<ramlimit); j++)
+                                                        idatamap[j]=(fchar=='D')?dchar:fchar;
+                                                if((taxp->a_size>0)&&(fchar=='D'))dchar++;
+                                                if((dchar<'a')||(dchar>'z')) dchar='D'; /*Ran out of letters?*/
+                                        }
+                                        else /*We are in trouble, there is not enough memory for an areax chunk*/
+                                        {
+                                                taxp->a_addr = addr;
+                                                addr += taxp->a_size;
+                                                size += taxp->a_size;
+                                                tap->a_unaloc+=taxp->a_size;
+                                                fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+                                                lkerr++;
+                                        }
+                                }
+                                else if (fchar=='B')
+                                {
+                                        /*Search for a space large enough in data memory for this areax*/
+                                        for(j=0x20, k=0; j<0x30; j++)
+                                        {
+                                                if(idatamap[j]==' ')
+                                                        k++;
+                                                else
+                                                        k=0;
+                                                if(k==(int)taxp->a_size) break;
+                                        }
+
+                                        /*Mark the memory used*/
+                                        if(k==(int)taxp->a_size)
+                                        {
+                                                taxp->a_addr = j-k+1;
+                                                for(j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<0x30); j++)
+                                                        idatamap[j]=fchar;
+                                        }
+                                        else /*Couldn't find a chunk big enough: report the problem.*/
+                                        {
+                                                tap->a_unaloc=taxp->a_size;
+                                                fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+                                                lkerr++;
+                                        }
+                                        size += taxp->a_size;
+                                }
+                                else /*For concatenated BIT, CODE, and XRAM areax's*/
+                                {
+                                        //expand external stack
+                                        if((fchar=='K') && (taxp->a_size == 1))
+                                        {
+                                                taxp->a_size = 256-(addr & 0xFF);
+                                        }
+                                        //find next unused address now
+                                        if (locIndex == 1)
+                                        {
+                                                addr = find_empty_space(addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051));
+                                                allocate_space(addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051));
+                                        }
+                                        if (locIndex == 2)
+                                        {
+                                                addr = find_empty_space(addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap));
+                                                allocate_space(addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap));
+                                        }
+                                        taxp->a_addr = addr;
+                                        addr += taxp->a_size;
+                                        size += taxp->a_size;
+                                }
+                        }
+                        else
+                        {
+                            taxp->a_addr = addr;
+                        }
+                        taxp = taxp->a_axp;
+                }
+        }
+        tap->a_size = size;
+        tap->a_addr = tap->a_axp->a_addr;
+        for (taxp = tap->a_axp; taxp && !taxp->a_size; taxp = taxp->a_axp)
+        {
+        }
+        if (taxp)
+        {
+                tap->a_addr = taxp->a_addr;
+        }
+
+        if ((tap->a_flag & A3_PAG) && (size > 256))
+        {
+                fprintf(stderr,
+                        "\n?ASlink-Warning-Paged Area %s Length Error\n",
+                        tap->a_id);
+                lkerr++;
+        }
+        if ((tap->a_flag & A3_PAG) && (tap->a_size) &&
+                ((tap->a_addr & 0xFFFFFF00) != ((addr-1) & 0xFFFFFF00)))
+        {
+                fprintf(stderr,
+                        "\n?ASlink-Warning-Paged Area %s Boundary Error\n",
+                        tap->a_id);
+                lkerr++;
+        }
+        return addr;
+}
+/* end sdld specific */
+
diff --git a/Kernel/tools/bankld/lkbank.c b/Kernel/tools/bankld/lkbank.c
new file mode 100644 (file)
index 0000000..22dfd76
--- /dev/null
@@ -0,0 +1,644 @@
+/* lkbank.c */
+
+/*
+ *  Copyright (C) 2001-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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ */
+
+#include "aslink.h"
+
+/*Module        lkbank.c
+ *
+ *      The module lkbank.c contains the function newbank() which
+ *      creates a bank structure and the function module() which
+ *      loads the module name into the current head structure.
+ *
+ *      lkbank.c contains the following functions:
+ *              VOID    newbank()
+ *              VOID    lkpbank()
+ *              VOID    setbank()
+ *              VOID    chkbank()
+ *              VOID    lkfopen()
+ *              VOID    lkfclose()
+ *
+ *      lkbank.c contains no local variables.
+ */
+
+/*)Function     VOID    newbank()
+ *
+ *      The function newbank() creates and/or modifies bank
+ *      structures for each B directive read from
+ *      the .rel file(s).  The function lkpbank() is called
+ *      to find the bank structure associated with this name.
+ *      If the bank does not yet exist then a new bank
+ *      structure is created and linked to any existing
+ *      linked bank structures. The bank flags are copied
+ *      into the bank flag variable.  Refer to lkdata.c for
+ *      details of the structures and their linkage.
+ *
+ *      local variables:
+ *              bank    **hblp          pointer to an array of pointers
+ *              int     i               counter, loop variable, value
+ *              char    id[]            id string
+ *              int     nbank           number of banks in this head structure
+ *              a_uint  v               temporary value
+ *
+ *      global variables:
+ *              bank    *bp             Pointer to the current
+ *                                      bank structure
+ *              head    *hp             Pointer to the current
+ *                                      head structure
+ *              int     lkerr           error flag
+ *
+ *      functions called:
+ *              a_uint  eval()          lkeval.c
+ *              VOID    exit()          c_library
+ *              int     fprintf()       c_library
+ *              VOID    getid()         lklex.c
+ *              VOID    lkpbank()       lkbank.c
+ *              VOID    skip()          lklex.c
+ *
+ *      side effects:
+ *              The bank structure is created and
+ *              linked with the appropriate head structures.
+ *              Failure to allocate bank structure
+ *              space will terminate the linker.  Other internal
+ *              errors most likely caused by corrupted .rel
+ *              files will also terminate the linker.
+ */
+
+/*
+ * Create a bank entry.
+ *
+ * B xxxxxx base nnnn size nnnn map nnn flags n fsfx xxxxxx
+ *   |           |         |        |         |      |
+ *   |           |         |        |         |      `-- bp->b_fsfx
+ *   |           |         |        |         `--------- bp->b_flag
+ *   |           |         |        `--------------------bp->b_map
+ *   |           |         `---------------------------- bp->b_size
+ *   |           `-------------------------------------- bp->b_base
+ *   `-------------------------------------------------- bp->b_id
+ *
+ */
+VOID
+newbank(void)
+{
+        int i;
+        a_uint v;
+        char id[NCPS];
+        int nbank;
+        struct bank **hblp;
+
+        if (headp == NULL) {
+                fprintf(stderr, "No header defined\n");
+                lkexit(ER_FATAL);
+        }
+        /*
+         * Create bank entry
+         */
+        getid(id, -1);
+        lkpbank(id);
+        /*
+         * Evaluate Parameters
+         */
+        while (more()) {
+                getid(id, -1);
+                /*
+                 * Evaluate base address
+                 */
+                if (symeq("base", id, 1)) {
+                        v = eval();
+                        if (bp->b_base == 0) {
+                                bp->b_base = v;
+                        } else {
+                                if (v && (bp->b_base != v)) {
+                                        fprintf(stderr, "Conflicting address in bank %s\n", id);
+                                        lkerr++;
+                                }
+                        }
+                } else
+                /*
+                 * Evaluate bank size
+                 */
+                if (symeq("size", id, 1)) {
+                        v = eval();
+                        if (bp->b_size == 0) {
+                                bp->b_size = v;
+                        } else {
+                                if (v && (bp->b_size != v)) {
+                                        fprintf(stderr, "Conflicting size in bank %s\n", id);
+                                        lkerr++;
+                                }
+                        }
+                } else
+                /*
+                 * Evaluate bank mapping
+                 */
+                if (symeq("map", id, 1)) {
+                        v = eval();
+                        if (bp->b_map == 0) {
+                                bp->b_map = v;
+                        } else {
+                                if (v && (bp->b_map != v)) {
+                                        fprintf(stderr, "Conflicting mapping in bank %s\n", id);
+                                        lkerr++;
+                                }
+                        }
+                } else
+                /*
+                 * Evaluate flags
+                 */
+                if (symeq("flags", id, 1)) {
+                        i = (int) eval();
+                        if (bp->b_flag == 0) {
+                                bp->b_flag = i;
+                        } else {
+                                if (i && (bp->b_flag != i)) {
+                                        fprintf(stderr, "Conflicting flags in bank %s\n", id);
+                                        lkerr++;
+                                }
+                        }
+                } else
+                /*
+                 * File Suffix
+                 */
+                if (symeq("fsfx", id, 1)) {
+                        if (more()) {
+                                getid(id, -1);
+                                if (bp->b_fsfx == NULL) {
+                                        bp->b_fsfx = strsto(id);
+                                } else {
+                                        if (!symeq(bp->b_fsfx, id, 1)) {
+                                                fprintf(stderr, "Conflicting fsfx in bank %s\n", id);
+                                                lkerr++;
+                                        }
+                                }
+                        }
+                }
+        }
+        /*
+         * Place pointer in header bank list
+         */
+        nbank = hp->h_nbank;
+        hblp = hp->b_list;
+        for (i=0; i < nbank; i++) {
+                if (hblp[i] == NULL) {
+                        hblp[i] = bp;
+                        return;
+                }
+        }
+        fprintf(stderr, "Header bank list overflow\n");
+        lkexit(ER_FATAL);
+}
+
+/*)Function     VOID    lkpbank(id)
+ *
+ *              char *  id              pointer to the bank name string
+ *
+ *      The function lkpbank() searches the linked bank structures
+ *      for a name match.  If the name is not found then a bank
+ *      structure is created.  The linker flag, rtaflg, for initializing
+ *      i86 format output is set.
+ *
+ *      local variables:
+ *              area *  tbp             pointer to a bank structure
+ *
+ *      global variables:
+ *              bank    *bp             Pointer to the current
+ *                                      bank structure
+ *              bank    *bankp          The pointer to the first
+ *                                      bank structure of a linked list
+ *
+ *      functions called:
+ *              VOID *  new()           lksym()
+ *              char *  strsto()        lksym.c
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              Bank structure may be created.
+ *              Failure to allocate space for a structure
+ *              will terminate the linker.
+ */
+
+VOID
+lkpbank(char *id)
+{
+        struct bank *tbp;
+
+        bp = bankp;
+        while (bp) {
+                if (symeq(id, bp->b_id, 1)) {
+                        return;
+                }
+                bp = bp->b_bp;
+        }
+        bp = (struct bank *) new (sizeof(struct bank));
+        tbp = bankp;
+        while (tbp->b_bp)
+                tbp = tbp->b_bp;
+        tbp->b_bp = bp;
+        bp->b_id = strsto(id);
+        bp->b_rtaflg = 1;
+}
+
+
+/*)Function     VOID    setbank()
+ *
+ *      The function setbank() sets the base address of the bank by
+ *      finding the first area in the bank and initializing the
+ *      value to the bank base address.  The bank base address is always
+ *      specified in 'byte' addressing.  A first area which is not 'byte'
+ *      addressed (e.g. a processor addressed by a 'word' of 2 or more bytes)
+ *      has the base address scaled to begin at the 'byte' address.
+ *
+ *      If the area base address has been set using the -b linker
+ *      option then the bank base address is NOT set.
+ *
+ *      The function setbank() also scans all the areas searching
+ *      for non-banked entries.  All non-banked areas are linked
+ *      to bank[0] which does not have a bank file suffix.
+ *
+ *      local variables:
+ *              a_uint  base            base address in 'bytes'
+ *              int     bytes           size of PC increment in bytes
+ *
+ *      global variables:
+ *              area    *ap             Pointer to the current
+ *                                      area structure
+ *              area    *areap          The pointer to the first
+ *                                      area structure of a linked list
+ *              bank    *bp             Pointer to the current
+ *                                      bank structure
+ *              bank    *bankp          The pointer to the first
+ *                                      bank structure of a linked list
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              Base starting address may be set and non-banked
+ *              areas linked to bank[0].
+ */
+
+VOID
+setbank(void)
+{
+        a_uint base;
+        int bytes;
+
+        /*
+         * For each bank structure with a defined base address value
+         * scan the area structures for the first relocatable area
+         * in the bank and all absolute areas in the bank.
+         * Load the base address value into the area address if the
+         * bank base address has not been overridden by a -b option.
+         * The bank base address is always expressed in 'bytes'.
+         */
+        for (bp = bankp; bp != NULL; bp = bp->b_bp) {
+                if ((bp->b_flag & B_BASE) == 0)
+                        continue;
+                for (ap = areap; ap != NULL; ap = ap->a_ap) {
+                        if (ap->a_bp != bp)
+                                continue;
+                        if ((ap->a_flag & A4_BNK) != A4_BNK)
+                                continue;
+                        if (ap->a_bset)
+                                continue;
+                        bytes = 1 + (ap->a_flag & A4_WLMSK);
+                        base = bp->b_base;
+                        ap->a_addr = (base/bytes) + ((base % bytes) ? 1 : 0);
+                        ap->a_bset = 1;
+                        if ((ap->a_flag & A4_ABS) == A4_ABS) {
+                                continue;
+                        } else {
+                                break;
+                        }
+                }
+        }
+
+        /*
+         * Scan all the area structures for non-banked
+         * areas.  Set the area bank pointer to reference
+         * bank[0] which has no file suffix.
+         */
+        for (ap = areap; ap != NULL; ap = ap->a_ap) {
+                if ((ap->a_flag & A4_BNK) == 0) {
+                        ap->a_bp = bankp;
+                }
+        }
+}
+
+
+/*)Function     VOID    chkbank(fp)
+ *
+ *              FILE    *fp             file handle
+ *
+ *      The function chkbank() scans the bank/area structures to
+ *      determine the length of a bank.  Banks exceeding the size
+ *      specified from a bank size option are flagged.  The bank
+ *      size is always in 'byte' units.
+ *
+ *      local variables:
+ *              a_uint  alow            lowest  address in a bank
+ *              a_uint  ahigh           highest address in a bank
+ *              a_uint  blimit          bank size limit
+ *
+ *      global variables:
+ *              area    *ap             Pointer to the current
+ *                                      area structure
+ *              area    *areap          The pointer to the first
+ *                                      area structure of a linked list
+ *              bank    *bp             Pointer to the current
+ *                                      bank structure
+ *              bank    *bankp          The pointer to the first
+ *                                      bank structure of a linked list
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              Bank size may be flagged.
+ */
+
+VOID
+chkbank(FILE *fp)
+{
+        a_uint alow, ahigh, blimit, bytes;
+
+        for (bp = bankp; bp != NULL; bp = bp->b_bp) {
+                if ((bp->b_flag & B_SIZE) == 0) {
+                        continue;
+                }
+                blimit = bp->b_size;
+                if (blimit == 0) {
+                        continue;
+                }
+                alow = ~0;
+                ahigh = 0;
+                for (ap = areap; ap != NULL; ap = ap->a_ap) {
+                        if (ap->a_bp != bp) {
+                                continue;
+                        }
+                        if ((ap->a_flag & A4_BNK) != A4_BNK) {
+                                continue;
+                        }
+                        bytes = ap->a_addr * (1 + (ap->a_flag & A4_WLMSK));
+                        if (bytes < alow) {
+                                alow = bytes;
+                        }
+                        bytes = (ap->a_addr + ap->a_size) * (1 + (ap->a_flag & A4_WLMSK));
+                        if (bytes > ahigh) {
+                                ahigh = bytes;
+                        }
+                }
+                if ((ahigh - alow) > blimit) {
+                        fprintf(fp,
+                        "\n?ASlink-Warning-Size limit exceeded in bank %s\n", bp->b_id);
+                        lkerr++;
+                }
+        }
+}
+
+
+/*)Function     VOID    lkfopen()
+ *
+ *      The function lkfopen() scans the bank/area structures to
+ *      open output data files for banks with any data.  Files
+ *      are not opened for banks/areas with no output data.
+ *
+ *      The bank structures are first scanned to create the
+ *      file specification from the output file name combined
+ *      with any given file suffixs.
+ *
+ *      local variables:
+ *              int     idx             position of FSEPX in file specification
+ *              File *  fp              temporary file handle
+ *              char *  frmt            temporary file type string
+ *              char    str[]           File Specification String
+ *              struct bank *tbp        temporary bank pointer
+ *
+ *
+ *      global variables:
+ *              int     a_bytes         T line address bytes
+ *              area    *ap             Pointer to the current
+ *                                      area structure
+ *              area    *areap          The pointer to the first
+ *                                      area structure of a linked list
+ *              char    afspec[]        Filespec from afile()
+ *              bank    *bp             Pointer to the current
+ *                                      bank structure
+ *              bank    *bankp          The pointer to the first
+ *                                      bank structure of a linked list
+ *              FILE *  jfp             NoICE output file handle
+ *              int     oflag           data output type flag
+ *              FILE *  stderr          Standard Error Output handle
+ *
+ *      functions called:
+ *              FILE *  afile()         lkmain.c
+ *              int     fclose()        c_library
+ *              int     fprintf()       c_library
+ *              VOID    lkexit()        lkmain.c
+ *              char *  strcpy()        c_library
+ *              char *  strsto()        lksym.c
+ *              char *  symeq()         lksym.c
+ *
+ *      side effects:
+ *              All data output files are opened.
+ */
+
+VOID
+lkfopen(void)
+{
+        int idx;
+        char * frmt;
+        char str[NCPS+NCPS];
+        struct bank *tbp;
+        struct sym *sp;
+        FILE * fp;
+
+        if (oflag == 0) return;
+
+        /*
+         * Scan bank structures preparing
+         * the output file specifications.
+         */
+        idx = linkp->f_idx + fndext(linkp->f_idp + linkp->f_idx);
+        strncpy(str, linkp->f_idp, idx);
+        str[idx] = 0;
+
+        for (bp = bankp; bp != NULL; bp = bp->b_bp) {
+                if (bp->b_flag & B_FSFX) {
+                        strcpy(str + idx, bp->b_fsfx);
+                }
+                bp->b_fspec = strsto(str);
+                str[idx] = 0;
+        }
+
+        /*
+         * If .__.END. is defined force
+         * an output file to be opened.
+         */
+        sp = lkpsym(".__.END.", 0);
+        if (sp) {
+                sp->s_axp->a_bap->a_flag |= A4_OUT;
+        }
+
+        /*
+         * Scan the area list opening the appropriate
+         * output file if there is data in the area.
+         */
+        ap = areap;
+        while (ap) {
+                if ((ap->a_flag & A4_BNK) != A4_BNK) {
+                        ap->a_bp = bankp;
+                }
+                if ((ap->a_flag & A4_OUT) || (ap->a_size != 0)) {
+                        bp = ap->a_bp;
+                        if (bp->b_ofp == NULL) {
+                                /*
+                                 * Scan file specifications for
+                                 * identical file already opened.
+                                 */
+                                for (tbp = bankp; tbp != NULL; tbp = tbp->b_bp) {
+                                        if (symeq(tbp->b_fspec, bp->b_fspec, 1)) {
+                                                if (tbp->b_ofp != NULL) {
+                                                        bp->b_ofp = tbp->b_ofp;
+                                                        bp->b_ofspec = tbp->b_ofspec;
+                                                }
+                                        }
+                                }
+                        }
+                        if (bp->b_ofp == NULL) {
+                                fp = stderr;
+                                /*
+                                 * Open output file
+                                 */
+                                if (oflag == 1) {
+                                        switch(a_bytes) {
+                                        default:
+                                        case 2: frmt = "ihx"; break;
+                                        }
+                                        fp = afile(bp->b_fspec, frmt, 1);
+                                } else
+                                if (oflag == 2) {
+                                        switch(a_bytes) {
+                                        default:
+                                        case 2: frmt = "s19"; break;
+                                        case 3: frmt = "s28"; break;
+                                        case 4: frmt = "s37"; break;
+                                        }
+                                        fp = afile(bp->b_fspec, frmt, 1);
+                                } else
+                                if (oflag == 3) {
+                                        switch(a_bytes) {
+                                        default:
+                                        case 2: frmt = "bin"; break;
+                                        case 3: frmt = "bi3"; break;
+                                        case 4: frmt = "bi4"; break;
+                                        }
+                                        fp = afile(bp->b_fspec, frmt, 2);
+                                } else
+                                /* sdld specific */
+                                if (oflag == 4) {
+                                        fp = afile(bp->b_fspec, "elf", 2);
+                                }
+                                /* end sdld specific */
+                                if (fp != stderr) {
+                                        if (fp == NULL) {
+                                                lkexit(ER_FATAL);
+                                        }
+                                        bp->b_ofspec = strsto(afspec);
+#if NOICE
+                                        /*
+                                         * Include NoICE command to load file
+                                         */
+                                        if (jfp) {
+                                                fprintf(jfp, "LOAD %s\n", bp->b_ofspec);
+                                        }
+#endif
+                                }
+                                bp->b_ofp = fp;
+                        }
+                        ap->a_ofp = bp->b_ofp;
+                } else {
+                        ap->a_ofp = NULL;
+                }
+                ap = ap->a_ap;
+        }
+}
+
+
+/*)Function     VOID    lkfclose()
+ *
+ *      The function lkfclose() scans the bank structures to
+ *      close all open data output files.
+ *
+ *      local variables:
+ *              struct bank *tbp        temporary bank pointer
+ *
+ *      global variables:
+ *              bank    *bp             Pointer to the current
+ *                                      bank structure
+ *              bank    *bankp          The pointer to the first
+ *                                      bank structure of a linked list
+ *              FILE *  ofp             Output file handle
+ *              FILE *  stderr          Standard Error Output handle
+ *
+ *      functions called:
+ *              VOID    lkout()         lkout.c
+ *              int     fclose()        c_library
+ *
+ *      side effects:
+ *              All open data output files are closed.
+ */
+
+VOID
+lkfclose(void)
+{
+        struct bank *tbp;
+
+        /*
+         * Scan Bank Structure
+         * Output data terminations
+         * and close open files
+         */
+        bp = bankp;
+        while (bp != NULL) {
+                ofp = bp->b_ofp;
+                if (ofp != NULL) {
+                        lkout(0, 0);
+                        if (ofp != stderr) {
+                                fclose(ofp);
+                        }
+                        /*
+                         * Scan bank structure for
+                         * identical file handles.
+                         */
+                        for (tbp = bp->b_bp; tbp != NULL; tbp = tbp->b_bp) {
+                                if (tbp->b_ofp == ofp) {
+                                        tbp->b_ofp = NULL;
+                                }
+                        }
+                        ofp = NULL;
+                        bp->b_ofp = NULL;
+                }
+                bp = bp->b_bp;
+        }
+}
diff --git a/Kernel/tools/bankld/lkdata.c b/Kernel/tools/bankld/lkdata.c
new file mode 100644 (file)
index 0000000..bb83900
--- /dev/null
@@ -0,0 +1,623 @@
+/* lkdata.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ *   With enhancements from
+ *      John L. Hartman (JLH)
+ *      jhartman@compuserve.com
+ *
+ */
+
+#include "aslink.h"
+
+/*)Module       lkdata.c
+ *
+ *      The module lkdata contains the global variables
+ *      and structures used in the linker aslink.
+ */
+
+/*
+ * Internal ASxxxx Version Variable
+ */
+int     ASxxxx_VERSION;
+
+
+/*
+ *      Definitions for all Global Variables
+ */
+
+char    *_abs_  = { ".  .ABS." };
+
+char    afspec[FILSPC]; /*      The filespec created by afile()
+                         */
+int     lkerr;          /*      Linker error flag
+                         */
+char    *ip;            /*      Pointer into the REL file text line in ib[]
+                         */
+char    ib[NINPUT];     /*      REL file text line
+                         */
+char    *rp;            /*      pointer into the LST file
+                         *      text line in rb[]
+                         */
+char    rb[NINPUT];     /*      LST file text line being
+                         *      address relocated
+                         */
+int     oflag;          /*      Output file type flag
+                         */
+int     objflg;         /*      Linked file/library object output flag
+                         */
+
+#if NOICE
+int     jflag;          /*      NoICE output flag
+                         */
+#endif
+
+#if SDCDB
+int     yflag;          /*      SDCDB output flag
+                         */
+#endif
+
+int     mflag;          /*      Map output flag
+                         */
+int     xflag;          /*      Map file radix type flag
+                         */
+int     pflag;          /*      print linker command file flag
+                         */
+int     uflag;          /*      Listing relocation flag
+                         */
+int     wflag;          /*      Enable wide format listing
+                         */
+int     zflag;          /*      Disable symbol case sensitivity
+                         */
+int     radix;          /*      current number conversion radix:
+                         *      2 (binary), 8 (octal), 10 (decimal),
+                         *      16 (hexadecimal)
+                         */
+int     line;           /*      current line number
+                         */
+int     page;           /*      current page number
+                         */
+int     lop;            /*      current line number on page
+                         */
+int     pass;           /*      linker pass number
+                         */
+a_uint  pc;             /*      current relocation address
+                         */
+int     pcb;            /*      current bytes per pc word
+                         */
+int     rtcnt;          /*      count of elements in the
+                         *      rtval[] and rtflg[] arrays
+                         */
+a_uint  rtval[NTXT];    /*      data associated with relocation
+                         */
+int     rtflg[NTXT];    /*      indicates if rtval[] value is
+                         *      to be sent to the output file.
+                         */
+int     rterr[NTXT];    /*      indicates if rtval[] value should
+                         *      be flagged as a relocation error.
+                         */
+char    rtbuf[NMAX];    /*      S19/IHX output buffer
+                         */
+struct  bank * rtabnk;  /*      rtbuf[] processing
+                         */
+int     rtaflg;         /*      rtbuf[] processing
+                         */
+a_uint  rtadr0 = 0;     /*
+                         */
+a_uint  rtadr1 = 0;     /*
+                         */
+a_uint  rtadr2 = 0;     /*
+                         */
+int     obj_flag = 0;   /*      Linked file/library object output flag
+                         */
+int     a_bytes;        /*      REL file T Line address length
+                         */
+int     hilo;           /*      REL file byte ordering
+                         */
+a_uint  a_mask;         /*      Address Mask
+                         */
+a_uint  s_mask;         /*      Sign Mask
+                         */
+a_uint  v_mask;         /*      Value Mask
+                         */
+int     gline;          /*      LST file relocation active
+                         *      for current line
+                         */
+int     gcntr;          /*      LST file relocation active
+                         *      counter
+                         */
+/* sdld specific */
+char    *optsdcc;
+char    *optsdcc_module;
+int     sflag;          /*      JCF: Memory usage output flag
+                         */
+int     packflag=0;     /*      JCF: Pack internal memory flag
+                         */
+int     stacksize=0;    /*      JCF: Stack size
+                         */
+int     aflag;          /*      Overlapping area warning flag
+                         */
+int     rflag;          /*      Extended linear address record flag.
+                         */
+a_uint  iram_size;      /*      internal ram size
+                         */
+long    xram_size = -1; /*      external ram size
+                         */
+long    code_size = -1; /*      code size
+                         */
+/* end sdld specific */
+
+/*
+ *      The structure lfile contains a pointer to a
+ *      file specification string, an index which points
+ *      to the file name (past the 'path'), the file type,
+ *      an object output flag, and a link to the next
+ *      lfile structure.
+ *
+ *      struct  lfile
+ *      {
+ *              struct  lfile   *f_flp;         lfile link
+ *              int     f_type;                 File type
+ *              char    *f_idp;                 Pointer to file spec
+ *              int     f_obj;                  Object output flag
+ *      };
+ */
+struct  lfile   *filep; /*      The pointers (lfile *) filep,
+                         *      (lfile *) cfp, and (FILE *) sfp
+                         *      are used in conjunction with
+                         *      the routine nxtline() to read
+                         *      asmlnk commands from
+                         *      (1) the standard input or
+                         *      (2) or a command file
+                         *      and to read the REL files
+                         *      sequentially as defined by the
+                         *      asmlnk input commands.
+                         *
+                         *      The pointer *filep points to the
+                         *      beginning of a linked list of
+                         *      lfile structures.
+                         */
+struct  lfile   *cfp;   /*      The pointer *cfp points to the
+                         *      current lfile structure
+                         */
+struct  lfile   *startp;/*      aslink startup file structure
+                         */
+struct  lfile   *linkp; /*      pointer to first lfile structure
+                         *      containing an input REL file
+                         *      specification
+                         */
+struct  lfile   *lfp;   /*      pointer to current lfile structure
+                         *      being processed by parse()
+                         */
+FILE    *ofp = NULL;    /*      Output file handle
+                         *      for word formats
+                         */
+
+#if NOICE
+FILE    *jfp = NULL;    /*      NoICE output file handle
+                         */
+#endif
+
+#if SDCDB
+FILE    *yfp = NULL;    /*      SDCDB output file handle
+                         */
+#endif
+
+FILE    *mfp = NULL;    /*      Map output file handle
+                         */
+FILE    *rfp = NULL;    /*      File handle for output
+                         *      address relocated ASxxxx
+                         *      listing file
+                         */
+FILE    *sfp = NULL;    /*      The file handle sfp points to the
+                         *      currently open file
+                         */
+FILE    *tfp = NULL;    /*      File handle for input
+                         *      ASxxxx listing file
+                         */
+
+/*
+ *      The structures of head, bank, area, areax, and sym
+ *      are created as the REL files are read during the first
+ *      pass of the linker.  The struct head is created upon
+ *      encountering a H directive in the REL file.  The
+ *      structure contains a link to a link file structure
+ *      (struct lfile) which describes the file containing the H
+ *      directive, a pointer to an array of merge mode
+ *      definition pointers, the number of data/code areas
+ *      contained in this header segment, the number of
+ *      symbols referenced/defined in this header segment, a pointer
+ *      to an array of pointers to areax structures (struct areax)
+ *      created as each A directive is read, a pointer to an
+ *      array of pointers to symbol structures (struct sym) for
+ *      all referenced/defined symbols and a pointer to an array
+ *      of pointers to bank structures (struct bank) referenced
+ *      by this module.  As H directives are read
+ *      from the REL files a linked list of head structures is
+ *      created by placing a link to the new head structure
+ *      in the previous head structure.
+ *
+ *      struct  head
+ *      {
+ *              struct  head   *h_hp;           Header link
+ *              struct  lfile  *h_lfile;        Associated file
+ *              int     h_narea;                # of areas
+ *              struct  areax **a_list;         Area list
+ *              int     h_nsym;                 # of symbols
+ *              struct  sym   **s_list;         Symbol list
+ *              int     h_nbank;                # of banks
+ *              struct  bank  **b_list;         Bank list
+ *              int     h_nmode;                # of modes
+ *              struct  mode  **m_list;         Mode list
+ *              char *  m_id;                   Module name
+ *      };
+ */
+struct  head    *headp; /*      The pointer to the first
+                         *      head structure of a linked list
+                         */
+struct  head    *hp;    /*      Pointer to the current
+                         *      head structure
+                         */
+
+/*
+ *      The bank structure contains the parameter values for a
+ *      specific program or data bank.  The bank structure
+ *      is a linked list of banks.  The initial default bank
+ *      is unnamed and is defined in lkdata.c, the next bank structure
+ *      will be linked to this structure through the structure
+ *      element 'struct bank *b_bp'.  The structure contains the
+ *      bank name, the bank base address (default = 0)
+ *      the bank size, (default = 0, whole addressing space)
+ *      and the file name suffix. (default is none)  These optional
+ *      parameters are from  the .bank assembler directive.
+ *      The bank structure also contains the bank data output
+ *      file specificatiion, file handle pointer and the
+ *      bank first output flag.
+ *
+ *      struct  bank
+ *      {
+ *              struct  bank *b_bp;     Bank link
+ *              char *  b_id;           Bank Name
+ *              char *  b_fsfx;         Bank File Suffix
+ *              a_uint  b_base;         Bank base address
+ *              a_uint  b_size;         Bank size
+ *              a_uint  b_map           Bank mapping
+ *              int     b_flag;         Bank flags
+ *              char *  b_fspec;        Bank File Specification
+ *              FILE *  b_ofp;          Bank File Handle
+ *              int     b_oflag;        Bank has output flag
+ *              int     b_rtaflg        Bank First Output flag
+ *      };
+ */
+struct  bank    bank[1] = {
+    {   NULL,   "",     "",     0,      0,      0,      0,      "",     NULL,   0,      1       }
+};
+
+struct  bank    *bankp = &bank[0];
+                        /*      The pointer to the first
+                         *      bank structure
+                         */
+struct  bank    *bp;    /*      Pointer to the current
+                         *      bank structure
+                         */
+
+/*
+ *      A structure area is created for each 'unique' data/code
+ *      area definition found as the REL files are read.  The
+ *      struct area contains the name of the area, a flag byte
+ *      which contains the area attributes (REL/CON/OVR/ABS),
+ *      the area base address set flag byte (-b option), and the
+ *      area base address and total size which will be filled
+ *      in at the end of the first pass through the REL files.
+ *      The area structure also contains a link to the bank
+ *      this area is a part of and a data output file handle
+ *      pointer which is loaded from from the bank structure.
+ *      As A directives are read from the REL files a linked
+ *      list of unique area structures is created by placing a
+ *      link to the new area structure in the previous area structure.
+ *
+ *      struct  area
+ *      {
+ *              struct  area    *a_ap;          Area link
+ *              struct  areax   *a_axp;         Area extension link
+ *              struct  bank    *a_bp;          Bank link
+ *              FILE *  a_ofp;                  Area File Handle
+ *              a_uint  a_addr;                 Beginning address of area
+ *              a_uint  a_size;                 Total size of the area
+ *              int     a_bset;                 Area base address set
+ *              int     a_flag;                 Flags
+ *              char *  a_id;                   Name
+ *      };
+ */
+struct  area    *areap; /*      The pointer to the first
+                         *      area structure of a linked list
+                         */
+struct  area    *ap;    /*      Pointer to the current
+                         *      area structure
+                         */
+
+/*
+ *      An areax structure is created for every A directive found
+ *      while reading the REL files.  The struct areax contains a
+ *      link to the 'unique' area structure referenced by the A
+ *      directive and to the head structure this area segment is
+ *      a part of.  The size of this area segment as read from the
+ *      A directive is placed in the areax structure.  The beginning
+ *      address of this segment will be filled in at the end of the
+ *      first pass through the REL files.  As A directives are read
+ *      from the REL files a linked list of areax structures is
+ *      created for each unique area.  The final areax linked
+ *      list has at its head the 'unique' area structure linked
+ *      to the linked areax structures (one areax structure for
+ *      each A directive for this area).
+ *
+ *      struct  areax
+ *      {
+ *              struct  areax   *a_axp;         Area extension link
+ *              struct  area    *a_bap;         Base area link
+ *              struct  head    *a_bhp;         Base header link
+ *              a_uint  a_addr;                 Beginning address of section
+ *              a_uint  a_size;                 Size of the area in section
+ *      };
+ */
+struct  areax   *axp;   /*      Pointer to the current
+                         *      areax structure
+                         */
+
+/*
+ *      A sym structure is created for every unique symbol
+ *      referenced/defined while reading the REL files.  The
+ *      struct sym contains the symbol's name, a flag value
+ *      (not used in this linker), a symbol type denoting
+ *      referenced/defined, and an address which is loaded
+ *      with the relative address within the area in which
+ *      the symbol was defined.  The sym structure also
+ *      contains a link to the area where the symbol was defined.
+ *      The sym structures are linked into linked lists using
+ *      the symbol link element.
+ *
+ *      struct  sym
+ *      {
+ *              struct  sym     *s_sp;          Symbol link
+ *              struct  areax   *s_axp;         Symbol area link
+ *              char    s_type;                 Symbol subtype
+ *              char    s_flag;                 Flag byte
+ *              a_uint  s_addr;                 Address
+ *              char    *s_id;                  Name (JLH)
+ *              char    *m_id;                  Module
+ *      };
+ */
+struct  sym *symhash[NHASH]; /* array of pointers to NHASH
+                              * linked symbol lists
+                              */
+/*
+ *      The struct base contains a pointer to a
+ *      base definition string and a link to the next
+ *      base structure.
+ *
+ *      struct  base
+ *      {
+ *              struct  base  *b_base;          Base link
+ *              char          *b_strp;          String pointer
+ *      };
+ */
+struct  base    *basep; /*      The pointer to the first
+                         *      base structure
+                         */
+struct  base    *bsp;   /*      Pointer to the current
+                         *      base structure
+                         */
+
+/*
+ *      The struct globl contains a pointer to a
+ *      global definition string and a link to the next
+ *      global structure.
+ *
+ *      struct  globl
+ *      {
+ *              struct  globl *g_globl;         Global link
+ *              char          *g_strp;          String pointer
+ *      };
+ */
+struct  globl   *globlp;/*      The pointer to the first
+                         *      globl structure
+                         */
+struct  globl   *gsp;   /*      Pointer to the current
+                         *      globl structure
+                         */
+
+/*
+ *      A structure sdp is created for each 'unique' paged
+ *      area definition found as the REL files are read.
+ *      As P directives are read from the REL files a linked
+ *      list of unique sdp structures is created by placing a
+ *      link to the new sdp structure in the previous area structure.
+ *
+ *      struct  sdp
+ *      {
+ *              struct  area  *s_area;  Paged Area link
+ *              struct  areax *s_areax; Paged Area Extension Link
+ *              a_uint  s_addr;         Page address offset
+ *      };
+ */
+struct  sdp     sdp;    /* Base Page Structure */
+
+/*
+ *      The structure rerr is loaded with the information
+ *      required to report an error during the linking
+ *      process.  The structure contains an index value
+ *      which selects the areax structure from the header
+ *      areax structure list, a mode value which selects
+ *      symbol or area relocation, the base address in the
+ *      area section, an area/symbol list index value, and
+ *      an area/symbol offset value.
+ *
+ *      struct  rerr
+ *      {
+ *              int     aindex;         Linking area
+ *              int     mode;           Relocation mode
+ *              a_uint  rtbase;         Base address in section
+ *              int     rindex;         Area/Symbol relocation index
+ *              a_uint  rval;           Area/Symbol offset value
+ *      };
+ */
+struct  rerr    rerr;   /*      Structure containing the
+                         *      linker error information
+                         */
+
+/*
+ *      The structure lbpath is created for each library
+ *      path specification input by the -k option.  The
+ *      lbpath structures are linked into a list using
+ *      the next link element.
+ *
+ *      struct lbpath {
+ *              struct  lbpath  *next;
+ *              char            *path;
+ *      };
+ */
+struct  lbpath  *lbphead;       /*      pointer to the first
+                                 *      library path structure
+                                 */
+
+/*
+ *      The structure lbname is created for all combinations of the
+ *      library path specifications (input by the -k option) and the
+ *      library file specifications (input by the -l option) that
+ *      lead to an existing file.  The element path points to
+ *      the path string, element libfil points to the library
+ *      file string, and the element libspc is the concatenation
+ *      of the valid path and libfil strings.
+ *
+ *      The lbpath structures are linked into a list
+ *      using the next link element.
+ *
+ *      Each library file contains a list of object files
+ *      that are contained in the particular library. e.g.:
+ *
+ *              \iolib\termio
+ *              \inilib\termio
+ *
+ *      Only one specification per line is allowed.
+ *
+ *      struct lbname {
+ *              struct  lbname  *next;
+ *              char            *path;
+ *              char            *libfil;
+ *              char            *libspc;
+ *              char            f_obj;
+ *      };
+ */
+struct  lbname  *lbnhead;       /*      pointer to the first
+                                 *      library name structure
+                                 */
+
+/*
+ *      The function fndsym() searches through all combinations of the
+ *      library path specifications (input by the -k option) and the
+ *      library file specifications (input by the -l option) that
+ *      lead to an existing file for a symbol definition.
+ *
+ *      The structure lbfile is created for the first library
+ *      object file which contains the definition for the
+ *      specified undefined symbol.
+ *
+ *      The element libspc points to the library file path specification
+ *      and element relfil points to the object file specification string.
+ *      The element filspc is the complete path/file specification for
+ *      the library file to be imported into the linker.  The f_obj
+ *      flag specifies if the object code from this file is
+ *      to be output by the linker.  The file specification
+ *      may be formed in one of two ways:
+ *
+ *      (1)     If the library file contained an absolute
+ *              path/file specification then this becomes filspc.
+ *              (i.e. C:\...)
+ *
+ *      (2)     If the library file contains a relative path/file
+ *              specification then the concatenation of the path
+ *              and this file specification becomes filspc.
+ *              (i.e. \...)
+ *
+ *      The lbpath structures are linked into a list
+ *      using the next link element.
+ *
+ *      struct lbfile {
+ *              struct  lbfile  *next;
+ *              char            *libspc;
+ *              char            *relfil;
+ *              char            *filspc;
+ *              int             f_obj;
+ *      };
+ */
+struct  lbfile  *lbfhead;       /*      pointer to the first
+                                 *      library file structure
+                                 */
+/* sdld 8051 specific */
+char idatamap[256];
+/* end sdld 8051 specific */
+
+/*
+ *      array of character types, one per
+ *      ASCII character
+ */
+char   ctype[128] = {
+/*NUL*/ ILL,    ILL,    ILL,    ILL,    ILL,    ILL,    ILL,    ILL,
+/*BS*/  ILL,    SPACE,  ILL,    ILL,    SPACE,  ILL,    ILL,    ILL,
+/*DLE*/ ILL,    ILL,    ILL,    ILL,    ILL,    ILL,    ILL,    ILL,
+/*CAN*/ ILL,    ILL,    ILL,    ILL,    ILL,    ILL,    ILL,    ILL,
+/*SPC*/ SPACE,  ETC,    ETC,    ETC,    LETTER, BINOP,  BINOP,  ETC,
+/*(*/   ETC,    ETC,    BINOP,  BINOP,  ETC,    BINOP,  LETTER, BINOP,
+/*0*/   DGT2,   DGT2,   DGT8,   DGT8,   DGT8,   DGT8,   DGT8,   DGT8,
+/*8*/   DGT10,  DGT10,  ETC,    ETC,    BINOP,  ETC,    BINOP,  ETC,
+/*@*/   ETC,    LTR16,  LTR16,  LTR16,  LTR16,  LTR16,  LTR16,  LETTER,
+/*H*/   LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+/*P*/   LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+/*X*/   LETTER, LETTER, LETTER, BINOP,  ETC,    ETC,    BINOP,  LETTER,
+/*`*/   ETC,    LTR16,  LTR16,  LTR16,  LTR16,  LTR16,  LTR16,  LETTER,
+/*h*/   LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+/*p*/   LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+/*x*/   LETTER, LETTER, LETTER, ETC,    BINOP,  ETC,    ETC,    ETC
+};
+
+/*
+ *      an array of characters which
+ *      perform the case translation function
+ */
+char    ccase[128] = {
+/*NUL*/ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+/*BS*/  '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+/*DLE*/ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+/*CAN*/ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+/*SPC*/ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+/*(*/   '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+/*0*/   '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+/*8*/   '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+/*@*/   '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+/*H*/   '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+/*P*/   '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+/*X*/   '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+/*`*/   '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+/*h*/   '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+/*p*/   '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+/*x*/   '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177'
+};
diff --git a/Kernel/tools/bankld/lkelf.c b/Kernel/tools/bankld/lkelf.c
new file mode 100644 (file)
index 0000000..46c6914
--- /dev/null
@@ -0,0 +1,804 @@
+/* lkelf.c - Create an executable ELF/DWARF file
+
+   Copyright (C) 2004 Erik Petrich, epetrich at users dot sourceforge dot net
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <asxxxx_config.h>
+
+#include "aslink.h"
+
+static int execStartMSB;
+static int execStartLSB;
+static char execStartMSBfound;
+static char execStartLSBfound;
+
+typedef TYPE_UDWORD Elf32_Addr;
+typedef TYPE_WORD Elf32_Half;
+typedef TYPE_UDWORD Elf32_Off;
+typedef TYPE_DWORD Elf32_Sword;
+typedef TYPE_UDWORD Elf32_Word;
+
+enum
+{
+  EI_MAG0 = 0,
+  EI_MAG1,
+  EI_MAG2,
+  EI_MAG3,
+  EI_CLASS,
+  EI_DATA,
+  EI_VERSION,
+  EI_PAD,
+  EI_NIDENT = 16
+};
+
+enum
+{
+  ELFMAG0 = 0x7f,
+  ELFMAG1 = 'E',
+  ELFMAG2 = 'L',
+  ELFMAG3 = 'F'
+};
+
+enum
+{
+  ET_NONE = 0,
+  ET_REL,
+  ET_EXEC,
+  ET_DYN,
+  ET_CORE
+};
+
+/* These e_machine values are from "Motorola 8- and 16-bit Embedded */
+/* Application Binary Interface (M8/16EABI)" version 2.0 */
+enum
+{
+  EM_NONE = 0,
+  EM_68HC05 = 72,
+  EM_68HC08 = 71,
+  EM_68HC11 = 70,
+  EM_68HC12 = 53,
+  EM_68HC16 = 69
+};
+
+enum
+{
+  EV_NONE = 0,
+  EV_CURRENT
+};
+
+enum
+{
+  ELFCLASSNONE = 0,
+  ELFCLASS32,
+  ELFCLASS64
+};
+
+enum
+{
+  ELFDATANONE = 0,
+  ELFDATA2LSB,
+  ELFDATA2MSB
+};
+
+enum
+{
+  SHT_NULL = 0,
+  SHT_PROGBITS,
+  SHT_SYMTAB,
+  SHT_STRTAB,
+  SHT_RELA,
+  SHT_HASH,
+  SHT_DYNAMIC,
+  SHT_NOTE,
+  SHT_NOBITS,
+  SHT_REL,
+  SHT_SHLIB,
+  SHT_DYNSYM
+};
+
+enum
+{
+  SHF_WRITE = (1 << 0),
+  SHF_ALLOC = (1 << 1),
+  SHF_EXECINSTR = (1 << 2),
+};
+
+enum
+{
+  PT_NULL = 0,
+  PT_LOAD
+};
+
+enum
+{
+  PF_X = (1 << 0),
+  PF_W = (1 << 1),
+  PF_R = (1 << 2)
+};
+
+typedef struct
+{
+  unsigned char e_ident[EI_NIDENT];
+  Elf32_Half e_type;
+  Elf32_Half e_machine;
+  Elf32_Word e_version;
+  Elf32_Addr e_entry;
+  Elf32_Off e_phoff;
+  Elf32_Off e_shoff;
+  Elf32_Word e_flags;
+  Elf32_Half e_ehsize;
+  Elf32_Half e_phentsize;
+  Elf32_Half e_phnum;
+  Elf32_Half e_shentsize;
+  Elf32_Half e_shnum;
+  Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct
+{
+  Elf32_Word sh_name;
+  Elf32_Word sh_type;
+  Elf32_Word sh_flags;
+  Elf32_Addr sh_addr;
+  Elf32_Off sh_offset;
+  Elf32_Word sh_size;
+  Elf32_Word sh_link;
+  Elf32_Word sh_info;
+  Elf32_Word sh_addralign;
+  Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct
+{
+  Elf32_Word p_type;
+  Elf32_Off p_offset;
+  Elf32_Addr p_vaddr;
+  Elf32_Addr p_paddr;
+  Elf32_Word p_filesz;
+  Elf32_Word p_memsz;
+  Elf32_Word p_flags;
+  Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct strtabString
+{
+  char * string;
+  struct strtabString * prev;
+  struct strtabString * next;
+  Elf32_Word index;
+} strtabString;
+
+typedef struct
+{
+  strtabString * first;
+  strtabString * last;
+} strtabList;
+
+static strtabList shstrtab;
+
+
+typedef struct listEntry
+{
+  void * item;
+  struct listEntry * prev;
+  struct listEntry * next;
+} listEntry;
+
+typedef struct
+{
+  listEntry * first;
+  listEntry * last;
+  int count;
+} listHeader;
+
+
+
+static void
+listAdd (listHeader * lhp, void * item)
+{
+  listEntry * lep;
+
+  lep = (listEntry *)new (sizeof (*lep));
+  lep->item = item;
+  lep->prev = lhp->last;
+  if (lep->prev)
+    lep->prev->next = lep;
+
+  lhp->last = lep;
+  if (!lhp->first)
+    lhp->first = lep;
+
+  lhp->count++;
+}
+
+static listHeader *
+listNew (void)
+{
+  listHeader * lhp;
+
+  lhp = (listHeader *)new (sizeof (*lhp));
+
+  return lhp;
+}
+
+
+#if 0
+static Elf32_Word
+strtabFind (strtabList * strtab, char * str)
+{
+  strtabString * sp;
+  sp = strtab->first;
+
+  while (sp)
+    {
+      if (!strcmp (str, sp->string))
+        return sp->index;
+      sp = sp->next;
+    }
+
+  return 0;
+}
+#endif
+
+/*-------------------------------------------------------------------*/
+/* strtabFindOrAdd - Finds a string in a string table or adds the    */
+/*   string if it does not already exist. Returns the offset of the  */
+/*   string in the table.                                            */
+/*-------------------------------------------------------------------*/
+static Elf32_Word
+strtabFindOrAdd (strtabList * strtab, char * str)
+{
+  strtabString * sp;
+  sp = strtab->first;
+
+  while (sp)
+    {
+      if (!strcmp (str, sp->string))
+        return sp->index;
+      sp = sp->next;
+    }
+
+  sp = (strtabString *)new (sizeof(*sp));
+  if (strtab->last)
+    sp->index = strtab->last->index + 1 + strlen (strtab->last->string);
+  else
+    sp->index = 1;
+  sp->string = new (1+strlen (str));
+  strcpy (sp->string, str);
+
+  sp->prev = strtab->last;
+  if (sp->prev)
+    sp->prev->next = sp;
+  strtab->last = sp;
+  if (!strtab->first)
+    strtab->first = sp;
+
+  return sp->index;
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElfStrtab - writes a string table to a file                   */
+/*-------------------------------------------------------------------*/
+static void
+fputElfStrtab (strtabList *strtab, FILE *fp)
+{
+  strtabString * sp;
+
+  fputc (0, fp);        /* index 0 must be the null character */
+
+  sp = strtab->first;
+  while (sp)
+    {
+      fputs (sp->string, fp);
+      fputc (0, fp);
+      sp = sp->next;
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElf32_Word - writes an Elf32_Word value to a file             */
+/*-------------------------------------------------------------------*/
+static void
+fputElf32_Word (Elf32_Word x, FILE *fp)
+{
+  if (hilo == 0)
+    {
+      fputc (x & 0xff, fp);
+      fputc ((x >> 8) & 0xff, fp);
+      fputc ((x >> 16) & 0xff, fp);
+      fputc ((x >> 24) & 0xff, fp);
+    }
+  else
+    {
+      fputc ((x >> 24) & 0xff, fp);
+      fputc ((x >> 16) & 0xff, fp);
+      fputc ((x >> 8) & 0xff, fp);
+      fputc (x & 0xff, fp);
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElf32_Off - writes an Elf32_Off value to a file               */
+/*-------------------------------------------------------------------*/
+static void
+fputElf32_Off (Elf32_Off x, FILE *fp)
+{
+  if (hilo == 0)
+    {
+      fputc (x & 0xff, fp);
+      fputc ((x >> 8) & 0xff, fp);
+      fputc ((x >> 16) & 0xff, fp);
+      fputc ((x >> 24) & 0xff, fp);
+    }
+  else
+    {
+      fputc ((x >> 24) & 0xff, fp);
+      fputc ((x >> 16) & 0xff, fp);
+      fputc ((x >> 8) & 0xff, fp);
+      fputc (x & 0xff, fp);
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElf32_Addr - writes an Elf32_Addr value to a file             */
+/*-------------------------------------------------------------------*/
+static void
+fputElf32_Addr (Elf32_Addr x, FILE *fp)
+{
+  if (hilo == 0)
+    {
+      fputc (x & 0xff, fp);
+      fputc ((x >> 8) & 0xff, fp);
+      fputc ((x >> 16) & 0xff, fp);
+      fputc ((x >> 24) & 0xff, fp);
+    }
+  else
+    {
+      fputc ((x >> 24) & 0xff, fp);
+      fputc ((x >> 16) & 0xff, fp);
+      fputc ((x >> 8) & 0xff, fp);
+      fputc (x & 0xff, fp);
+    }
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElf32_Half - writes an Elf32_Half value to a file             */
+/*-------------------------------------------------------------------*/
+static void
+fputElf32_Half (Elf32_Half x, FILE *fp)
+{
+  if (hilo == 0)
+    {
+      fputc (x & 0xff, fp);
+      fputc ((x >> 8) & 0xff, fp);
+    }
+  else
+    {
+      fputc ((x >> 8) & 0xff, fp);
+      fputc (x & 0xff, fp);
+    }
+}
+
+/*------------------------------------------------------------------------*/
+/* fputElf32_Ehdr - writes an Elf32_Ehdr struct (ELF header) to a file    */
+/*------------------------------------------------------------------------*/
+static void
+fputElf32_Ehdr (Elf32_Ehdr * ehdr, FILE * fp)
+{
+  int i;
+
+  for (i=0; i<EI_NIDENT; i++)
+    fputc (ehdr->e_ident[i], fp);
+
+  fputElf32_Half (ehdr->e_type, fp);
+  fputElf32_Half (ehdr->e_machine, fp);
+  fputElf32_Word (ehdr->e_version, fp);
+  fputElf32_Addr (ehdr->e_entry, fp);
+  fputElf32_Off (ehdr->e_phoff, fp);
+  fputElf32_Off (ehdr->e_shoff, fp);
+  fputElf32_Word (ehdr->e_flags, fp);
+  fputElf32_Half (ehdr->e_ehsize, fp);
+  fputElf32_Half (ehdr->e_phentsize, fp);
+  fputElf32_Half (ehdr->e_phnum, fp);
+  fputElf32_Half (ehdr->e_shentsize, fp);
+  fputElf32_Half (ehdr->e_shnum, fp);
+  fputElf32_Half (ehdr->e_shstrndx, fp);
+}
+
+/*-------------------------------------------------------------------------*/
+/* fputElf32_Ehdr - writes an Elf32_Shdr struct (section header) to a file */
+/*-------------------------------------------------------------------------*/
+static void
+fputElf32_Shdr (Elf32_Shdr * shdr, FILE * fp)
+{
+  fputElf32_Word (shdr->sh_name, fp);
+  fputElf32_Word (shdr->sh_type, fp);
+  fputElf32_Word (shdr->sh_flags, fp);
+  fputElf32_Addr (shdr->sh_addr, fp);
+  fputElf32_Off (shdr->sh_offset, fp);
+  fputElf32_Word (shdr->sh_size, fp);
+  fputElf32_Word (shdr->sh_link, fp);
+  fputElf32_Word (shdr->sh_info, fp);
+  fputElf32_Word (shdr->sh_addralign, fp);
+  fputElf32_Word (shdr->sh_entsize, fp);
+}
+
+/*-------------------------------------------------------------------------*/
+/* fputElf32_Ehdr - writes an Elf32_Phdr struct (segment header) to a file */
+/*-------------------------------------------------------------------------*/
+static void
+fputElf32_Phdr (Elf32_Phdr * phdr, FILE * fp)
+{
+  fputElf32_Word (phdr->p_type, fp);
+  fputElf32_Off (phdr->p_offset, fp);
+  fputElf32_Addr (phdr->p_vaddr, fp);
+  fputElf32_Addr (phdr->p_paddr, fp);
+  fputElf32_Word (phdr->p_filesz, fp);
+  fputElf32_Word (phdr->p_memsz, fp);
+  fputElf32_Word (phdr->p_flags, fp);
+  fputElf32_Word (phdr->p_align, fp);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* elfGenerateAbs - generates segments and sections for an absolute area.   */
+/*   This is a little more complicated than a relative area since it may    */
+/*   contain noncontiguous regions.                                         */
+/*--------------------------------------------------------------------------*/
+static void
+elfGenerateAbs (struct area *ap, listHeader * segments, listHeader * sections)
+{
+  Elf32_Addr ofs;
+  Elf32_Addr addr;
+  Elf32_Word size;
+  Elf32_Phdr * phdrp;
+  Elf32_Shdr * shdrp;
+
+  if (!ap->a_image)
+    {
+      return;
+    }
+
+  ofs = 0;
+  for (;;)
+    {
+      /* Find the start of a contiguously */
+      /* used region within this area */
+      while (ofs < ap->a_imagesize && !ap->a_used[ofs])
+        ofs++;
+      if (ofs >= ap->a_imagesize)
+        return;
+
+      /* Find the end of the region */
+      addr = ap->a_addr + ofs;
+      while (ofs < ap->a_imagesize && ap->a_used[ofs])
+        ofs++;
+      size = ap->a_addr + ofs - addr;
+
+      /* create a segment header for this region if loadable */
+      if (!(ap->a_flag & A_NOLOAD))
+        {
+          phdrp = (Elf32_Phdr *)new (sizeof (*phdrp));
+          phdrp->p_type = PT_LOAD;
+          phdrp->p_offset = ftell (ofp);
+          phdrp->p_vaddr = addr;
+          phdrp->p_paddr = addr;
+          phdrp->p_filesz = size;
+          phdrp->p_memsz = size;
+          phdrp->p_flags = PF_R;
+          if (ap->a_flag & A_CODE)
+            phdrp->p_flags |= PF_X;
+          phdrp->p_align = 1;
+          listAdd (segments, phdrp);
+        }
+
+      /* create a section header for this region */
+      shdrp = (Elf32_Shdr *)new (sizeof (*shdrp));
+      shdrp->sh_name = strtabFindOrAdd (&shstrtab, ap->a_id);
+      shdrp->sh_type = SHT_PROGBITS;
+      shdrp->sh_flags = 0;
+      if (!(ap->a_flag & A_NOLOAD))
+        shdrp->sh_flags |= SHF_ALLOC;
+      if (ap->a_flag & A_CODE)
+        shdrp->sh_flags |= SHF_EXECINSTR;
+      shdrp->sh_addr = addr;
+      shdrp->sh_offset = ftell (ofp);
+      shdrp->sh_size = size;
+      shdrp->sh_link = 0;
+      shdrp->sh_info = 0;
+      shdrp->sh_addralign = 0;
+      shdrp->sh_entsize = 0;
+      listAdd (sections, shdrp);
+
+      fwrite (&ap->a_image[addr-ap->a_addr], 1, size, ofp);
+    }
+}
+
+/*--------------------------------------------------------------------------*/
+/* elfGenerateRel - generates a segment and section for a relative area.    */
+/*--------------------------------------------------------------------------*/
+static void
+elfGenerateRel (struct area *ap, listHeader * segments, listHeader * sections)
+{
+  Elf32_Phdr * phdrp;
+  Elf32_Shdr * shdrp;
+
+  if (!ap->a_image)
+    {
+      return;
+    }
+
+  /* create a segment header for this area if loadable */
+  if (!(ap->a_flag & A_NOLOAD))
+    {
+      phdrp = (Elf32_Phdr *)new (sizeof (*phdrp));
+      phdrp->p_type = PT_LOAD;
+      phdrp->p_offset = ftell (ofp);
+      phdrp->p_vaddr = ap->a_addr;
+      phdrp->p_paddr = ap->a_addr;
+      phdrp->p_filesz = ap->a_size;
+      phdrp->p_memsz = ap->a_size;
+      phdrp->p_flags = PF_R;
+      if (ap->a_flag & A_CODE)
+        phdrp->p_flags |= PF_X;
+      phdrp->p_align = 1;
+      listAdd (segments, phdrp);
+    }
+
+  /* create a section header for this area */
+  shdrp = (Elf32_Shdr *)new (sizeof (*shdrp));
+  shdrp->sh_name = strtabFindOrAdd (&shstrtab, ap->a_id);
+  shdrp->sh_type = SHT_PROGBITS;
+  shdrp->sh_flags = 0;
+  if (!(ap->a_flag & A_NOLOAD))
+    shdrp->sh_flags |= SHF_ALLOC;
+  if (ap->a_flag & A_CODE)
+    shdrp->sh_flags |= SHF_EXECINSTR;
+  shdrp->sh_addr = ap->a_addr;
+  shdrp->sh_offset = ftell (ofp);
+  shdrp->sh_size = ap->a_size;
+  shdrp->sh_link = 0;
+  shdrp->sh_info = 0;
+  shdrp->sh_addralign = 0;
+  shdrp->sh_entsize = 0;
+  listAdd (sections, shdrp);
+
+  fwrite (ap->a_image, 1, ap->a_size, ofp);
+}
+
+/*--------------------------------------------------------------------------*/
+/* elfGenerate - generates the complete ELF file                            */
+/*--------------------------------------------------------------------------*/
+static void
+elfGenerate (void)
+{
+  listHeader * sections = listNew();
+  listHeader * segments = listNew();
+  struct area *ap;
+  Elf32_Ehdr ehdr;
+  Elf32_Shdr * shdrp;
+  Elf32_Phdr * phdrp;
+  listEntry * lep;
+  int i;
+  Elf32_Word shstrtabName;
+
+  /* create the null section header for index 0 */
+  shdrp = (Elf32_Shdr *)new (sizeof (*shdrp));
+  shdrp->sh_name = 0;
+  shdrp->sh_type = SHT_NULL;
+  shdrp->sh_flags = 0;
+  shdrp->sh_addr = 0;
+  shdrp->sh_offset = 0;
+  shdrp->sh_size = 0;
+  shdrp->sh_link = 0;
+  shdrp->sh_info = 0;
+  shdrp->sh_addralign = 0;
+  shdrp->sh_entsize = 0;
+  listAdd (sections, shdrp);
+
+  /* Initialize the ELF header */
+  for (i=0; i<EI_NIDENT; i++)
+    ehdr.e_ident[i] = 0;
+  ehdr.e_ident[EI_MAG0] = ELFMAG0;
+  ehdr.e_ident[EI_MAG1] = ELFMAG1;
+  ehdr.e_ident[EI_MAG2] = ELFMAG2;
+  ehdr.e_ident[EI_MAG3] = ELFMAG3;
+  ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+  if (hilo == 0)
+    ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+  else
+    ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
+  ehdr.e_ident[EI_VERSION] = 1;
+  ehdr.e_type = ET_EXEC;
+  ehdr.e_machine = EM_68HC08; /* FIXME: get rid of hardcoded value - EEP */
+  ehdr.e_phentsize = sizeof (*phdrp);
+  ehdr.e_shentsize = sizeof (*shdrp);
+  ehdr.e_ehsize = sizeof (ehdr);
+  ehdr.e_phnum = 0;
+  ehdr.e_shnum = 0;
+  ehdr.e_shstrndx = 0;
+  ehdr.e_version = 1;
+  ehdr.e_entry = 0;
+  if (execStartMSBfound && execStartLSBfound)
+    ehdr.e_entry = (execStartMSB << 8) + execStartLSB;
+
+  /* Write out the ELF header as a placeholder; we will update */
+  /* it with the final values when everything is complete */
+  fputElf32_Ehdr (&ehdr, ofp);
+
+  /* Iterate over the linker areas to generate */
+  /* the ELF sections and segments */
+  ap = areap;
+  while (ap)
+    {
+      if (ap->a_size)
+        {
+          if (ap->a_flag & A3_ABS)
+            elfGenerateAbs (ap, segments, sections);
+          else
+            elfGenerateRel (ap, segments, sections);
+        }
+      ap = ap->a_ap;
+    }
+
+  /* Create the string table section after the other sections */
+  shdrp = (Elf32_Shdr *)new (sizeof (*shdrp));
+  shdrp->sh_name = strtabFindOrAdd (&shstrtab, ".shstrtab");
+  shdrp->sh_type = SHT_STRTAB;
+  shdrp->sh_flags = 0;
+  shdrp->sh_addr = 0;
+  shdrp->sh_offset = ftell (ofp);
+  shdrp->sh_size = shstrtab.last->index + strlen (shstrtab.last->string) + 1;
+  shdrp->sh_link = 0;
+  shdrp->sh_info = 0;
+  shdrp->sh_addralign = 0;
+  shdrp->sh_entsize = 0;
+  listAdd (sections, shdrp);
+  fputElfStrtab (&shstrtab, ofp);
+
+  /* Find the index of the section string table */
+  /* header and save it in the ELF header */
+  ehdr.e_shstrndx = 0;
+  shstrtabName = shdrp->sh_name;
+  lep = sections->first;
+  while (lep)
+    {
+      shdrp = lep->item;
+      if (shdrp->sh_name == shstrtabName)
+        break;
+      ehdr.e_shstrndx++;
+      lep = lep->next;
+    }
+
+  /* Write out the segment headers */
+  ehdr.e_phnum = segments->count;
+  ehdr.e_phoff = ftell (ofp);
+  lep = segments->first;
+  while (lep)
+    {
+      phdrp = lep->item;
+      fputElf32_Phdr (phdrp, ofp);
+      lep = lep->next;
+    }
+
+  /* Write out the section headers */
+  ehdr.e_shnum = sections->count;
+  ehdr.e_shoff = ftell (ofp);
+  lep = sections->first;
+  while (lep)
+    {
+      shdrp = lep->item;
+      fputElf32_Shdr (shdrp, ofp);
+      lep = lep->next;
+    }
+
+  /* All the values in the ELF header have now been computed; write */
+  /* over the placeholder header with the final values */
+  fseek (ofp, 0, SEEK_SET);
+  fputElf32_Ehdr (&ehdr, ofp);
+  fseek (ofp, 0, SEEK_END);
+}
+
+/*--------------------------------------------------------------------------*/
+/* elf - incrementally called by the linker core to generate ELF file data. */
+/*    The parameter is nonzero when there is data available and zero when   */
+/*    the linker is finished.                                               */
+/*--------------------------------------------------------------------------*/
+void
+elf (int i)
+{
+  a_uint address;
+
+  /* Buffer the data until we have it all */
+  if (i)
+    {
+      if (hilo == 0)
+        address = rtval[0] + (rtval[1] << 8); /* little endian order */
+      else
+        address = rtval[1] + (rtval[0] << 8); /* big endian order */
+
+      /* If this area doesn't have an image buffer, create one */
+      if (!ap->a_image)
+        {
+          if (ap->a_flag & A3_ABS)
+            ap->a_imagesize = ap->a_addr + ap->a_size;
+          else
+            ap->a_imagesize = ap->a_size;
+          ap->a_image = new (ap->a_imagesize);
+          if (ap->a_flag & A3_ABS)
+            ap->a_used = new (ap->a_imagesize);
+        }
+
+      /* Copy the data into the image buffer */
+      for (i = 2; i < rtcnt ; i++)
+        {
+          if (rtflg[i])
+            {
+              if (address-ap->a_addr >= ap->a_imagesize)
+                {
+                  a_uint newsize;
+
+                  if (ap->a_flag & A3_ABS)
+                    {
+                      newsize = ap->a_imagesize;
+                      while (address-ap->a_addr >= newsize)
+                        newsize = (newsize & ~4095)+4096;
+                      ap->a_image = (char *) realloc (ap->a_image, newsize);
+                      ap->a_used = (char *) realloc (ap->a_used, newsize);
+                      if (!ap->a_image || !ap->a_used)
+                        {
+                          fprintf (stderr, "Out of space!\n");
+                          lkexit (ER_FATAL);
+                        }
+                      memset (ap->a_image+ap->a_imagesize, 0, newsize-ap->a_imagesize);
+                      memset (ap->a_used+ap->a_imagesize, 0, newsize-ap->a_imagesize);
+                      ap->a_imagesize = newsize;
+                    }
+                  else
+                    {
+                      fprintf (stderr, "Unexpected area %s overflow. Address = 0x%x but allocated range is 0x%x - 0x%x\n",
+                               ap->a_id, address, ap->a_addr, ap->a_addr+ap->a_imagesize-1);
+                      lkexit (ER_FATAL);
+                    }
+                }
+              ap->a_image[address-ap->a_addr] = rtval[i];
+              if (ap->a_used)
+                ap->a_used[address-ap->a_addr] = 1;
+
+              /* Make note of the reset vector */
+              if (!(ap->a_flag & A_NOLOAD))
+                {
+                  if (address == 0xfffe)
+                    {
+                      execStartMSB = rtval[i];
+                      execStartMSBfound = 1;
+                    }
+                  if (address == 0xffff)
+                    {
+                      execStartLSB = rtval[i];
+                      execStartLSBfound = 1;
+                    }
+                }
+              address++;
+            }
+        }
+    }
+  else
+    elfGenerate();
+}
diff --git a/Kernel/tools/bankld/lkeval.c b/Kernel/tools/bankld/lkeval.c
new file mode 100644 (file)
index 0000000..e4662c9
--- /dev/null
@@ -0,0 +1,449 @@
+/* lkeval.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ */
+
+#include "aslink.h"
+
+/*)Module      lkeval.c
+ *
+ *     The module lkeval.c contains the routines to evaluate
+ *     arithmetic/numerical expressions.  The functions in
+ *     lkeval.c perform a recursive evaluation of the arithmetic
+ *     expression read from the input text line.
+ *     The expression may include binary/unary operators, brackets,
+ *     symbols, labels, and constants in hexadecimal, decimal, octal
+ *     and binary.  Arithmetic operations are prioritized and
+ *     evaluated by normal arithmetic conventions.
+ *
+ *     lkeval.c contains the following functions:
+ *             int     digit()
+ *             a_uint  eval()
+ *             a_uint  expr()
+ *             int     oprio()
+ *             a_uint  term()
+ *
+ *     lkeval.c contains no local/static variables
+ */
+
+/*)Function    a_uint  eval()
+ *
+ *     The function eval() evaluates a character string to a
+ *     numerical value.
+ *
+ *     Notes about the arithmetic:
+ *             The coding emulates X-Bit unsigned
+ *             arithmetic operations.  This allows
+ *             program compilation without regard to the
+ *             intrinsic integer length of the host
+ *             machine.
+ *
+ *     local variables:
+ *             int     c               character from input string
+ *             int     v               value of character in current radix
+ *             a_uint  n               evaluation value
+ *
+ *     global variables:
+ *             int     radix           current number conversion radix
+ *
+ *     functions called:
+ *             int     digit()         lkeval.c
+ *             int     get()           lklex.c
+ *             int     getnb()         lklex.c
+ *             VOID    unget()         lklex.c
+ *
+ *     side effects:
+ *             Input test is scanned and evaluated to a
+ *             numerical value.
+ */
+
+a_uint
+eval(void)
+{
+       int c, v;
+       a_uint n;
+
+       c = getnb();
+       n = 0;
+       while ((v = digit(c, radix)) >= 0) {
+               n = n*radix + v;
+               c = get();
+       }
+       unget(c);
+       return (n & a_mask);
+}
+
+/*)Function    a_uint  expr(n)
+ *
+ *             int     n               a firewall priority; all top
+ *                                     level calls (from the user)
+ *                                     should be made with n set to 0.
+ *
+ *     The function expr() evaluates an expression and
+ *     returns the value.
+ *
+ *     Notes about the arithmetic:
+ *             The coding emulates X-Bit unsigned
+ *             arithmetic operations.  This allows
+ *             program compilation without regard to the
+ *             intrinsic integer length of the host
+ *             machine.
+ *
+ *     local variables:
+ *             int     c               current input text character
+ *             int     p               current operator priority
+ *             a_uint  v               value returned by term()
+ *             a_uint  ve              value returned by a
+ *                                     recursive call to expr()
+ *
+ *     global variables:
+ *             char    ctype[]         array of character types, one per
+ *                                     ASCII character
+ *             int     lkerr           error flag
+ *             FILE *  stderr          c_library
+ *
+ *     functions called:
+ *             VOID    expr()          lkeval.c
+ *             int     fprintf()       c_library
+ *             int     getnb()         lklex.c
+ *             int     oprio()         lkeval.c
+ *             VOID    term()          lkeval.c
+ *             VOID    unget()         lklex.c
+ *
+ *
+ *     side effects:
+ *             An expression is evaluated by scanning the input
+ *             text string.
+ */
+
+a_uint
+expr (int n)
+{
+       int c, p;
+       a_uint v, ve;
+
+       v = term();
+       while (ctype[c = getnb()] & BINOP) {
+               if ((p = oprio(c)) <= n)
+                       break;
+               if ((c == '>' || c == '<') && c != get()) {
+                       fprintf(stderr, "Invalid expression");
+                       lkerr++;
+                       return(v);
+               }
+               ve = expr(p);
+
+               /*
+                * X-Bit Unsigned Arithmetic
+                */
+               v  &= a_mask;
+               ve &= a_mask;
+
+               if (c == '+') {
+                       v += ve;
+               } else
+               if (c == '-') {
+                       v -= ve;
+               } else {
+                       switch (c) {
+
+                       case '*':
+                               v *= ve;
+                               break;
+
+                       case '/':
+                               if (ve == 0) {
+                                       v = 0;
+                               } else {
+                                       v /= ve;
+                               }
+                               break;
+
+                       case '&':
+                               v &= ve;
+                               break;
+
+                       case '|':
+                               v |= ve;
+                               break;
+
+                       case '%':
+                               if (ve == 0) {
+                                       v = 0;
+                               } else {
+                                       v %= ve;
+                               }
+                               break;
+
+                       case '^':
+                               v ^= ve;
+                               break;
+
+                       case '<':
+                               v <<= ve;
+                               break;
+
+                       case '>':
+                               v >>= ve;
+                               break;
+                       }
+               }
+               v = (v & a_mask);
+       }
+       unget(c);
+       return(v);
+}
+
+/*)Function    a_uint  term()
+ *
+ *     The function term() evaluates a single constant
+ *     or symbol value prefaced by any unary operator
+ *     ( +, -, ~, ', ", >, or < ).
+ *
+ *     Notes about the arithmetic:
+ *             The coding emulates X-Bit unsigned
+ *             arithmetic operations.  This allows
+ *             program compilation without regard to the
+ *             intrinsic integer length of the host
+ *             machine.
+ *
+ *     local variables:
+ *             int     c               current character
+ *             char    id[]            symbol name
+ *             int     n               value of digit in current radix
+ *             int     r               current evaluation radix
+ *             sym *   sp              pointer to a sym structure
+ *             a_uint  v               evaluation value
+ *
+ *     global variables:
+ *             char    ctype[]         array of character types, one per
+ *                                     ASCII character
+ *             int     lkerr           error flag
+ *
+ *     functions called:
+ *             int     digit()         lkeval.c
+ *             VOID    expr()          lkeval.c
+ *             int     fprintf()       c_library
+ *             int     get()           lklex.c
+ *             VOID    getid()         lklex.c
+ *             int     getmap()        lklex.c
+ *             int     getnb()         lklex.c
+ *             sym *   lkpsym()        lksym.c
+ *             a_uint  symval()        lksym.c
+ *             VOID    unget()         lklex.c
+ *
+ *     side effects:
+ *             An arithmetic term is evaluated by scanning input text.
+ */
+
+a_uint
+term(void)
+{
+       int c, r, n;
+       a_uint v;
+       struct sym *sp;
+       char id[NCPS];
+
+       c = getnb();
+       if (c == '#') { c = getnb(); }
+       if (c == '(') {
+               v = expr(0);
+               if (getnb() != ')') {
+                       fprintf(stderr, "Missing delimiter");
+                       lkerr++;
+               }
+               return(v);
+       }
+       if (c == '-') {
+               return(~expr(100)+1);
+       }
+       if (c == '~') {
+               return(~expr(100));
+       }
+       if (c == '\'') {
+               v = getmap(-1)&0377;
+               c = get();
+               if (c != '\'') { unget(c); }
+               return(v);
+       }
+       if (c == '\"') {
+               if (hilo) {
+                       v  = (getmap(-1)&0377)<<8;
+                       v |=  getmap(-1)&0377;
+               } else {
+                       v  =  getmap(-1)&0377;
+                       v |= (getmap(-1)&0377)<<8;
+               }
+               c = get();
+               if (c != '\"') { unget(c); }
+               return(v & a_mask);
+       }
+       if (c == '>' || c == '<') {
+               v = expr(100);
+               if (c == '>')
+                       v >>= 8;
+               return(v&0377);
+       }
+       if (ctype[c] & DIGIT) {
+               r = 10;
+               if (c == '0') {
+                       c = get();
+                       switch (c) {
+                       case 'b':
+                       case 'B':
+                               r = 2;
+                               c = get();
+                               break;
+                       case '@':
+                       case 'o':
+                       case 'O':
+                       case 'q':
+                       case 'Q':
+                               r = 8;
+                               c = get();
+                               break;
+                       case 'd':
+                       case 'D':
+                               r = 10;
+                               c = get();
+                               break;
+                       case 'h':
+                       case 'H':
+                       case 'x':
+                       case 'X':
+                               r = 16;
+                               c = get();
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               v = 0;
+               while ((n = digit(c, r)) >= 0) {
+                       v = r*v + n;
+                       c = get();
+               }
+               unget(c);
+               return(v & a_mask);
+       }
+       if (ctype[c] & LETTER) {
+               getid(id, c);
+               if ((sp = lkpsym(id, 0)) == NULL) {
+                       fprintf(stderr, "Undefined symbol %s\n", id);
+                       lkerr++;
+                       return(0);
+               } else {
+                       return(symval(sp));
+               }
+       }
+       fprintf(stderr, "Unknown operator %c\n", c);
+       lkerr++;
+       return(0);
+}
+
+/*)Function    int     digit(c, r)
+ *
+ *             int     c               digit character
+ *             int     r               current radix
+ *
+ *     The function digit() returns the value of c
+ *     in the current radix r.  If the c value is not
+ *     a number of the current radix then a -1 is returned.
+ *
+ *     local variables:
+ *             none
+ *
+ *     global variables:
+ *             char    ctype[]         array of character types, one per
+ *                                     ASCII character
+ *
+ *     functions called:
+ *             none
+ *
+ *     side effects:
+ *             none
+ */
+
+int
+digit(int c, int r)
+{
+       if (r == 16) {
+               if (ctype[c] & RAD16) {
+                       if (c >= 'A' && c <= 'F')
+                               return (c - 'A' + 10);
+                       if (c >= 'a' && c <= 'f')
+                               return (c - 'a' + 10);
+                       return (c - '0');
+               }
+       } else
+       if (r == 10) {
+               if (ctype[c] & RAD10)
+                       return (c - '0');
+       } else
+       if (r == 8) {
+               if (ctype[c] & RAD8)
+                       return (c - '0');
+       } else
+       if (r == 2) {
+               if (ctype[c] & RAD2)
+                       return (c - '0');
+       }
+       return (-1);
+}
+
+/*)Function    int     oprio(c)
+ *
+ *             int     c               operator character
+ *
+ *     The function oprio() returns a relative priority
+ *     for all valid unary and binary operators.
+ *
+ *     local variables:
+ *             none
+ *
+ *     global variables:
+ *             none
+ *
+ *     functions called:
+ *             none
+ *
+ *     side effects:
+ *             none
+ */
+
+int
+oprio(int c)
+{
+       if (c == '*' || c == '/' || c == '%')
+               return (10);
+       if (c == '+' || c == '-')
+               return (7);
+       if (c == '<' || c == '>')
+               return (5);
+       if (c == '^')
+               return (4);
+       if (c == '&')
+               return (3);
+       if (c == '|')
+               return (1);
+       return (0);
+}
diff --git a/Kernel/tools/bankld/lkhead.c b/Kernel/tools/bankld/lkhead.c
new file mode 100644 (file)
index 0000000..f7970a0
--- /dev/null
@@ -0,0 +1,313 @@
+/* lkhead.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ */
+
+#include "aslink.h"
+
+/*Module       lkhead.c
+ *
+ *     The module lkhead.c contains the function newhead() which
+ *     creates a head structure, the function module() which
+ *     loads the module name into the current head structure,
+ *     and newmode() which loads the linker merge modes.
+ *
+ *     lkhead.c contains the following functions:
+ *             VOID    newhead()
+ *             VOID    newmode()
+ *             VOID    module()
+ *
+ *     lkhead.c contains no local variables.
+ */
+
+/*)Function    VOID    newhead()
+ *
+ *     The function newhead() creates a head structure.  All head
+ *     structures are linked to form a linked list of head structures
+ *     with the current head structure at the tail of the list.
+ *
+ *     local variables:
+ *             int     i               evaluation value
+ *             char    id[]            temporary string
+ *             head *  thp             temporary pointer
+ *                                     to a header structure
+ *
+ *     global variables:
+ *             area    *ap             Pointer to the current
+ *                                     area structure
+ *             lfile   *cfp            The pointer *cfp points to the
+ *                                     current lfile structure
+ *             head    *headp          The pointer to the first
+ *                                     head structure of a linked list
+ *             head    *hp             Pointer to the current
+ *                                     head structure
+ *
+ *     functions called:
+ *             a_uint  expr()          lkeval.c
+ *             a_uint  eval()          lkeval.c
+ *             VOID    getid()         lklex.c
+ *             VOID *  new()           lksym.c
+ *             VOID    lkparea()       lkarea.c
+ *             int     more()          lklex.c
+ *             int     symeq()         lksym.c
+ *
+ *     side effects:
+ *             A new head structure is created and linked to any
+ *             existing linked head structure.  The head structure
+ *             parameters of file handle, number of areas, number
+ *             of global symbols, number of banks and number of
+ *             merge modes are loaded into the structure.  The
+ *             area, bank, symbol, and mode structure lists are created.
+ *             The default area "_abs_" is created when the first
+ *             head structure is created and an areax structure is
+ *             created for every head structure called.
+ */
+
+/*
+ * Create a new header entry.
+ *
+ * H n areas n global symbols n banks n modes
+ *   |       |                |       |
+ *   |       |                |       `----- G Lines
+ *   |       |                `------------- B Lines
+ *   |      `------------------------------ hp->h_nsym
+ *   `-------------------------------------- hp->h_narea
+ *
+ */
+VOID
+newhead()
+{
+       int i;
+       char id[NCPS];
+       struct head *thp;
+
+       hp = (struct head *) new (sizeof(struct head));
+       if (headp == NULL) {
+               headp = hp;
+       } else {
+               thp = headp;
+               while (thp->h_hp)
+                       thp = thp->h_hp;
+               thp->h_hp = hp;
+       }
+       /*
+        * Initialize the header
+        */
+       hp->h_lfile = cfp;              /* Set file pointer */
+       hp->m_id = "";                  /* No Module */
+       /*
+        * Scan for Parameters   
+        */
+       while (more()) {
+               i = (int) eval();
+               getid(id, -1);
+               /*
+                * Area pointer list
+                */
+               if (symeq("areas", id, 1)) {
+                       hp->h_narea = i;
+                       if (i)
+                               hp->a_list = (struct areax **) new (i*sizeof(struct areax *));
+               } else
+               /*
+                * Symbol pointer list
+                */
+               if (symeq("global", id, 1)) {
+                       hp->h_nsym = i;
+                       if (i)
+                               hp->s_list = (struct sym **) new (i*sizeof(struct sym *));
+                       skip(-1);
+               } else
+               /*
+                * Bank pointer list
+                */
+               if (symeq("banks", id, 1)) {
+                       hp->h_nbank = i;
+                       if (i)
+                               hp->b_list = (struct bank **) new (i*sizeof(struct bank *));
+               } else
+               /*
+                * Mode pointer list
+                */
+               if (symeq("modes", id, 1)) {
+                       hp->h_nmode = i;
+                       if (i)
+                               hp->m_list = (struct mode **) new (i*sizeof(struct mode *));
+               }
+       }
+       /*
+        * Setup Absolute DEF linkage.
+        */
+       lkparea(_abs_);
+       ap->a_flag = A3_ABS;
+       axp->a_addr = 0;
+}
+
+
+/*)Function    VOID    newmode()
+ *
+ *     The function newmode() creates / fills in a merge mode
+ *     definition for this module.
+ *
+ *     The MODE structure contains the specification of one of the
+ *     assemblers' relocation modes.  Each assembler must specify
+ *     at least one relocation mode.  The relocation specification
+ *     allows arbitrarily defined active bits and bit positions.
+ *     The 32 element arrays are indexed from 0 to 31.
+ *     Index 0 corresponds to bit 0, ..., and 31 corresponds to bit 31
+ *     of a normal integer value.
+ *
+ *     The value an array element defines if the normal integer bit is
+ *     active (bit <7> is set, 0x80) and what destination bit
+ *     (bits <4:0>, 0 - 31) should be loaded with this normal
+ *     integer bit.
+ *
+ *     The mode structure also contains a flag indicating if bit
+ *     positioning is required, a mask word containing the active
+ *     bits for merging, and an address paging mask.
+ *
+ *     local variables:
+ *             int     index           bit index of mode definition
+ *             int     n               counter
+ *             struct mode *mp         pointer to a mode structure
+ *
+ *     global variables:
+ *             head    *headp          The pointer to the first
+ *                                     head structure of a linked list
+ *             head    *hp             Pointer to the current
+ *                                     head structure
+ *             FILE *  stderr          standard library error handle
+ *
+ *     functions called:
+ *             a_uint  eval()          lkexpr.c
+ *             int     fprintf()       c_library
+ *             VOID    lkexit()        lkmain.c
+ *             int     more()          lklex.c
+ *             char *  new()           lksym.c
+ *
+ *     side effects:
+ *             The merge mode structure is created / updated with
+ *             the definition values.
+ */
+
+VOID
+newmode()
+{
+       int index, n;
+       a_uint v;
+       struct mode *mp;
+
+       if (headp == NULL) {
+               fprintf(stderr, "No header defined\n");
+               lkexit(ER_FATAL);
+       }
+       /*
+        * Mode number
+        */
+       n = (int) eval();
+       if (n >= hp->h_nmode) {
+               fprintf(stderr, "Header mode list overflow\n");
+               lkexit(ER_FATAL);
+       }
+       /*
+        * Bit index
+        */
+       index = (int) eval();
+       if (index == 0) {
+               mp = (struct mode *) new (sizeof(struct mode));
+               hp->m_list[n] = mp;
+               /*
+                * Initialize Mode
+                */
+               for (n=0; n<32; n++) {
+                       mp->m_def[n] = n;
+               }
+       } else {
+               mp = hp->m_list[n];
+       }
+       /*
+        * Load Bits
+        */
+       while (more() && (index < 32)) {
+               n = (int) eval();
+               if (mp->m_def[index] != (n & 0x1F)) {
+                       mp->m_flag |= 1;
+               }
+               mp->m_def[index] = n;
+               if (n & 0x80) {
+                       mp->m_dbits |= (((a_uint) 1) << (n & 0x1F));
+                       mp->m_sbits |= (((a_uint) 1) << index);
+               }
+               index += 1;
+       }
+       /*
+        * Set Missing Low Order Bits
+        */
+       for (n=0; n<32; n++) {
+               v = 1 << n;
+               if (mp->m_sbits & v) {
+                       break;
+               } else {
+                       mp->m_sbits |= v;
+               }
+       }
+}
+
+
+/*)Function    VOID    module()
+ *
+ *     The function module() copies the module name into
+ *     the current head structure.
+ *
+ *     local variables:
+ *             char    id[]            module id string
+ *
+ *     global variables:
+ *             head    *headp          The pointer to the first
+ *                                     head structure of a linked list
+ *             head    *hp             Pointer to the current
+ *                                     head structure
+ *             int     lkerr           error flag
+ *             FILE *  stderr          c_library
+ *
+ *     functions called:
+ *             int     fprintf()       c_library
+ *             VOID    getid()         lklex.c
+ *             char *  strsto()        lksym.c
+ *
+ *     side effects:
+ *             The module name is copied into the head structure.
+ */
+
+VOID
+module()
+{
+       char id[NCPS];
+
+       if (headp) {
+               getid(id, -1);
+               hp->m_id = strsto(id);
+       } else {
+               fprintf(stderr, "No header defined\n");
+               lkerr++;
+       }
+}
diff --git a/Kernel/tools/bankld/lkihx.c b/Kernel/tools/bankld/lkihx.c
new file mode 100644 (file)
index 0000000..355c96f
--- /dev/null
@@ -0,0 +1,278 @@
+/* lkihx.c
+
+   Copyright (C) 1989-1995 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+#include "sdld.h"
+#include "aslink.h"
+
+/*)Module   lkihx.c
+ *
+ *  The module lkihx.c contains the function to
+ *  output the relocated object code in the
+ *  Intel Hex format.
+ *
+ *  lkihx.c contains the following functions:
+ *      VOID    hexRecord(addr, rtvalIndex)
+ *      VOID    ihx(i)
+ *      VOID    ihxExtendedLinearAddress(a)
+ *
+ *  local variables: hexPageOverrun, lastHexAddr
+ */
+
+/*Intel Format
+ *      Record Mark Field    -  This  field  signifies  the  start  of a
+ *                              record, and consists of an  ascii  colon
+ *                              (:).
+ *
+ *      Record Length Field  -  This   field   consists   of  two  ascii
+ *                              characters which indicate the number  of
+ *                              data   bytes   in   this   record.   The
+ *                              characters are the result of  converting
+ *                              the  number  of  bytes  in binary to two
+ *                              ascii characters, high digit first.   An
+ *                              End  of  File  record contains two ascii
+ *                              zeros in this field.
+ *
+ *      Load Address Field   -  This  field  consists  of the four ascii
+ *                              characters which result from  converting
+ *                              the  the  binary value of the address in
+ *                              which to begin loading this record.  The
+ *                              order is as follows:
+ *
+ *                                  High digit of high byte of address.
+ *                                  Low digit of high byte of address.
+ *                                  High digit of low byte of address.
+ *                                  Low digit of low byte of address.
+ *
+ *                              In an End of File record this field con-
+ *                              sists of four ascii zeros, in a start
+ *                             address record this is the program entry
+ *                             address (low), or in a segment record
+ *                             this is the high order address.
+ *
+ *      Record Type Field    -  This  field  identifies the record type,
+ *                              which is either 0 for data records,  1
+ *                              for an End of File record, 3 for a
+ *                             start address, or 4 for a
+ *                             segment record.  It consists
+ *                              of two ascii characters, with  the  high
+ *                              digit of the record type first, followed
+ *                              by the low digit of the record type.
+ *
+ *      Data Field           -  This  field consists of the actual data,
+ *                              converted to two ascii characters,  high
+ *                              digit first.  There are no data bytes in
+ *                              the End of File record.
+ *
+ *      Checksum Field       -  The  checksum  field is the 8 bit binary
+ *                              sum of the record length field, the load
+ *                              address  field,  the  record type field,
+ *                              and the data field.  This  sum  is  then
+ *                              negated  (2's  complement) and converted
+ *                              to  two  ascii  characters,  high  digit
+ *                              first.
+ */
+
+/* Static variable which holds the count of hex page overruns
+ * (crossings of the 64kB boundary). Cleared at explicit extended
+ * address output.
+ */
+static int hexPageOverrun = 0;
+
+/* Global which holds the last (16 bit) address of hex record.
+ * Cleared at begin of new area or when the extended address is output.
+ */
+unsigned int lastHexAddr = 0;
+
+
+/*)Function hexRecord(addr, rtvalIndex)
+ *
+ *      unsigned addr       starting address of hex record
+ *      int rtvalIndex      starting index into the rtval[] array
+ *
+ *  The function hexRecord() outputs the relocated data
+ *  in the standard Intel Hex format (with inserting
+ *  the extended address record if necessary).
+ *
+ *  local variables:
+ *      a_uint  chksum      byte checksum
+ *      int     i           index for loops
+ *      int     overrun     temporary storage for hexPageOverrun
+ *      int     bytes       counter for bytes written
+ *
+ *  global variables:
+ *      FILE *  ofp         output file handle
+ *      int     rtcnt       count of data words
+ *      int     rtflg[]     output the data flag
+ *      a_uint  rtval[]     relocated data
+ *
+ *  functions called:
+ *      int     fprintf()           c_library
+ *      ihxExtendedLinearAddress()  lkihx.c
+ *      hexRecord()                 lkihx.c     (recursion)
+ *
+ *  side effects:
+ *      hexPageOverrun is eventually incremented,
+ *      lastHexAddr is updated
+ */
+
+VOID
+hexRecord(unsigned addr, int rtvalIndex)
+{
+    a_uint chksum;
+    int i, overrun, bytes;
+
+    for (i = rtvalIndex, chksum = 0; i < rtcnt; i++) {
+        if (rtflg[i]) {
+            if (addr + ++chksum > 0xffff)
+                break;
+        }
+    }
+    if (chksum == 0)
+        return;         // nothing to output
+
+    /* Is this record in the same bank as previous? */
+    if ((TARGET_IS_8051 && ((lastHexAddr>>16) != (addr>>16)) && (rflag)) ||
+        (TARGET_IS_6808 && lastHexAddr > addr) {
+        overrun = hexPageOverrun + 1;
+        ihxExtendedLinearAddress(lastExtendedAddress + overrun);
+        hexPageOverrun = overrun;
+        hexRecord(addr, rtvalIndex);
+        return;
+    }
+
+    lastHexAddr = addr;
+    fprintf(ofp, "%02X:%02X%04X00", addr >>16, chksum, addr);
+    chksum += (addr >> 8) + (addr & 0xff);
+    for (i = rtvalIndex, bytes = 0; i < rtcnt; i++) {
+        if (rtflg[i]) {
+            fprintf(ofp, "%02X", rtval[i]);
+            chksum += rtval[i];
+            if (TARGET_IS_8051) {
+                if (addr + ++bytes > 0xffff) {
+                    if (rflag) {
+                        fprintf(ofp, "%02X\n", (0-chksum) & 0xff);
+                        overrun = hexPageOverrun + 1;
+                        ihxExtendedLinearAddress(lastExtendedAddress + overrun);
+                        hexPageOverrun = overrun;
+                        hexRecord(0, i + 1);
+                        return;
+                    } else {
+                        fprintf(stderr,
+                            "warning: extended linear address encountered; "
+                            "you probably want the -r flag.\n");
+                    }
+                }
+            }
+        }
+    }
+    fprintf(ofp, "%02X\n", (0-chksum) & 0xff);
+}
+
+/*)Function ihx(i)
+ *
+ *      int     i           0 - process data
+ *                          1 - end of data
+ *
+ *  The function ihx() calls the hexRecord() function for processing data
+ *  or writes the End of Data record to the file defined by ofp.
+ *
+ *  local variables:
+ *      a_uint  n           auxiliary variable
+ *
+ *  global variables:
+ *      int     hilo        byte order
+ *      FILE *  ofp         output file handle
+ *      a_uint  rtval[]     relocated data
+ *
+ *  functions called:
+ *      VOID hexRecord()    lkihx.c
+ *      int fprintf()       c_library
+ *
+ *  side effects:
+ *      The sequence of rtval[0], rtval[1] is eventually changed.
+ */
+
+VOID
+ihx(int i)
+{
+    a_uint n;
+    if (i) {
+        if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD)
+            return;
+
+        if (hilo == 0) {
+            n = rtval[0];
+            rtval[0] = rtval[1];
+            rtval[1] = n;
+        }
+        hexRecord((rtval[0]<<8) + rtval[1], 2);
+    } else {
+        if (TARGET_IS_8051 && rflag) /* linear start address, hardcoded as reset vector (0x0000) */
+            fprintf(ofp, ":0400000500000000F7\n");
+        fprintf(ofp, ":00000001FF\n");
+    }
+}
+
+/*)Function ihxNewArea(i)
+ * The function ihxNewArea() is called when processing of new area is started.
+ * It resets the value of lastHexAddr.
+ */
+
+VOID
+ihxNewArea()
+{
+    lastHexAddr = 0;
+}
+
+/*)Function ihxExtendedLinearAddress(i)
+ *
+ *      a_uint  i           16 bit extended linear address.
+ *
+ *  The function ihxExtendedLinearAddress() writes an extended
+ *  linear address record (type 04) to the output file.
+ *
+ *  local variables:
+ *      a_uint  chksum      byte checksum
+ *
+ *  global variables:
+ *      FILE *  ofp         output file handle
+ *
+ *  functions called:
+ *      int     fprintf()   c_library
+ *
+ *  side effects:
+ *      The data is output to the file defined by ofp.
+ *      hexPageOverrun and lastHexAddr is cleared
+ */
+VOID
+ihxExtendedLinearAddress(a_uint a)
+{
+    a_uint  chksum;
+
+    /* The checksum is the complement of the bytes in the
+     * record: the 2 is record length, 4 is the extended linear
+     * address record type, plus the two address bytes.
+     */
+    chksum = 2 + 4 + (a & 0xff) + ((a >> 8) & 0xff);
+
+    fprintf(ofp, ":02000004%04X%02X\n", a & 0xffff, (0-chksum) & 0xff);
+    hexPageOverrun = 0;
+    lastHexAddr = 0;
+}
diff --git a/Kernel/tools/bankld/lklex.c b/Kernel/tools/bankld/lklex.c
new file mode 100644 (file)
index 0000000..6979c92
--- /dev/null
@@ -0,0 +1,669 @@
+/* lklex.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ */
+
+#include "aslink.h"
+
+/*)Module       lklex.c
+ *
+ *      The module lklex.c contains the general lexical analysis
+ *      functions used to scan the text lines from the .rel files.
+ *
+ *      lklex.c contains the following functions:
+ *              VOID    chopcrlf()
+ *              char    endline()
+ *              int     get()
+ *              VOID    getfid()
+ *              VOID    getid()
+ *              VOID    getSid()
+ *              int     getmap()
+ *              int     getnb()
+ *              int     more()
+ *              int     nxtline()
+ *              VOID    skip()
+ *              VOID    unget()
+ *
+ *      lklex.c contains no local variables.
+ */
+
+/*)Function     VOID    getid(id,c)
+ *
+ *              char *  id              a pointer to a string of
+ *                                      maximum length NCPS-1
+ *              int     c               mode flag
+ *                                      >=0     this is first character to
+ *                                              copy to the string buffer
+ *                                      <0      skip white space
+ *
+ *      The function getid() scans the current input text line
+ *      from the current position copying the next LETTER | DIGIT string
+ *      into the external string buffer (id).  The string ends when a non
+ *      LETTER or DIGIT character is found. The maximum number of characters
+ *      copied is NCPS-1.  If the input string is larger than NCPS-1
+ *      characters then the string is truncated.  The string is always
+ *      NULL terminated.  If the mode argument (c) is >=0 then (c) is
+ *      the first character copied to the string buffer, if (c) is <0
+ *      then intervening white space (SPACES and TABS) are skipped.
+ *
+ *      local variables:
+ *              char *  p               pointer to external string buffer
+ *              int     c               current character value
+ *
+ *      global variables:
+ *              char    ctype[]         a character array which defines the
+ *                                      type of character being processed.
+ *                                      This index is the character
+ *                                      being processed.
+ *
+ *      called functions:
+ *              int     get()           lklex.c
+ *              int     getnb()         lklex.c
+ *              VOID    unget()         lklex.c
+ *
+ *      side effects:
+ *              use of getnb(), get(), and unget() updates the
+ *              global pointer ip the position in the current
+ *              input text line.
+ */
+
+VOID
+getid(char *id, int c)
+{
+        char *p;
+
+        if (c < 0) {
+                c = getnb();
+        }
+        p = id;
+        do {
+                if (p < &id[NCPS-1])
+                        *p++ = c;
+        } while (ctype[c=get()] & (LETTER|DIGIT));
+        unget(c);
+        *p++ = 0;
+}
+
+/*)Function     VOID    getSid (char *id)
+ *
+ *              char *  id              a pointer to a string of
+ *                                      maximum length NCPS-1
+ *
+ *  getSid is derived from getid. It is called from newsym()
+ *  in lksym.c, when an S-record has to be scanned. getSid accepts
+ *  much more characters than getid, which is necessary for SDCC.
+ *
+ *      The function getSid() scans the current input text line
+ *      from the current position copying the next string
+ *      into the external string buffer (id).  The string ends when a space
+ *      character (space, tab, \0) is found. The maximum number of
+ *      characters copied is NCPS.  If the input string is larger than
+ *      NCPS characters then the string is truncated, if the input string
+ *      is shorter than NCPS characters then the string is NULL filled.
+ *      Intervening white space (SPACES and TABS) are skipped.
+ *
+ *      local variables:
+ *              char *  p               pointer to external string buffer
+ *              int     c               current character value
+ *
+ *      global variables:
+ *              none
+ *
+ *      called functions:
+ *              int     get()           lklex.c
+ *              int     getnb()         lklex.c
+ *              VOID    unget()         lklex.c
+ *
+ *      side effects:
+ *              use of getnb(), get(), and unget() updates the
+ *              global pointer ip the position in the current
+ *              input text line.
+ */
+
+VOID
+getSid (char *id)
+{
+        int c;
+        char *p;
+
+        c = getnb();
+        p = id;
+        do {
+                if (p < &id[NCPS-1])
+                        *p++ = c;
+                c = get();
+        } while (c != '\0' && c != ' ' && c != '\t');
+        unget(c);
+        *p++ = 0;
+}
+
+/*)Function     VOID    getfid(str,c)
+ *
+ *              char *  str             a pointer to a string of
+ *                                      maximum length FILSPC-1
+ *              int     c               this is first character to
+ *                                      copy to the string buffer
+ *
+ *      asxxxx version:
+ *
+ *      The function getfid() copies a string of characters from
+ *      the current text line into the external string buffer (str).
+ *      The maximum number of characters copied is FILSPC-1.  The
+ *      string is terminated by a 'space', 'tab' or end of string.
+ *
+ *      sdld version:
+ *
+ *      The function getfid() scans the current input text line from
+ *      the current position copying the next string into the external
+ *      string buffer (str).  The string ends when end of line is found.
+ *      Trailing spaces are removed. The maximum number of characters
+ *      copied is FILSPC-1. If the input string is larger than FILSPC-1
+ *      characters then the string is truncated. The string is NULL
+ *      terminated.
+ *
+ *      local variables:
+ *              char *  p               pointer to external string buffer
+ *              int     c               current character value
+ *
+ *      global variables:
+ *              char    ctype[]         a character array which defines the
+ *                                      type of character being processed.
+ *                                      This index is the character
+ *                                      being processed.
+ *
+ *      called functions:
+ *              int     get()           lklex.c
+ *
+ *      side effects:
+ *              use of get() updates the global pointer ip
+ *              the position in the current input text line.
+ */
+
+VOID
+getfid(char *str, int c)
+{
+        char *p;
+
+        p = str;
+        if (!is_sdld()) {
+                do {
+                        if (p < &str[FILSPC-1])
+                                *p++ = c;
+                        c = get();
+                } while ((c != 0) && (c != ' ') && (c != '\t'));
+                *p++ = 0;
+        }
+        else {
+                do {
+                        if (p < &str[FILSPC-1])
+                                *p++ = c;
+                        c = get();
+                        /* skip comment */
+                        if (c == ';')
+                                while (c)
+                                        c = get();
+                } while (c);
+                /* trim trailing spaces */
+                --p;
+                while (p >= str && ctype[*p & 0x007F] == SPACE)
+                        --p;
+                /* terminate the string */
+                *(++p) = '\0';
+        }
+}
+
+/*)Function     int     getnb()
+ *
+ *      The function getnb() scans the current input text
+ *      line returning the first character not a SPACE or TAB.
+ *
+ *      local variables:
+ *              int     c               current character from input
+ *
+ *      global variables:
+ *              none
+ *
+ *      called functions:
+ *              int     get()           lklex.c
+ *
+ *      side effects:
+ *              use of get() updates the global pointer ip, the position
+ *              in the current input text line
+ */
+
+int
+getnb()
+{
+        int c;
+
+        while ((c=get())==' ' || c=='\t')
+                ;
+        return (c);
+}
+
+/*)Function     VOID    skip(c)
+ *
+ *      The function skip() scans the input text skipping all
+ *      letters and digits.
+ *
+ *      local variables:
+ *              int     c               last character read
+ *              none
+ *
+ *      global variables:
+ *              char    ctype[]         array of character types, one per
+ *                                      ASCII character
+ *
+ *      functions called:
+ *              int     get()           lklex.c
+ *              int     getnb()         lklex.c
+ *              VOID    unget()         lklex.c
+ *
+ *      side effects:
+ *              Input letters and digits are skipped.
+ */
+
+VOID
+skip(c)
+int c;
+{
+        if (c < 0)
+                c = getnb();
+        while (ctype[c=get()] & (LETTER|DIGIT)) { ; }
+        unget(c);
+}
+
+/*)Function     int     get()
+ *
+ *      The function get() returns the next character in the
+ *      input text line, at the end of the line a
+ *      NULL character is returned.
+ *
+ *      local variables:
+ *              int     c               current character from
+ *                                      input text line
+ *
+ *      global variables:
+ *              char *  ip              pointer into the current
+ *                                      input text line
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              updates ip to the next character position in the
+ *              input text line.  If ip is at the end of the
+ *              line, ip is not updated.
+ */
+
+int
+get()
+{
+        int c;
+
+        if ((c = *ip) != 0)
+                ++ip;
+        return (c & 0x007F);
+}
+
+/*)Function     VOID    unget(c)
+ *
+ *              int     c               value of last character
+ *                                      read from input text line
+ *
+ *      If (c) is not a NULL character then the global pointer ip
+ *      is updated to point to the preceeding character in the
+ *      input text line.
+ *
+ *      NOTE:   This function does not push the character (c)
+ *              back into the input text line, only
+ *              the pointer ip is changed.
+ *
+ *      local variables:
+ *              int     c               last character read
+ *                                      from input text line
+ *
+ *      global variables:
+ *              char *  ip              position into the current
+ *                                      input text line
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              ip decremented by 1 character position
+ */
+
+VOID
+unget(c)
+int c;
+{
+        if (c != 0)
+                --ip;
+}
+
+/*)Function     int     getmap(d)
+ *
+ *              int     d               value to compare with the
+ *                                      input text line character
+ *
+ *      The function getmap() converts the 'C' style characters \b, \f,
+ *      \n, \r, and \t to their equivalent ascii values and also
+ *      converts 'C' style octal constants '\123' to their equivalent
+ *      numeric values.  If the first character is equivalent to (d) then
+ *      a (-1) is returned, if the end of the line is detected then
+ *      a 'q' error terminates the parse for this line, or if the first
+ *      character is not a \ then the character value is returned.
+ *
+ *      local variables:
+ *              int     c               value of character
+ *                                      from input text line
+ *              int     n               looping counter
+ *              int     v               current value of numeric conversion
+ *
+ *      global variables:
+ *              none
+ *
+ *      called functions:
+ *              int     get()           lklex.c
+ *              VOID    unget()         lklex.c
+ *
+ *      side effects:
+ *              use of get() updates the global pointer ip the position
+ *              in the current input text line
+ */
+
+int
+getmap(d)
+int d;
+{
+        int c, n, v;
+
+        if ((c = get()) == '\0')
+                return (-1);
+        if (c == d)
+                return (-1);
+        if (c == '\\') {
+                c = get();
+                switch (c) {
+
+                case 'b':
+                        c = '\b';
+                        break;
+
+                case 'f':
+                        c = '\f';
+                        break;
+
+                case 'n':
+                        c = '\n';
+                        break;
+
+                case 'r':
+                        c = '\r';
+                        break;
+
+                case 't':
+                        c = '\t';
+                        break;
+
+                case '0':
+                case '1':
+                case '2':
+                case '3':
+                case '4':
+                case '5':
+                case '6':
+                case '7':
+                        n = 0;
+                        v = 0;
+                        while (++n<=3 && c>='0' && c<='7') {
+                                v = (v<<3) + c - '0';
+                                c = get();
+                        }
+                        unget(c);
+                        c = v;
+                        break;
+                }
+        }
+        return (c);
+}
+
+/*)Function     int     nxtline()
+ *
+ *      The function nxtline() reads a line of input text from a
+ *      .rel source text file, a .lnk command file or from stdin.
+ *      Lines of text are processed from a single .lnk file or
+ *      multiple .rel files until all files have been read.
+ *      The input text line is copied into the global string ib[]
+ *      and converted to a NULL terminated string.  The function
+ *      nxtline() returns a (1) after succesfully reading a line
+ *      or a (0) if all files have been read.
+ *      This function also opens each input .lst file and output
+ *      .rst file as each .rel file is processed.
+ *
+ *      local variables:
+ *              int     ftype           file type
+ *              char *  fid             file name
+ *
+ *      global variables:
+ *              lfile   *cfp            The pointer *cfp points to the
+ *                                      current lfile structure
+ *              lfile   *filep          The pointer *filep points to the
+ *                                      beginning of a linked list of
+ *                                      lfile structures.
+ *              int     gline           get a line from the LST file
+ *                                      to translate for the RST file
+ *              char    ib[NINPUT]      REL file text line
+ *              int     pass            linker pass number
+ *              int     pflag           print linker command file flag
+ *              FILE    *rfp            The file handle to the current
+ *                                      output RST file
+ *              FILE    *sfp            The file handle sfp points to the
+ *                                      currently open file
+ *              FILE *  stdin           c_library
+ *              FILE *  stdout          c_library
+ *              FILE    *tfp            The file handle to the current
+ *                                      LST file being scanned
+ *              int     uflag           update listing flag
+ *              int     obj_flag        linked file/library object output flag
+ *
+ *      called functions:
+ *              VOID    chopcrlf()      lklex.c
+ *              FILE *  afile()         lkmain.c
+ *              int     fclose()        c_library
+ *              char *  fgets()         c_library
+ *              int     fprintf()       c_library
+ *              VOID    lkulist()       lklist.c
+ *              VOID    lkexit()        lkmain.c
+ *
+ *      side effects:
+ *              The input stream is scanned.  The .rel files will be
+ *              opened and closed sequentially scanning each in turn.
+ */
+
+int
+nxtline()
+{
+        int ftype;
+        char *fid;
+
+loop:   if (pflag && cfp && cfp->f_type == F_STD)
+                fprintf(stdout, "ASlink >> ");
+
+        if (sfp == NULL || fgets(ib, sizeof(ib), sfp) == NULL) {
+                obj_flag = 0;
+                if (sfp) {
+                        if(sfp != stdin) {
+                                fclose(sfp);
+                        }
+                        sfp = NULL;
+                        lkulist(0);
+                }
+                if (cfp == NULL) {
+                        cfp = filep;
+                } else {
+                        cfp = cfp->f_flp;
+                }
+                if (cfp) {
+                        ftype = cfp->f_type;
+                        fid = cfp->f_idp;
+                        if (ftype == F_STD) {
+                                sfp = stdin;
+                        } else
+                        if (ftype == F_LNK) {
+                                sfp = afile(fid, strrchr(fid, FSEPX) ? "" : "lnk", 0);
+                        } else
+                        if (ftype == F_REL) {
+                                obj_flag = cfp->f_obj;
+                                sfp = afile(fid, "", 0);
+                                if (sfp && (obj_flag == 0)) {
+                                        if (uflag && (pass != 0)) {
+                                                if (is_sdld())
+                                                        SaveLinkedFilePath(fid); //Save the linked path for aomf51
+                                                if ((tfp = afile(fid, "lst", 0)) != NULL) {
+                                                        if ((rfp = afile(fid, "rst", 1)) == NULL) {
+                                                                fclose(tfp);
+                                                                tfp = NULL;
+                                                        }
+                                                }
+                                        }
+                                }
+
+#if SDCDB
+                                if (sfp && (pass == 0)) {
+                                        SDCDBcopy(fid);
+                                }
+#endif
+
+                                gline = 1;
+                        } else {
+                                fprintf(stderr, "Invalid file type\n");
+                                lkexit(ER_FATAL);
+                        }
+                        if (sfp == NULL) {
+                                lkexit(ER_FATAL);
+                        }
+                        goto loop;
+                } else {
+                        filep = NULL;
+                        return(0);
+                }
+        }
+        chopcrlf(ib);
+        return (1);
+}
+
+/*)Function     int     more()
+ *
+ *      The function more() scans the input text line
+ *      skipping white space (SPACES and TABS) and returns a (0)
+ *      if the end of the line or a comment delimeter (;) is found,
+ *      or a (1) if their are additional characters in the line.
+ *
+ *      local variables:
+ *              int     c               next character from
+ *                                      the input text line
+ *
+ *      global variables:
+ *              none
+ *
+ *      called functions:
+ *              int     getnb()         lklex.c
+ *              VOID    unget()         lklex.c
+ *
+ *      side effects:
+ *              use of getnb() and unget() updates the global pointer ip
+ *              the position in the current input text line
+ */
+
+int
+more()
+{
+        int c;
+
+        c = getnb();
+        unget(c);
+        return( (c == '\0' || c == ';') ? 0 : 1 );
+}
+
+/*)Function     char    endline()
+ *
+ *      The function endline() scans the input text line
+ *      skipping white space (SPACES and TABS) and returns the next
+ *      character or a (0) if the end of the line is found or a
+ *      comment delimiter (;) is found.
+ *
+ *      local variables:
+ *              int     c               next character from
+ *                                      the input text line
+ *
+ *      global variables:
+ *              none
+ *
+ *      called functions:
+ *              int     getnb()         lklex.c
+ *
+ *      side effects:
+ *              Use of getnb() updates the global pointer ip the
+ *              position in the current input text line.
+ */
+
+char
+endline()
+{
+        int c;
+
+        c = getnb();
+        return( (c == '\0' || c == ';') ? 0 : c );
+}
+
+/*)Function     VOID    chopcrlf(str)
+ *
+ *              char    *str            string to chop
+ *
+ *      The function chop_crlf() removes trailing LF or CR/LF from
+ *      str, if present.
+ *
+ *      local variables:
+ *              int     i               string length
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              none
+ */
+
+VOID
+chopcrlf(str)
+char *str;
+{
+        int i;
+
+        i = strlen(str);
+        if (i >= 1 && str[i-1] == '\n') str[i-1] = 0;
+        if (i >= 2 && str[i-2] == '\r') str[i-2] = 0;
+}
diff --git a/Kernel/tools/bankld/lklib.c b/Kernel/tools/bankld/lklib.c
new file mode 100644 (file)
index 0000000..e6da0ca
--- /dev/null
@@ -0,0 +1,253 @@
+/* lklib.c
+
+   Copyright (C) 1989-1995 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+   Copyright (C) 2008-2009 Borut Razem, borut dot razem at siol dot net
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <string.h>
+
+#include "sdld.h"
+#include "lk_readnl.h"
+#include "aslink.h"
+#include "lklibr.h"
+#include "lkrel.h"
+
+static int
+is_lib (FILE * libfp)
+{
+  return 1;
+}
+
+#ifdef INDEXLIB
+/* buildlibraryindex - build an in-memory cache of the symbols contained in
+ *                     the libraries
+ */
+static pmlibraryfile
+buildlibraryindex_lib (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
+{
+  char relfil[NINPUT];
+
+  while (lk_readnl (relfil, sizeof (relfil), libfp) != NULL)
+    {
+      FILE *fp;
+      char str[PATH_MAX];
+
+      if (lbnh->path != NULL)
+        {
+          strcpy (str, lbnh->path);
+#ifdef  OTHERSYSTEM
+          if ((*str != '\0') && (str[strlen (str) - 1] != '/') && (str[strlen (str) - 1] != LKDIRSEP))
+            {
+              strcat (str, LKDIRSEPSTR);
+            }
+#endif
+        }
+      else
+        str[0] = '\0';
+
+      if ((relfil[0] == '/') || (relfil[0] == LKDIRSEP))
+        {
+          strcat (str, relfil + 1);
+        }
+      else
+        {
+          strcat (str, relfil);
+        }
+
+      if (strchr (relfil, FSEPX) == NULL)
+        {
+          sprintf (&str[strlen (str)], "%c%s", FSEPX, LKOBJEXT);
+        }
+
+      if ((fp = fopen (str, "rb")) != NULL)
+        {
+          /* Opened OK - create a new libraryfile object for it */
+          if (libr == NULL)
+            {
+              libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+            }
+          else
+            {
+              This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+              This = This->next;
+            }
+          This->next = NULL;
+          This->loaded = -1;
+          This->libspc = lbnh->libspc;
+          This->relfil = strdup (relfil);
+          This->filspc = strdup (str);
+          This->type = type;
+
+          /* Start a new linked list of symbols for this module: */
+          This->symbols = NULL;
+
+          add_rel_index (fp, -1, This);
+          fclose (fp);
+        }                       /* Closes if object file opened OK */
+      else
+        {
+          fprintf (stderr, "?ASlink-Warning-Cannot open library module %s\n", str);
+        }
+    }                           /* Ends while - processing all in libr */
+
+  return This;
+}
+
+#else
+
+static int
+fndsym_lib (const char *name, struct lbname *lbnh, FILE * libfp, int type)
+{
+  char relfil[NINPUT];
+
+  D ("Searching symbol: %s\n", name);
+
+  while (lk_readnl (relfil, sizeof (relfil), libfp) != NULL)
+    {
+      char str[PATH_MAX];
+      FILE *fp;
+
+      if (lbnh->path != NULL)
+        {
+          strcpy (str, lbnh->path);
+#ifdef  OTHERSYSTEM
+          if ((*str != '\0') && (str[strlen (str) - 1] != '/') && (str[strlen (str) - 1] != LKDIRSEP))
+            {
+              strcat (str, LKDIRSEPSTR);
+            }
+#endif
+        }
+      else
+        str[0] = '\0';
+
+      if ((relfil[0] == '/') || (relfil[0] == LKDIRSEP))
+        {
+          strcat (str, relfil + 1);
+        }
+      else
+        {
+          strcat (str, relfil);
+        }
+
+      if (strchr (relfil, FSEPX) == NULL)
+        {
+          sprintf (&str[strlen (str)], "%c%s", FSEPX, LKOBJEXT);
+        }
+
+      if ((fp = fopen (str, "rb")) != NULL)
+        {
+          /* Opened OK - create a new libraryfile object for it */
+          int ret = add_rel_file (name, lbnh, relfil, str, -1, fp, -1, type);
+          fclose (fp);
+          if (ret)
+            {
+              D ("Loaded module %s from file %s.\n", str, str);
+              /* if cdb information required & adb file present */
+              if (yflag && yfp)
+                {
+                  FILE *xfp = afile (str, "adb", 0);    //JCF: Nov 30, 2002
+                  if (xfp)
+                    {
+                      SaveLinkedFilePath (str);
+                      copyfile (yfp, xfp);
+                      fclose (xfp);
+                    }
+                }
+              return 1;         /* Found the symbol, so success! */
+            }
+        }                       /* Closes if object file opened OK */
+      else
+        {
+          fprintf (stderr, "?ASlink-Warning-Cannot open library module %s\n", str);
+        }
+    }                           /* Ends while - processing all in libr */
+
+  return 0;                     /* The symbol is not in this library */
+}
+#endif
+
+/*)Function VOID    loadfile_lib(filspc)
+ *
+ *      char    *filspc     library object file specification
+ *
+ *  The function loadfile() links the library object module.
+ *
+ *  local variables:
+ *      FILE    *fp         file handle
+ *      int     i           input line length
+ *      char    str[]       file input line
+ *
+ *  global variables:
+ *      char    *ip         pointer to linker input string
+ *
+ *   functions called:
+ *      int     fclose()    c_library
+ *      char    *lk_readnl()  lk_readnl.c
+ *      FILE *  fopen()     c_library
+ *      VOID    link_main() lkmain.c
+ *      int     strlen()    c_library
+ *
+ *  side effects:
+ *      If file exists it is linked.
+ */
+
+static VOID
+loadfile_lib (struct lbfile *lbfh)
+{
+  FILE *fp;
+#ifdef __CYGWIN__
+  char posix_path[PATH_MAX];
+  void cygwin_conv_to_full_posix_path (char *win_path, char *posix_path);
+  cygwin_conv_to_full_posix_path (lbfh->filspc, posix_path);
+  fp = fopen (posix_path, "rb");
+#else
+  fp = fopen (lbfh->filspc, "rb");
+#endif
+
+  if (fp != NULL)
+    {
+      load_rel (fp, -1);
+      fclose (fp);
+    }
+  else
+    {
+      fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->filspc);
+      fclose (fp);
+      lkexit (1);
+    }
+}
+
+struct aslib_target aslib_target_lib = {
+  &is_lib,
+#ifdef INDEXLIB
+  &buildlibraryindex_lib,
+#else
+  &fndsym_lib,
+#endif
+  &loadfile_lib,
+};
diff --git a/Kernel/tools/bankld/lklibr.c b/Kernel/tools/bankld/lklibr.c
new file mode 100644 (file)
index 0000000..1124fff
--- /dev/null
@@ -0,0 +1,856 @@
+/* lklibr.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenhat cmf dot nrl dot navy dot mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <ctype.h>
+#include <assert.h>
+
+#include "aslink.h"
+#include "lkrel.h"
+#include "lklibr.h"
+
+/*)Module   lklibr.c
+ *
+ *  The module lklibr.c contains the functions which
+ *  (1) specify the path(s) to library files [.LIB]
+ *  (2) specify the library file(s) [.LIB] to search
+ *  (3) search the library files for specific symbols
+ *      and link the module containing this symbol
+ *
+ *  lklibr.c contains the following functions:
+ *      VOID    addpath()
+ *      VOID    addlib()
+ *      VOID    addfile()
+ *      VOID    search()
+ *      VOID    fndsym()
+ *      VOID    library()
+ *      VOID    loadfile()
+ *
+ */
+
+#define EQ(A,B) !strcmp((A),(B))
+#define NELEM(x) (sizeof (x) / sizeof (*x))
+
+#ifdef INDEXLIB
+/* First entry in the library object symbol cache */
+pmlibraryfile libr = NULL;
+
+int buildlibraryindex (void);
+void freelibraryindex (void);
+#endif /* INDEXLIB */
+
+struct aslib_target *aslib_targets[] = {
+  &aslib_target_sdcclib,
+  &aslib_target_ar,
+  &aslib_target_lib,
+};
+
+/*)Function VOID    addpath()
+ *
+ *  The function addpath() creates a linked structure containing
+ *  the paths to various object module library files.
+ *
+ *  local variables:
+ *      lbpath  *lbph       pointer to new path structure
+ *      lbpath  *lbp        temporary pointer
+ *
+ *  global variables:
+ *      lbpath  *lbphead    The pointer to the first
+ *                          path structure
+ *
+ *   functions called:
+ *      int     getnb()     lklex.c
+ *      VOID *  new()       lksym.c
+ *      int     strlen()    c_library
+ *      char *  strcpy()    c_library
+ *      VOID    unget()     lklex.c
+ *
+ *  side effects:
+ *      An lbpath structure may be created.
+ */
+
+VOID
+addpath (void)
+{
+  struct lbpath *lbph, *lbp;
+
+  lbph = (struct lbpath *) new (sizeof (struct lbpath));
+  if (lbphead == NULL)
+    {
+      lbphead = lbph;
+    }
+  else
+    {
+      lbp = lbphead;
+      while (lbp->next)
+        {
+          lbp = lbp->next;
+        }
+      lbp->next = lbph;
+    }
+  unget (getnb ());
+  lbph->path = strdup (ip);
+}
+
+/*)Function VOID    addlib()
+ *
+ *  The function addlib() tests for the existance of a
+ *  library path structure to determine the method of
+ *  adding this library file to the library search structure.
+ *
+ *  This function calls the function addfile() to actually
+ *  add the library file to the search list.
+ *
+ *  local variables:
+ *      lbpath  *lbph       pointer to path structure
+ *
+ *  global variables:
+ *      lbpath  *lbphead    The pointer to the first
+ *                          path structure
+ *      ip a pointer to the library name
+ *
+ *   functions called:
+ *      VOID    addfile()   lklibr.c
+ *      int     getnb()     lklex.c
+ *      VOID    unget()     lklex.c
+ *
+ *  side effects:
+ *      The function addfile() may add the file to
+ *      the library search list.
+ */
+
+VOID
+addlib (void)
+{
+  struct lbpath *lbph;
+  int foundcount = 0;
+
+  unget (getnb ());
+
+  if (lbphead == NULL)
+    {
+      foundcount = addfile (NULL, ip);
+    }
+  else
+    {
+      for (lbph = lbphead; lbph; lbph = lbph->next)
+        {
+          foundcount += addfile (lbph->path, ip);
+        }
+    }
+  if (foundcount == 0)
+    {
+      fprintf (stderr, "?ASlink-Warning-Couldn't find library '%s'\n", ip);
+    }
+}
+
+/*)Function int addfile(path,libfil)
+ *
+ *      char    *path       library path specification
+ *      char    *libfil     library file specification
+ *
+ *  The function addfile() searches for the library file
+ *  by concatenating the path and libfil specifications.
+ *  if the library is found, an lbname structure is created
+ *  and linked to any previously defined structures.  This
+ *  linked list is used by the function fndsym() to attempt
+ *  to find any undefined symbols.
+ *
+ *  The function does not report an error on invalid
+ *  path / file specifications or if the file is not found.
+ *
+ *  local variables:
+ *      lbname  *lbnh           pointer to new name structure
+ *      lbname  *lbn            temporary pointer
+ *      char *  str             path / file string
+ *      char *  strend          end of path pointer
+ *      char *  str             path / file string
+ *      char *  strend          end of path pointer
+ *
+ *  global variables:
+ *      lbname  *lbnhead        The pointer to the first
+ *                              path structure
+ *      int     objflg          linked file/library object output flag
+ *
+ *   functions called:
+ *      int     getnb()     lklex.c
+ *      VOID *  new()       lksym.c
+ *      int     strlen()    c_library
+ *      char *  strcpy()    c_library
+ *      VOID    unget()     lklex.c
+ *
+ *  side effects:
+ *      An lbname structure may be created.
+ *
+ *  return:
+ *      1: the library was found
+ *      0: the library was not found
+ */
+
+int
+addfile (char *path, char *libfil)
+{
+  FILE *fp;
+  char *str, *strend;
+  struct lbname *lbnh, *lbn;
+#ifdef  OTHERSYSTEM
+  int libfilinc = 0;
+#endif
+
+  if (path != NULL)
+    {
+      str = (char *) new (strlen (path) + strlen (libfil) + 6);
+      strcpy (str, path);
+      strend = str + strlen(str) - 1;
+#ifdef  OTHERSYSTEM
+      if (strlen (str) && (*strend != '/') && (*strend != LKDIRSEP))
+        {
+          strcat (str, LKDIRSEPSTR);
+        }
+#endif
+    }
+  else
+    {
+      str = (char *) new (strlen (libfil) + 5);
+    }
+
+#ifdef  OTHERSYSTEM
+  if ((libfil[0] == '/') || (libfil[0] == LKDIRSEP))
+    {
+      libfil++;
+      libfilinc = 1;
+    }
+#endif
+
+  strcat (str, libfil);
+  if (strchr (libfil, FSEPX) == NULL)
+    {
+      sprintf (&str[strlen (str)], "%clib", FSEPX);
+    }
+
+  fp = fopen (str, "rb");
+  if (fp == NULL)
+    {
+      /*Ok, that didn't work.  Try with the 'libfil' name only */
+#ifdef  OTHERSYSTEM
+      if (libfilinc)
+        libfil--;
+#endif
+      fp = fopen (libfil, "rb");
+      if (fp != NULL)
+        {
+          /*Bingo!  'libfil' is the absolute path of the library */
+          strcpy (str, libfil);
+          path = NULL;          /*This way 'libfil' and 'path' will be rebuilt from 'str' */
+        }
+    }
+
+  if (path == NULL)
+    {
+      /*'path' can not be null since it is needed to find the object files associated with
+         the library.  So, get 'path' from 'str' and then chop it off and recreate 'libfil'.
+         That way putting 'path' and 'libfil' together will result into the original filepath
+         as contained in 'str'. */
+      int j;
+      path = strdup (str);
+      for (j = strlen (path) - 1; j >= 0; j--)
+        {
+          if ((path[j] == '/') || (path[j] == LKDIRSEP))
+            {
+              strcpy (libfil, &path[j + 1]);
+              path[j + 1] = 0;
+              break;
+            }
+        }
+      if (j <= 0)
+        path[0] = 0;
+    }
+
+  if (fp != NULL)
+    {
+      fclose (fp);
+      lbnh = (struct lbname *) new (sizeof (struct lbname));
+      if (lbnhead == NULL)
+        {
+          lbnhead = lbnh;
+        }
+      else
+        {
+          lbn = lbnhead;
+          while (lbn->next)
+            {
+              lbn = lbn->next;
+            }
+          lbn->next = lbnh;
+        }
+
+      lbnh->path = path;
+      lbnh->libfil = strdup (libfil);
+      lbnh->libspc = str;
+      lbnh->f_obj = objflg;
+      return 1;
+    }
+  else
+    {
+      free (str);
+      return 0;
+    }
+}
+
+/*)Function VOID    search()
+ *
+ *  The function search() looks through all the symbol tables
+ *  at the end of pass 1.  If any undefined symbols are found
+ *  then the function fndsym() is called. Function fndsym()
+ *  searches any specified library files to automagically
+ *  import the object modules containing the needed symbol.
+ *
+ *  After a symbol is found and imported by the function
+ *  fndsym() the symbol tables are again searched.  The
+ *  symbol tables are searched until no more symbols can be
+ *  resolved within the library files.  This ensures that
+ *  back references from one library module to another are
+ *  also resolved.
+ *
+ *  local variables:
+ *      int     i           temporary counter
+ *      sym     *sp         pointer to a symbol structure
+ *      int     symfnd      found a symbol flag
+ *
+ *  global variables:
+ *      sym     *symhash[]  array of pointers to symbol tables
+ *
+ *   functions called:
+ *      int     fndsym()    lklibr.c
+ *
+ *  side effects:
+ *      If a symbol is found then the library object module
+ *      containing the symbol will be imported and linked.
+ */
+
+VOID
+search (void)
+{
+  struct sym *sp;
+  int i, symfnd;
+
+  /*
+   * Look for undefined symbols.  Keep
+   * searching until no more symbols are resolved.
+   */
+  symfnd = 1;
+  while (symfnd)
+    {
+      symfnd = 0;
+      /*
+       * Look through all the symbols
+       */
+      for (i = 0; i < NHASH; ++i)
+        {
+          sp = symhash[i];
+          while (sp)
+            {
+              /* If we find an undefined symbol
+               * (one where S_DEF is not set), then
+               * try looking for it.  If we find it
+               * in any of the libraries then
+               * increment symfnd.  This will force
+               * another pass of symbol searching and
+               * make sure that back references work.
+               */
+              if ((sp->s_type & S_DEF) == 0)
+                {
+                  if (fndsym (sp->s_id))
+                    {
+                      symfnd++;
+                    }
+                }
+              sp = sp->s_sp;
+            }
+        }
+    }
+}
+
+/*)Function VOID    fndsym(name)
+ *
+ *      char    *name       symbol name to find
+ *
+ *  The function fndsym() searches through all combinations of the
+ *  library path specifications (input by the -k option) and the
+ *  library file specifications (input by the -l option) that
+ *  lead to an existing file.
+ *
+ *  The file specification may be formed in one of two ways:
+ *
+ *  (1) If the library file contained an absolute
+ *      path/file specification then this becomes filspc.
+ *      (i.e. C:\...)
+ *
+ *  (2) If the library file contains a relative path/file
+ *      specification then the concatenation of the path
+ *      and this file specification becomes filspc.
+ *      (i.e. \...)
+ *
+ *  The structure lbfile is created for the first library
+ *  object file which contains the definition for the
+ *  specified undefined symbol.
+ *
+ *  If the library file [.LIB] contains file specifications for
+ *  non existant files, no errors are returned.
+ *
+ *  local variables:
+ *      char    buf[]       [.REL] file input line
+ *      char    c           [.REL] file input character
+ *      FILE    *fp         file handle for object file
+ *      lbfile  *lbf        temporary pointer
+ *      lbfile  *lbfh       pointer to lbfile structure
+ *      FILE    *libfp      file handle for library file
+ *      lbname  *lbnh       pointer to lbname structure
+ *      char    *path       file specification path
+ *      char    relfil[]    [.REL] file specification
+ *      char    *str        combined path and file specification
+ *      char    symname[]   [.REL] file symbol string
+ *
+ *  global variables:
+ *      lbname  *lbnhead    The pointer to the first
+ *                          name structure
+ *      lbfile  *lbfhead    The pointer to the first
+ *                          file structure
+ *      int     obj_flag    linked file/library object output flag
+ *
+ *   functions called:
+ *      int     fclose()    c_library
+ *      FILE    *fopen()    c_library
+ *      VOID    free()      c_library
+ *      int     getnb()     lklex.c
+ *      VOID    lkexit()    lkmain.c
+ *      VOID    loadfile()  lklibr.c
+ *      VOID *  new()       lksym.c
+ *      char *  sprintf()   c_library
+ *      int     sscanf()    c_library
+ *      char *  strcat()    c_library
+ *      char *  strchr()    c_library
+ *      char *  strcpy()    c_library
+ *      int     strlen()    c_library
+ *      int     strncmp()   c_library
+ *      VOID    unget()     lklex.c
+ *
+ *  side effects:
+ *      If the symbol is found then a new lbfile structure
+ *      is created and added to the linked list of lbfile
+ *      structures.  The file containing the found symbol
+ *      is linked.
+ */
+
+#ifdef INDEXLIB
+int
+fndsym (char *name)
+{
+  struct lbfile *lbfh, *lbf;
+  pmlibraryfile ThisLibr;
+  pmlibrarysymbol ThisSym = NULL;
+
+  pmlibraryfile FirstFound;
+  int numfound = 0;
+
+  D ("Searching symbol: %s\n", name);
+
+  /* Build the index if this is the first call to fndsym */
+  if (libr == NULL)
+    buildlibraryindex ();
+
+  /* Iterate through all library object files */
+  FirstFound = libr;            /* So gcc stops whining */
+  for (ThisLibr = libr; ThisLibr != NULL; ThisLibr = ThisLibr->next)
+    {
+      /* Iterate through all symbols in an object file */
+      for (ThisSym = ThisLibr->symbols; ThisSym != NULL; ThisSym = ThisSym->next)
+        {
+          if (!strcmp (ThisSym->name, name))
+            {
+              if ((!ThisLibr->loaded) && (numfound == 0))
+                {
+                  /* Object file is not loaded - add it to the list */
+                  lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+                  if (lbfhead == NULL)
+                    {
+                      lbfhead = lbfh;
+                    }
+                  else
+                    {
+                      for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
+                        ;
+
+                      lbf->next = lbfh;
+                    }
+                  lbfh->libspc = ThisLibr->libspc;
+                  lbfh->filspc = ThisLibr->filspc;
+                  lbfh->relfil = strdup (ThisLibr->relfil);
+                  lbfh->offset = ThisLibr->offset;
+                  lbfh->type = ThisLibr->type;
+
+                  (*aslib_targets[lbfh->type]->loadfile) (lbfh);
+
+                  ThisLibr->loaded = 1;
+                }
+
+              if (numfound == 0)
+                {
+                  numfound++;
+                  FirstFound = ThisLibr;
+                }
+              else
+                {
+                  char absPath1[PATH_MAX];
+                  char absPath2[PATH_MAX];
+#if defined(_WIN32)
+                  int j;
+
+                  _fullpath (absPath1, FirstFound->libspc, PATH_MAX);
+                  _fullpath (absPath2, ThisLibr->libspc, PATH_MAX);
+                  for (j = 0; absPath1[j] != 0; j++)
+                    absPath1[j] = tolower ((unsigned char) absPath1[j]);
+                  for (j = 0; absPath2[j] != 0; j++)
+                    absPath2[j] = tolower ((unsigned char) absPath2[j]);
+#else
+                  if (NULL == realpath (FirstFound->libspc, absPath1))
+                    *absPath1 = '\0';
+                  if (NULL == realpath (ThisLibr->libspc, absPath2))
+                    *absPath2 = '\0';
+#endif
+                  if (!(EQ (absPath1, absPath2) && EQ (FirstFound->relfil, ThisLibr->relfil)))
+                    {
+                      if (numfound == 1)
+                        {
+                          fprintf (stderr, "?ASlink-Warning-Definition of public symbol '%s'" " found more than once:\n", name);
+                          fprintf (stderr, "   Library: '%s', Module: '%s'\n", FirstFound->libspc, FirstFound->relfil);
+                        }
+                      fprintf (stderr, "   Library: '%s', Module: '%s'\n", ThisLibr->libspc, ThisLibr->relfil);
+                      numfound++;
+                    }
+                }
+            }
+        }
+    }
+  return numfound;
+}
+
+struct add_sym_s
+{
+  pmlibraryfile plf;
+  pmlibrarysymbol pls;
+};
+
+static int
+add_sybmol (const char *sym, void *param)
+{
+  struct add_sym_s *as = (struct add_sym_s *) param;
+  pmlibrarysymbol ps = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+
+  D ("    Indexing symbol: %s\n", sym);
+
+  as->plf->loaded = 0;
+  ps->next = NULL;
+  ps->name = strdup (sym);
+
+  if (as->pls == NULL)
+    {
+      as->pls = as->plf->symbols = ps;
+    }
+  else
+    {
+      as->pls->next = ps;
+      as->pls = as->pls->next;
+    }
+
+  return 0;
+}
+
+pmlibrarysymbol
+add_rel_index (FILE * fp, long size, pmlibraryfile This)
+{
+  struct add_sym_s as;
+  as.plf = This;
+  as.pls = This->symbols;
+
+  assert (This->symbols == NULL);
+
+  enum_symbols (fp, size, &add_sybmol, &as);
+
+  return as.pls;
+}
+
+/* buildlibraryindex - build an in-memory cache of the symbols contained in
+ *                     the libraries
+ */
+int
+buildlibraryindex (void)
+{
+  pmlibraryfile This = NULL;
+  struct lbname *lbnh;
+
+  /*
+   * Search through every library in the linked list "lbnhead".
+   */
+  for (lbnh = lbnhead; lbnh; lbnh = lbnh->next)
+    {
+      FILE *libfp;
+      int i;
+
+      D ("Indexing library: %s\n", lbnh->libspc);
+
+      if ((libfp = fopen (lbnh->libspc, "rb")) == NULL)
+        {
+          fprintf (stderr, "?ASlink-Error-Cannot open library file %s\n", lbnh->libspc);
+          lkexit (1);
+        }
+
+      for (i = 0; i < NELEM (aslib_targets); ++i)
+        {
+          if ((*aslib_targets[i]->is_lib) (libfp))
+            {
+              This = (*aslib_targets[i]->buildlibraryindex) (lbnh, libfp, This, i);
+              break;
+            }
+        }
+
+      if (i >= NELEM (aslib_targets))
+        fprintf (stderr, "?ASlink-Error-Unknown library file format %s\n", lbnh->libspc);
+
+      fclose (libfp);
+    }
+
+  return 0;
+}
+
+/* Release all memory allocated for the in-memory library index */
+void
+freelibraryindex (void)
+{
+  pmlibraryfile ThisLibr, ThisLibr2Free;
+  pmlibrarysymbol ThisSym, ThisSym2Free;
+
+  ThisLibr = libr;
+
+  while (ThisLibr)
+    {
+      ThisSym = ThisLibr->symbols;
+
+      while (ThisSym)
+        {
+          free (ThisSym->name);
+          ThisSym2Free = ThisSym;
+          ThisSym = ThisSym->next;
+          free (ThisSym2Free);
+        }
+      free (ThisLibr->filspc);
+      free (ThisLibr->relfil);
+      ThisLibr2Free = ThisLibr;
+      ThisLibr = ThisLibr->next;
+      free (ThisLibr2Free);
+    }
+
+  libr = NULL;
+}
+
+#else /* INDEXLIB */
+
+struct load_sym_s
+{
+  const char *name;
+  struct lbname *lbnh;
+  const char *relfil;
+  const char *filspc;
+  int offset;
+  int type;
+};
+
+static int
+load_sybmol (const char *sym, void *params)
+{
+  struct load_sym_s *ls = (struct load_sym_s *) params;
+
+  D ("    Symbol: %s\n", sym);
+
+  if (strcmp (ls->name, sym) == 0)
+    {
+      struct lbfile *lbfh, *lbf;
+
+      D ("    Symbol %s found in module %s!\n", sym, ls->relfil);
+
+      lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+      lbfh->libspc = ls->lbnh->libspc;
+      lbfh->relfil = strdup (ls->relfil);
+      lbfh->filspc = strdup (ls->filspc);
+      lbfh->offset = ls->offset;
+      lbfh->type = ls->type;
+
+      if (lbfhead == NULL)
+        lbfhead = lbfh;
+      else
+        {
+          for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
+              ;
+          lbf->next = lbfh;
+        }
+      (*aslib_targets[ls->type]->loadfile) (lbfh);
+
+      return 1;
+    }
+  else
+    return 0;
+}
+
+/*)Function int is_module_loaded(filspc)
+ *
+ * If this module has been already loaded
+ */
+
+int
+is_module_loaded (const char *filspc)
+{
+  struct lbfile *lbf;
+
+  for (lbf = lbfhead; lbf != NULL; lbf = lbf->next)
+    {
+      if (EQ (filspc, lbf->filspc))
+        {
+          D ("  Module %s already loaded!\n", filspc);
+          return 1;       /* Module already loaded */
+        }
+    }
+  return 0;
+}
+
+int
+add_rel_file (const char *name, struct lbname *lbnh, const char *relfil,
+              const char *filspc, int offset, FILE * fp, long size, int type)
+{
+  struct load_sym_s ls;
+
+  /* If this module has been loaded already don't load it again. */
+  if (is_module_loaded (filspc))
+    return 0;
+  else
+    {
+      ls.name = name;
+      ls.lbnh = lbnh;
+      ls.relfil = relfil;
+      ls.filspc = filspc;
+      ls.offset = offset;
+      ls.type = type;
+
+      return enum_symbols (fp, size, &load_sybmol, &ls);
+  }
+}
+
+int
+fndsym (const char *name)
+{
+  FILE *libfp;
+  struct lbname *lbnh;
+  int i;
+
+  /*
+   * Search through every library in the linked list "lbnhead".
+   */
+
+  D ("Searching symbol: %s\n", name);
+
+  for (lbnh = lbnhead; lbnh; lbnh = lbnh->next)
+    {
+      int ret = 0;
+
+      D ("Library: %s\n", lbnh->libspc);
+
+      if ((libfp = fopen (lbnh->libspc, "rb")) == NULL)
+        {
+          fprintf (stderr, "?ASlink-Error-Cannot open library file %s\n", lbnh->libspc);
+          lkexit (1);
+        }
+
+      for (i = 0; i < NELEM (aslib_targets); ++i)
+        {
+          if ((*aslib_targets[i]->is_lib) (libfp))
+            {
+              ret = (*aslib_targets[i]->fndsym) (name, lbnh, libfp, i);
+              break;
+            }
+        }
+
+      if (i >= NELEM (aslib_targets))
+        fprintf (stderr, "?ASlink-Error-Unknown library file format %s\n", lbnh->libspc);
+
+      fclose (libfp);
+
+      if (ret)
+        return 1;
+
+    }                           /* Ends good open of libr file */
+  return 0;
+}
+#endif /* INDEXLIB */
+
+/*)Function VOID    library()
+ *
+ *  The function library() links all the library object files
+ *  contained in the lbfile structures.
+ *
+ *  local variables:
+ *      lbfile  *lbfh       pointer to lbfile structure
+ *
+ *  global variables:
+ *      lbfile  *lbfhead    pointer to first lbfile structure
+ *      int     obj_flag    linked file/library object output flag
+ *
+ *   functions called:
+ *      VOID    loadfile    lklibr.c
+ *
+ *  side effects:
+ *      Links all files contained in the lbfile structures.
+ */
+
+VOID
+library (void)
+{
+  struct lbfile *lbfh;
+
+  for (lbfh = lbfhead; lbfh; lbfh = lbfh->next) {
+    obj_flag = lbfh->f_obj;
+    (*aslib_targets[lbfh->type]->loadfile) (lbfh);
+  }
+
+#ifdef INDEXLIB
+  freelibraryindex ();
+#endif
+}
diff --git a/Kernel/tools/bankld/lklibr.h b/Kernel/tools/bankld/lklibr.h
new file mode 100644 (file)
index 0000000..21f2126
--- /dev/null
@@ -0,0 +1,95 @@
+/* lklibr.h
+
+   Copyright (C) 1989-1995 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+   Copyright (C) 2008 Borut Razem, borut dot razem at siol dot net
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#ifndef __LKLIBR_H
+#define __LKLIBR_H
+
+#include <stdio.h>
+
+#ifdef INDEXLIB
+typedef struct slibrarysymbol mlibrarysymbol;
+typedef struct slibrarysymbol *pmlibrarysymbol;
+
+struct slibrarysymbol
+{
+  char *name;                   /* Warning: allocate memory before using */
+  pmlibrarysymbol next;
+};
+
+typedef struct slibraryfile mlibraryfile;
+typedef struct slibraryfile *pmlibraryfile;
+
+struct slibraryfile
+{
+  int loaded;
+  char *libspc;
+  char *relfil;                 /* Warning: allocate memory before using */
+  char *filspc;                 /* Warning: allocate memory before using */
+  long offset;                  /* The embedded file offset in the library file libspc */
+  unsigned int type;
+  pmlibrarysymbol symbols;
+  pmlibraryfile next;
+};
+
+extern pmlibraryfile libr;
+
+pmlibrarysymbol add_rel_index (FILE * fp, long size, pmlibraryfile This);
+#else
+int is_module_loaded (const char *filspc);
+int add_rel_file (const char *name, struct lbname *lbnh, const char *relfil,
+                  const char *filspc, int offset, FILE * fp, long size, int type);
+#endif
+
+struct aslib_target
+{
+  int (*is_lib) (FILE * libfp);
+#ifdef INDEXLIB
+  pmlibraryfile (*buildlibraryindex) (struct lbname * lbnh, FILE * libfp, pmlibraryfile This, int type);
+#else
+  int (*fndsym) (const char *name, struct lbname * lbnh, FILE * libfp, int type);
+#endif
+  void (*loadfile) (struct lbfile * lbfh);
+};
+
+extern struct aslib_target aslib_target_sdcclib;
+extern struct aslib_target aslib_target_ar;
+extern struct aslib_target aslib_target_lib;
+
+////
+//#define DEBUG_PRINT
+
+#ifdef DEBUG_PRINT
+# define D  printf
+#else
+# define D  1 ? (void)0 : (*(void (*)(const char *, ...))0)
+#endif
+
+#endif /* __LKLIBR_H */
diff --git a/Kernel/tools/bankld/lklist.c b/Kernel/tools/bankld/lklist.c
new file mode 100644 (file)
index 0000000..71106c9
--- /dev/null
@@ -0,0 +1,1304 @@
+/* lklist.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ */
+
+/*
+ * 28-Oct-97 JLH:
+ *           - lstarea: show s_id as string rather than array [NCPS]
+ *           - lstarea: show a_id as string rather than array [NCPS]
+ * 31-Oct-97 JLH: add NoICE output file genration in lstarea
+ * 02-Apr-98 JLH: add XDATA, DATA, BIT flags to area output
+ */
+
+#include "aslink.h"
+
+/*)Module       lklist.c
+ *
+ *      The module lklist.c contains the functions which
+ *      output the linker .map file and produce a relocated
+ *      listing .rst file.
+ *
+ *      lklist.c contains the following functions:
+ *              int     dgt()
+ *              VOID    newpag()
+ *              VOID    slew()
+ *              VOID    lstarea()
+ *              VOID    lkulist()
+ *              VOID    lkalist()
+ *              VOID    lkglist()
+ *
+ *      lklist.c contains no local variables.
+ */
+
+/*)Function     VOID    newpag()
+ *
+ *      The function newpag() outputs a page skip, writes the
+ *      first page header line, sets the line count to 1, and
+ *      increments the page counter.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              int     lop             current line number on page
+ *              int     page            current page number
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *
+ *      side effects:
+ *              The page and line counters are updated.
+ */
+
+VOID
+newpag(FILE *fp)
+{
+        fprintf(fp, "\fASxxxx Linker %s,  page %u.\n", VERSION, ++page);
+        lop = 1;
+}
+
+/*)Function     int     dgt(rdx,str,n)
+ *
+ *              int     rdx             radix bit code
+ *              char    *str            pointer to the test string
+ *              int     n               number of characters to check
+ *
+ *      The function dgt() verifies that the string under test
+ *      is of the specified radix.
+ *
+ *      local variables:
+ *              int     i               loop counter
+ *
+ *      global variables:
+ *              ctype[]                 array of character types
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              none
+ */
+
+int
+dgt(int rdx, char *str, int n)
+{
+        int i;
+
+        for (i=0; i<n; i++) {
+                if ((ctype[*str++ & 0x007F] & rdx) == 0)
+                        return(0);
+        }
+        return(1);
+}
+
+/*)Function     VOID    slew(xp, yp)
+ *
+ *              area *  xp              pointer to an area structure
+ *              bank *  yp              pointer to a  bank structure
+ *
+ *      The function slew() increments the page line counter.
+ *      If the number of lines exceeds the maximum number of
+ *      lines per page then a page skip and a page header are
+ *      output.
+ *
+ *      local variables:
+ *              a_uint  ai              temporary
+ *              a_uint  aj              temporary
+ *              int     i               loop counter
+ *              int     n               repeat counter
+ *              char *  frmta           temporary format specifier
+ *              char *  frmtb           temporary format specifier
+ *              char *  ptr             pointer to an id string
+ *
+ *      global variables:
+ *              int     a_bytes         T line address bytes
+ *              int     a_mask          addressing mask
+ *              int     lop             current line number on page
+ *              FILE    *mfp            Map output file handle
+ *              int     wflag           Wide format listing
+ *              int     xflag           Map file radix type flag
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    newpag()        lklist.c
+ *              char    putc()          c_library
+ *
+ *      side effects:
+ *              The page line and the page count may be updated.
+ */
+
+VOID
+slew(struct area *xp, struct bank *yp)
+{
+        int i, n;
+        char *frmta, *frmtb, *ptr;
+        a_uint  ai, aj;
+
+        if (lop++ >= NLPP) {
+                newpag(mfp);
+                switch(xflag) {
+                default:
+                case 0: frmta = "Hexadecimal"; break;
+                case 1: frmta = "Octal"; break;
+                case 2: frmta = "Decimal"; break;
+                }
+                fprintf(mfp, "%s  [%d-Bits]\n", frmta, a_bytes*8);
+                if (*yp->b_id) {
+                        fprintf(mfp, "[ Bank == %s ]\n", yp->b_id);
+                        lop += 1;
+                }
+                fprintf(mfp, "\n");
+                if (wflag) {
+                        fprintf(mfp,
+                                "Area                                    Addr");
+                        fprintf(mfp,
+                                "        Size        Decimal Bytes (Attributes)\n");
+                        fprintf(mfp,
+                                "--------------------------------        ----");
+                        fprintf(mfp,
+                                "        ----        ------- ----- ------------\n");
+                } else {
+                        fprintf(mfp,
+                                "Area                       Addr   ");
+                        fprintf(mfp,
+                                "     Size        Decimal Bytes (Attributes)\n");
+                        fprintf(mfp,
+                                "--------------------       ----   ");
+                        fprintf(mfp,
+                                "     ----        ------- ----- ------------\n");
+                }
+
+                ai = xp->a_addr & a_mask;
+                aj = xp->a_size & a_mask;
+
+                /*
+                 * Output Area Header
+                 */
+                ptr = &xp->a_id[0];
+                if (wflag) {
+                        fprintf(mfp, "%-32.32s", ptr);
+                } else {
+                        fprintf(mfp, "%-19.19s", ptr);
+                }
+#ifdef  LONGINT
+                switch(a_bytes) {
+                default:
+                case 2:
+                        switch(xflag) {
+                        default:
+                        case 0: frmta = "        %04lX        %04lX"; break;
+                        case 1: frmta = "      %06lo      %06lo"; break;
+                        case 2: frmta = "       %05lu       %05lu"; break;
+                        }
+                        frmtb = " =      %6lu. bytes "; break;
+                case 3:
+                        switch(xflag) {
+                        default:
+                        case 0: frmta = "      %06lX      %06lX"; break;
+                        case 1: frmta = "    %08lo    %08lo"; break;
+                        case 2: frmta = "    %08lu    %08lu"; break;
+                        }
+                        frmtb = " =    %8lu. bytes "; break;
+                case 4:
+                        switch(xflag) {
+                        default:
+                        case 0: frmta = "    %08lX    %08lX"; break;
+                        case 1: frmta = " %011lo %011lo"; break;
+                        case 2: frmta = "  %010lu  %010lu"; break;
+                        }
+                        frmtb = " =  %10lu. bytes "; break;
+                }
+#else
+                switch(a_bytes) {
+                default:
+                case 2:
+                        switch(xflag) {
+                        default:
+                        case 0: frmta = "        %04X        %04X"; break;
+                        case 1: frmta = "      %06o      %06o"; break;
+                        case 2: frmta = "       %05u       %05u"; break;
+                        }
+                        frmtb = " =      %6u. bytes "; break;
+                case 3:
+                        switch(xflag) {
+                        default:
+                        case 0: frmta = "      %06X      %06X"; break;
+                        case 1: frmta = "    %08o    %08o"; break;
+                        case 2: frmta = "    %08u    %08u"; break;
+                        }
+                        frmtb = " =    %8u. bytes "; break;
+                case 4:
+                        switch(xflag) {
+                        default:
+                        case 0: frmta = "    %08X    %08X"; break;
+                        case 1: frmta = " %011o %011o"; break;
+                        case 2: frmta = "  %010u  %010u"; break;
+                        }
+                        frmtb = " =  %10u. bytes "; break;
+                }
+#endif
+                fprintf(mfp, frmta, ai, aj);
+                fprintf(mfp, frmtb, aj);
+
+                if (xp->a_flag & A3_ABS) {
+                        fprintf(mfp, "(ABS");
+                } else {
+                        fprintf(mfp, "(REL");
+                }
+                if (xp->a_flag & A3_OVR) {
+                        fprintf(mfp, ",OVR");
+                } else {
+                        fprintf(mfp, ",CON");
+                }
+                if (xp->a_flag & A3_PAG) {
+                        fprintf(mfp, ",PAG");
+                }
+
+                /* sdld specific */
+                if (xp->a_flag & A_CODE) {
+                        fprintf(mfp, ",CODE");
+                }
+                if (xp->a_flag & A_XDATA) {
+                        fprintf(mfp, ",XDATA");
+                }
+                if (xp->a_flag & A_BIT) {
+                        fprintf(mfp, ",BIT");
+                }
+                /* end sdld specific */
+
+                fprintf(mfp, ")\n");
+                if (wflag) {
+                        putc('\n', mfp);
+                        fprintf(mfp,
+                        "      Value  Global                           ");
+                        fprintf(mfp,
+                        "   Global Defined In Module\n");
+                        fprintf(mfp,
+                        "      -----  --------------------------------");
+                        fprintf(mfp,
+                        "   ------------------------\n");
+                } else {
+                        switch(a_bytes) {
+                        default:
+                        case 2: frmta = "   Value  Global   ";
+                                frmtb = "   -----  ------   ";
+                                n = 4; break;
+                        case 3:
+                        case 4: frmta = "        Value  Global    ";
+                                frmtb = "        -----  ------    ";
+                                n = 3; break;
+                        }
+                        putc('\n', mfp);
+                        for(i=0;i<n;++i)
+                                fprintf(mfp, "%s", frmta);
+                        putc('\n', mfp);
+                        for(i=0;i<n;++i)
+                                fprintf(mfp, "%s", frmtb);
+                        putc('\n', mfp);
+                }
+
+                lop += 9;
+        }
+}
+
+/* sdld specific */
+/* Used for qsort call in lstsym */
+static int _cmpSymByAddr(const void *p1, const void *p2)
+{
+    struct sym **s1 = (struct sym **)(p1);
+    struct sym **s2 = (struct sym **)(p2);
+    int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) -
+                ((*s2)->s_addr + (*s2)->s_axp->a_addr);
+
+    /* Sort first by address, then by name. */
+    if (delta)
+    {
+        return delta;
+    }
+    return strcmp((*s1)->s_id,(*s2)->s_id);
+}
+/* end sdld specific */
+
+/*)Function     VOID    lstarea(xp, yp)
+ *
+ *              area *  xp              pointer to an area structure
+ *              bank *  yp              pointer to a  bank structure
+ *
+ *      The function lstarea() creates the linker map output for
+ *      the area specified by pointer xp.  The generated output
+ *      area header includes the area name, starting address,
+ *      size of area, number of words (in decimal), and the
+ *      area attributes.  The symbols defined in this area are
+ *      sorted by ascending address and output four per line
+ *      in the selected radix (one per line in wide format).
+ *
+ *      local variables:
+ *              areax * oxp             pointer to an area extension structure
+ *              int     i               loop counter
+ *              int     j               bubble sort update status
+ *              int     n               repeat counter
+ *              char *  frmt            temporary format specifier
+ *              char *  ptr             pointer to an id string
+ *              int     nmsym           number of symbols in area
+ *              a_uint  a0              temporary
+ *              a_uint  ai              temporary
+ *              a_uint  aj              temporary
+ *              sym *   sp              pointer to a symbol structure
+ *              sym **  p               pointer to an array of
+ *                                      pointers to symbol structures
+ *
+ *      global variables:
+ *              int     a_bytes         T line address bytes
+ *              FILE    *mfp            Map output file handle
+ *              sym *symhash[NHASH]     array of pointers to NHASH
+ *                                      linked symbol lists
+ *              int     wflag           Wide format listing
+ *              int     xflag           Map file radix type flag
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    free()          c_library
+ *              char *  malloc()        c_library
+ *              char    putc()          c_library
+ *              VOID    slew()          lklist.c
+ *
+ *      side effects:
+ *              Map output generated.
+ */
+
+VOID
+lstarea(struct area *xp, struct bank *yp)
+{
+        struct areax *oxp;
+        int i, j, n;
+        char *frmt, *ptr;
+        int nmsym;
+        a_uint a0, ai, aj;
+        struct sym *sp;
+        struct sym **p;
+        /* sdld specific */
+        int memPage;
+        /* end sdld specific */
+
+        /*
+         * Find number of symbols in area
+         */
+        nmsym = 0;
+        oxp = xp->a_axp;
+        while (oxp) {
+                for (i=0; i<NHASH; i++) {
+                        sp = symhash[i];
+                        while (sp != NULL) {
+                                if (oxp == sp->s_axp)
+                                        ++nmsym;
+                                sp = sp->s_sp;
+                        }
+                }
+                oxp = oxp->a_axp;
+        }
+
+        if ((nmsym == 0) && (xp->a_size == 0)) {
+                return;
+        }
+
+        lop = NLPP;
+        slew(xp, yp);
+
+        if (nmsym == 0) {
+                return;
+        }
+
+        /*
+         * Allocate space for an array of pointers to symbols
+         * and load array.
+         */
+        if ( (p = (struct sym **) malloc (nmsym*sizeof(struct sym *))) == NULL) {
+                fprintf(mfp, "Insufficient space to build Map Segment.\n");
+                return;
+        }
+        nmsym = 0;
+        oxp = xp->a_axp;
+        while (oxp) {
+                for (i=0; i<NHASH; i++) {
+                        sp = symhash[i];
+                        while (sp != NULL) {
+                                if (oxp == sp->s_axp) {
+                                        p[nmsym++] = sp;
+                                }
+                                sp = sp->s_sp;
+                        }
+                }
+                oxp = oxp->a_axp;
+        }
+
+        if (is_sdld()) {
+                /*
+                 * Quick Sort of Addresses in Symbol Table Array
+                 */
+                qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
+        } else {
+                /*
+                 * Bubble Sort of Addresses in Symbol Table Array
+                 */
+                j = 1;
+                while (j) {
+                        j = 0;
+                        sp = p[0];
+                        a0 = sp->s_addr + sp->s_axp->a_addr;
+                        for (i=1; i<nmsym; ++i) {
+                                sp = p[i];
+                                ai = sp->s_addr + sp->s_axp->a_addr;
+                                if (a0 > ai) {
+                                        j = 1;
+                                        p[i] = p[i-1];
+                                        p[i-1] = sp;
+                                }
+                                a0 = ai;
+                        }
+                }
+        }
+
+        /*
+         * Repeat Counter
+         */
+        switch(a_bytes) {
+        default:
+        case 2: n = 4; break;
+        case 3:
+        case 4: n = 3; break;
+        }
+
+        /*
+         * Symbol Table Output
+         */
+        /* sdld specific */
+        memPage = (xp->a_flag & A_CODE) ? 0x0C : ((xp->a_flag & A_XDATA) ? 0x0D : ((xp->a_flag & A_BIT) ? 0x0B : 0x00));
+        /* end sdld specific */
+        i = 0;
+        while (i < nmsym) {
+                if (wflag) {
+                        slew(xp, yp);
+                        if (is_sdld()) {
+                                switch(a_bytes) {
+                                default:
+                                case 2: frmt = "     "; break;
+                                case 3:
+                                case 4: frmt = ""; break;
+                                }
+                                if (memPage != 0)
+                                        fprintf(mfp, "%s%X:", frmt, memPage);
+                                else
+                                        fprintf(mfp, "%s  ", frmt);
+                        } else {
+                                switch(a_bytes) {
+                                default:
+                                case 2: frmt = "        "; break;
+                                case 3:
+                                case 4: frmt = "   "; break;
+                                }
+                                fprintf(mfp, "%s", frmt);
+                        }
+                } else
+                if ((i % n) == 0) {
+                        slew(xp, yp);
+                        switch(a_bytes) {
+                        default:
+                        case 2: frmt = "  "; break;
+                        case 3:
+                        case 4: frmt = "  "; break;
+                        }
+                        fprintf(mfp, "%s", frmt);
+                }
+
+                sp = p[i];
+                aj = (sp->s_addr + sp->s_axp->a_addr) & a_mask;
+#ifdef  LONGINT
+                switch(a_bytes) {
+                default:
+                case 2:
+                        switch(xflag) {
+                        default:
+                        case 0: frmt = "  %04lX  "; break;
+                        case 1: frmt = "%06lo  "; break;
+                        case 2: frmt = " %05lu  "; break;
+                        }
+                        break;
+                case 3:
+                        switch(xflag) {
+                        default:
+                        case 0: frmt = "     %06lX  "; break;
+                        case 1: frmt = "   %08lo  "; break;
+                        case 2: frmt = "   %08lu  "; break;
+                        }
+                        break;
+                case 4:
+                        switch(xflag) {
+                        default:
+                        case 0: frmt = "   %08lX  "; break;
+                        case 1: frmt = "%011lo  "; break;
+                        case 2: frmt = " %010lu  "; break;
+                        }
+                        break;
+                }
+#else
+                switch(a_bytes) {
+                default:
+                case 2:
+                        switch(xflag) {
+                        default:
+                        case 0: frmt = "  %04X  "; break;
+                        case 1: frmt = "%06o  "; break;
+                        case 2: frmt = " %05u  "; break;
+                        }
+                        break;
+                case 3:
+                        switch(xflag) {
+                        default:
+                        case 0: frmt = "     %06X  "; break;
+                        case 1: frmt = "   %08o  "; break;
+                        case 2: frmt = "   %08u  "; break;
+                        }
+                        break;
+                case 4:
+                        switch(xflag) {
+                        default:
+                        case 0: frmt = "   %08X  "; break;
+                        case 1: frmt = "%011o  "; break;
+                        case 2: frmt = " %010u  "; break;
+                        }
+                        break;
+                }
+#endif
+                fprintf(mfp, frmt, aj);
+
+                ptr = &sp->s_id[0];
+
+#if NOICE
+                /*
+                 * NoICE output of symbol
+                 */
+                if (jflag) DefineNoICE(ptr, aj, yp);
+#endif
+
+#if SDCDB
+                /*
+                 * SDCDB output of symbol
+                 */
+                if (yflag) DefineSDCDB(ptr, aj);
+#endif
+
+                if (wflag) {
+                        fprintf(mfp, "%-32.32s", ptr);
+                        i++;
+                        ptr = &sp->m_id[0];
+                        if(ptr) {
+                                fprintf(mfp, "   %-.28s", ptr);
+                        }
+                } else {
+                        switch(a_bytes) {
+                        default:
+                        case 2: frmt = "%-8.8s"; break;
+                        case 3:
+                        case 4: frmt = "%-9.9s"; break;
+                        }
+                        fprintf(mfp, frmt, ptr);
+                        if (++i < nmsym)
+                                if (i % n != 0)
+                                        fprintf(mfp, " | ");
+                }
+                if (wflag || (i % n == 0)) {
+                        putc('\n', mfp);
+                }
+        }
+        if (i % n != 0) {
+                putc('\n', mfp);
+        }
+        free(p);
+}
+
+/*)Function     VOID    lkulist(i)
+ *
+ *              int     i       i # 0   process LST to RST file
+ *                              i = 0   copy remainder of LST file
+ *                                      to RST file and close files
+ *
+ *      The function lkulist() creates a relocated listing (.rst)
+ *      output file from the ASxxxx assembler listing (.lst)
+ *      files.  The .lst file's program address and code bytes
+ *      are changed to reflect the changes made by ASlink as
+ *      the .rel files are combined into a single relocated
+ *      output file.
+ *
+ *      local variables:
+ *              a_uint  cpc             current program counter address in PC increments
+ *              int     cbytes          bytes so far in T line
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *              int     hilo            byte order
+ *              int     gline           get a line from the LST file
+ *                                      to translate for the RST file
+ *              a_uint  pc              current program counter address in bytes
+ *              int     pcb             bytes per instruction word
+ *              char    rb[]            read listing file text line
+ *              FILE    *rfp            The file handle to the current
+ *                                      output RST file
+ *              int     rtcnt           count of data words
+ *              int     rtflg[]         output the data flag
+ *              a_uint  rtval[]         relocated data
+ *              int     rterr[]         error flag ???
+ *              FILE    *tfp            The file handle to the current
+ *                                      LST file being scanned
+ *
+ *      functions called:
+ *              int     fclose()        c_library
+ *              int     fgets()         c_library
+ *              int     fprintf()       c_library
+ *              VOID    lkalist()       lklist.c
+ *              VOID    lkglist()       lklist.c
+ *
+ *      side effects:
+ *              A .rst file is created for each available .lst
+ *              file associated with a .rel file.
+ */
+
+VOID
+lkulist(int i)
+{
+        a_uint cpc;
+        int cbytes;
+
+        /*
+         * Exit if listing file is not open
+         */
+        if (tfp == NULL)
+                return;
+
+        /*
+         * Normal processing of LST to RST
+         */
+        if (i) {
+                /*
+                 * Line with only address
+                 */
+                if (rtcnt == a_bytes) {
+                        lkalist(pc);
+
+                /*
+                 * Line with address and code
+                 */
+                } else {
+                        cpc = pc;
+                        cbytes = 0;
+                        for (i=a_bytes; i < rtcnt; i++) {
+                                if (rtflg[i]) {
+                                        lkglist(cpc, (int) (rtval[i] & 0xFF), rterr[i]);
+                                        cbytes += 1;
+                                        cpc += (cbytes % pcb) ? 0 : 1;
+                                }
+                        }
+                }
+        /*
+         * Copy remainder of LST to RST
+         */
+        } else {
+                if (gline == 0)
+                        fprintf(rfp, "%s", rb);
+
+                while (fgets(rb, sizeof(rb)-2, tfp) != 0) {
+                        fprintf(rfp, "%s", rb);
+                }
+                fclose(tfp);
+                tfp = NULL;
+                fclose(rfp);
+                rfp = NULL;
+        }
+}
+
+/*)Function     VOID    lkalist(cpc)
+ *
+ *              int     cpc             current program counter value
+ *
+ *      The function lkalist() performs the following functions:
+ *
+ *      (1)     if the value of gline = 0 then the current listing
+ *              file line is copied to the relocated listing file output.
+ *
+ *      (2)     the listing file is read line by line and copied to
+ *              the relocated listing file until a valid source
+ *              line number and a program counter value of the correct
+ *              radix is found.  The new relocated pc value is substituted
+ *              and the line is written to the RST file.
+ *
+ *      local variables:
+ *              int     i               loop counter
+ *              int     m               character count
+ *              int     n               character index
+ *              int     r               character radix
+ *              char *  frmt            temporary format specifier
+ *              char    str[]           temporary string
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *              a_uint  a_mask          address masking parameter
+ *              int     gcntr           data byte counter
+ *              int     gline           get a line from the LST file
+ *                                      to translate for the RST file
+ *              char    rb[]            read listing file text line
+ *              FILE    *rfp            The file handle to the current
+ *                                      output RST file
+ *              FILE    *tfp            The file handle to the current
+ *                                      LST file being scanned
+ *
+ *      functions called:
+ *              int     dgt()           lklist.c
+ *              int     fclose()        c_library
+ *              int     fgets()         c_library
+ *              int     fprintf()       c_library
+ *              int     sprintf()       c_library
+ *              char *  strncpy()       c_library
+ *
+ *      side effects:
+ *              Lines of the LST file are copied to the RST file,
+ *              the last line copied has the code address
+ *              updated to reflect the program relocation.
+ */
+
+/* The Output Formats,  No Cycle Count
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+   |    |               |     | |
+ee XXXX xx xx xx xx xx xx LLLLL *************   HEX(16)
+ee 000000 ooo ooo ooo ooo LLLLL *************   OCTAL(16)
+ee  DDDDD ddd ddd ddd ddd LLLLL *************   DECIMAL(16)
+                     XXXX
+                   OOOOOO
+                    DDDDD
+
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+     |       |                  |     | |
+ee    XXXXXX xx xx xx xx xx xx xx LLLLL *********       HEX(24)
+ee   OO000000 ooo ooo ooo ooo ooo LLLLL *********       OCTAL(24)
+ee   DDDDDDDD ddd ddd ddd ddd ddd LLLLL *********       DECIMAL(24)
+                           XXXXXX
+                         OOOOOOOO
+                         DDDDDDDD
+
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+  |          |                  |     | |
+ee  XXXXXXXX xx xx xx xx xx xx xx LLLLL *********       HEX(32)
+eeOOOOO000000 ooo ooo ooo ooo ooo LLLLL *********       OCTAL(32)
+ee DDDDDDDDDD ddd ddd ddd ddd ddd LLLLL *********       DECIMAL(32)
+                         XXXXXXXX
+                      OOOOOOOOOOO
+                       DDDDDDDDDD
+*/
+
+/* The Output Formats,  With Cycle Count [nn]
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+   |    |               |     | |
+ee XXXX xx xx xx xx xx[nn]LLLLL *************   HEX(16)
+ee 000000 ooo ooo ooo [nn]LLLLL *************   OCTAL(16)
+ee  DDDDD ddd ddd ddd [nn]LLLLL *************   DECIMAL(16)
+                     XXXX
+                   OOOOOO
+                    DDDDD
+
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+     |       |                  |     | |
+ee    XXXXXX xx xx xx xx xx xx[nn]LLLLL *********       HEX(24)
+ee   OO000000 ooo ooo ooo ooo [nn]LLLLL *********       OCTAL(24)
+ee   DDDDDDDD ddd ddd ddd ddd [nn]LLLLL *********       DECIMAL(24)
+                           XXXXXX
+                         OOOOOOOO
+                         DDDDDDDD
+
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+  |          |                  |     | |
+ee  XXXXXXXX xx xx xx xx xx xx[nn]LLLLL *********       HEX(32)
+eeOOOOO000000 ooo ooo ooo ooo [nn]LLLLL *********       OCTAL(32)
+ee DDDDDDDDDD ddd ddd ddd ddd [nn]LLLLL *********       DECIMAL(32)
+                         XXXXXXXX
+                      OOOOOOOOOOO
+                       DDDDDDDDDD
+*/
+
+VOID
+lkalist(a_uint cpc)
+{
+        char str[16];
+        char *frmt;
+        int m, n, r;
+
+        /*
+         * Truncate (int) to N-Bytes
+         */
+        cpc &= a_mask;
+
+        /*
+         * Exit if listing file is not open
+         */
+loop:   if (tfp == NULL)
+                return;
+
+        /*
+         * Copy current LST to RST
+         */
+        if (gline == 0) {
+                fprintf(rfp, "%s", rb);
+                gline = 1;
+        }
+
+        /*
+         * Clear text line buffer
+         */
+        memset(rb, 0, sizeof(rb));
+
+        /*
+         * Get next LST text line
+         */
+        if (fgets(rb, sizeof(rb)-2, tfp) == NULL) {
+                fclose(tfp);
+                tfp = NULL;
+                fclose(rfp);
+                rfp = NULL;
+                return;
+        }
+
+        /*
+         * Must have an ASxxxx Listing line number
+         */
+         switch(a_bytes) {
+         default:
+         case 2: n = 30; break;
+         case 3:
+         case 4: n = 38; break;
+         }
+         if (!dgt(RAD10, &rb[n], 1)) {
+                fprintf(rfp, "%s", rb);
+                goto loop;
+        }
+
+        /*
+         * Must have an address in the expected radix
+         */
+#ifdef  LONGINT
+        switch(radix) {
+        default:
+        case 16:
+                r = RAD16;
+                switch(a_bytes) {
+                default:
+                case 2: n = 3; m = 4; frmt = "%04lX"; break;
+                case 3: n = 6; m = 6; frmt = "%06lX"; break;
+                case 4: n = 4; m = 8; frmt = "%08lX"; break;
+                }
+                break;
+        case 10:
+                r = RAD10;
+                switch(a_bytes) {
+                default:
+                case 2: n = 4; m = 5; frmt = "%05lu"; break;
+                case 3: n = 5; m = 8; frmt = "%08lu"; break;
+                case 4: n = 3; m = 10; frmt = "%010lu"; break;
+                }
+                break;
+        case 8:
+                r = RAD8;
+                switch(a_bytes) {
+                default:
+                case 2: n = 3; m = 6; frmt = "%06lo"; break;
+                case 3: n = 5; m = 8; frmt = "%08lo"; break;
+                case 4: n = 2; m = 11; frmt = "%011lo"; break;
+                }
+                break;
+        }
+#else
+        switch(radix) {
+        default:
+        case 16:
+                r = RAD16;
+                switch(a_bytes) {
+                default:
+                case 2: n = 3; m = 4; frmt = "%04X"; break;
+                case 3: n = 6; m = 6; frmt = "%06X"; break;
+                case 4: n = 4; m = 8; frmt = "%08X"; break;
+                }
+                break;
+        case 10:
+                r = RAD10;
+                switch(a_bytes) {
+                default:
+                case 2: n = 4; m = 5; frmt = "%05u"; break;
+                case 3: n = 5; m = 8; frmt = "%08u"; break;
+                case 4: n = 3; m = 10; frmt = "%010u"; break;
+                }
+                break;
+        case 8:
+                r = RAD8;
+                switch(a_bytes) {
+                default:
+                case 2: n = 3; m = 6; frmt = "%06o"; break;
+                case 3: n = 5; m = 8; frmt = "%08o"; break;
+                case 4: n = 2; m = 11; frmt = "%011o"; break;
+                }
+                break;
+        }
+#endif
+        if (!dgt(r, &rb[n], m)) {
+                        fprintf(rfp, "%s", rb);
+                        goto loop;
+                }
+        sprintf(str, frmt, cpc);
+        strncpy(&rb[n], str, m);
+
+        /*
+         * Copy updated LST text line to RST
+         */
+        fprintf(rfp, "%s", rb);
+        gcntr = 0;
+}
+
+/*)Function     VOID    lkglist(cpc,v,err)
+ *
+ *              int     cpc             current program counter value
+ *              int     v               value of byte at this address
+ *              int     err             error flag for this value
+ *
+ *      The function lkglist() performs the following functions:
+ *
+ *      (1)     if the value of gline = 1 then the listing file
+ *              is read line by line and copied to the
+ *              relocated listing file until a valid source
+ *              line number and a program counter value of the correct
+ *              radix is found.
+ *
+ *      (2)     The new relocated values and code address are
+ *              substituted and the line may be written to the RST file.
+ *
+ *      local variables:
+ *              int     a               string index for first byte
+ *              int     i               loop counter
+ *              int     m               character count
+ *              int     n               character index
+ *              int     r               character radix
+ *              int     s               spacing
+ *              int     u               repeat counter
+ *              char *  afrmt           temporary format specifier
+ *              char *  frmt            temporary format specifier
+ *              char    str[]           temporary string
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *              a_uint  a_mask          address masking parameter
+ *              int     gcntr           data byte counter
+ *                                      set to -1 for a continuation line
+ *              int     gline           get a line from the LST file
+ *                                      to translate for the RST file
+ *              char    rb[]            read listing file text line
+ *              char    *rp             pointer to listing file text line
+ *              FILE    *rfp            The file handle to the current
+ *                                      output RST file
+ *              FILE    *tfp            The file handle to the current
+ *                                      LST file being scanned
+ *              char    *errmsg3[]      array of pointers to error strings
+ *
+ *      functions called:
+ *              int     dgt()           lklist.c
+ *              int     fclose()        c_library
+ *              int     fgets()         c_library
+ *              int     fprintf()       c_library
+ *              int     sprintf()       c_library
+ *              char *  strncpy()       c_library
+ *
+ *      side effects:
+ *              Lines of the LST file are copied to the RST file
+ *              with updated data values and code addresses.
+ */
+
+/* The Output Formats, No Cycle Count
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+   |    |               |     | |
+ee XXXX xx xx xx xx xx xx LLLLL *************   HEX(16)
+ee 000000 ooo ooo ooo ooo LLLLL *************   OCTAL(16)
+ee  DDDDD ddd ddd ddd ddd LLLLL *************   DECIMAL(16)
+                     XXXX
+                   OOOOOO
+                    DDDDD
+
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+     |       |                  |     | |
+ee    XXXXXX xx xx xx xx xx xx xx LLLLL *********       HEX(24)
+ee   OO000000 ooo ooo ooo ooo ooo LLLLL *********       OCTAL(24)
+ee   DDDDDDDD ddd ddd ddd ddd ddd LLLLL *********       DECIMAL(24)
+                           XXXXXX
+                         OOOOOOOO
+                         DDDDDDDD
+
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+  |          |                  |     | |
+ee  XXXXXXXX xx xx xx xx xx xx xx LLLLL *********       HEX(32)
+eeOOOOO000000 ooo ooo ooo ooo ooo LLLLL *********       OCTAL(32)
+ee DDDDDDDDDD ddd ddd ddd ddd ddd LLLLL *********       DECIMAL(32)
+                         XXXXXXXX
+                      OOOOOOOOOOO
+                       DDDDDDDDDD
+*/
+
+/* The Output Formats,  With Cycle Count [nn]
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+   |    |               |     | |
+ee XXXX xx xx xx xx xx[nn]LLLLL *************   HEX(16)
+ee 000000 ooo ooo ooo [nn]LLLLL *************   OCTAL(16)
+ee  DDDDD ddd ddd ddd [nn]LLLLL *************   DECIMAL(16)
+                     XXXX
+                   OOOOOO
+                    DDDDD
+
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+     |       |                  |     | |
+ee    XXXXXX xx xx xx xx xx xx[nn]LLLLL *********       HEX(24)
+ee   OO000000 ooo ooo ooo ooo [nn]LLLLL *********       OCTAL(24)
+ee   DDDDDDDD ddd ddd ddd ddd [nn]LLLLL *********       DECIMAL(24)
+                           XXXXXX
+                         OOOOOOOO
+                         DDDDDDDD
+
+| Tabs- |       |       |       |       |       |
+          11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+  |          |                  |     | |
+ee  XXXXXXXX xx xx xx xx xx xx[nn]LLLLL *********       HEX(32)
+eeOOOOO000000 ooo ooo ooo ooo [nn]LLLLL *********       OCTAL(32)
+ee DDDDDDDDDD ddd ddd ddd ddd [nn]LLLLL *********       DECIMAL(32)
+                         XXXXXXXX
+                      OOOOOOOOOOO
+                       DDDDDDDDDD
+*/
+
+VOID
+lkglist(a_uint cpc, int v, int err)
+{
+        char str[16];
+        char *afrmt, *frmt;
+        int a, n, m, r, s, u;
+
+        /*
+         * Truncate (int) to N-Bytes
+         */
+         cpc &= a_mask;
+
+        /*
+         * Exit if listing file is not open
+         */
+loop:   if (tfp == NULL)
+                return;
+
+        /*
+         * Get next LST text line
+         */
+        if (gline) {
+                /*
+                 * Clear text line buffer
+                 */
+                memset(rb, 0, sizeof(rb));
+
+                /*
+                 * Get next LST text line
+                 */
+                if (fgets(rb, sizeof(rb)-2, tfp) == NULL) {
+                        fclose(tfp);
+                        tfp = NULL;
+                        fclose(rfp);
+                        rfp = NULL;
+                        return;
+                }
+
+                /*
+                 * Check for a listing line number if required
+                 */
+                if (gcntr != -1) {
+                        switch(a_bytes) {
+                        default:
+                        case 2: n = 30; break;
+                        case 3:
+                        case 4: n = 38; break;
+                        }
+                        if (!dgt(RAD10, &rb[n], 1)) {
+                                fprintf(rfp, "%s", rb);
+                                goto loop;
+                        }
+                        gcntr = 0;
+                }
+                gline = 0;
+        }
+
+        /*
+         * Hex Listing
+         */
+#ifdef  LONGINT
+         switch(radix) {
+         default:
+         case 16:
+                r = RAD16;
+                switch(a_bytes) {
+                default:
+                case 2: a = 8; s = 3; n = 3; m = 4; u = 6; afrmt = "%04lX"; break;
+                case 3: a = 13; s = 3; n = 6; m = 6; u = 7; afrmt = "%06lX"; break;
+                case 4: a = 13; s = 3; n = 4; m = 8; u = 7; afrmt = "%08lX"; break;
+                }
+                frmt = " %02X"; break;
+        case 10:
+                r = RAD10;
+                switch(a_bytes) {
+                default:
+                case 2: a = 10; s = 4; n = 4; m = 5; u = 4; afrmt = "%05lu"; break;
+                case 3: a = 14; s = 4; n = 5; m = 8; u = 5; afrmt = "%08lu"; break;
+                case 4: a = 14; s = 4; n = 3; m = 10; u = 5; afrmt = "%010lu"; break;
+                }
+                frmt = " %03u"; break;
+        case 8:
+                r = RAD8;
+                switch(a_bytes) {
+                default:
+                case 2: a = 10; s = 4; n = 3; m = 6; u = 4; afrmt = "%06lo"; break;
+                case 3: a = 14; s = 4; n = 5; m = 8; u = 5; afrmt = "%08lo"; break;
+                case 4: a = 14; s = 4; n = 2; m = 11; u = 5; afrmt = "%011lo"; break;
+                }
+                frmt = " %03o"; break;
+                        }
+#else
+         switch(radix) {
+         default:
+         case 16:
+                r = RAD16;
+                switch(a_bytes) {
+                default:
+                case 2: a = 8; s = 3; n = 3; m = 4; u = 6; afrmt = "%04X"; break;
+                case 3: a = 13; s = 3; n = 6; m = 6; u = 7; afrmt = "%06X"; break;
+                case 4: a = 13; s = 3; n = 4; m = 8; u = 7; afrmt = "%08X"; break;
+                }
+                frmt = " %02X"; break;
+        case 10:
+                r = RAD10;
+                switch(a_bytes) {
+                default:
+                case 2: a = 10; s = 4; n = 4; m = 5; u = 4; afrmt = "%05u"; break;
+                case 3: a = 14; s = 4; n = 5; m = 8; u = 5; afrmt = "%08u"; break;
+                case 4: a = 14; s = 4; n = 3; m = 10; u = 5; afrmt = "%010u"; break;
+                }
+                frmt = " %03u"; break;
+        case 8:
+                r = RAD8;
+                switch(a_bytes) {
+                default:
+                case 2: a = 10; s = 4; n = 3; m = 6; u = 4; afrmt = "%06o"; break;
+                case 3: a = 14; s = 4; n = 5; m = 8; u = 5; afrmt = "%08o"; break;
+                case 4: a = 14; s = 4; n = 2; m = 11; u = 5; afrmt = "%011o"; break;
+                }
+                frmt = " %03o"; break;
+        }
+#endif
+        /*
+         * Data Byte Pointer
+         */
+        if (gcntr == -1) {
+                rp = &rb[a];
+        } else {
+                rp = &rb[a + (s * gcntr)];
+        }
+        /*
+         * Number must be of proper radix
+         */
+        if (!dgt(r, rp, s-1)) {
+                fprintf(rfp, "%s", rb);
+                gline = 1;
+                goto loop;
+        }
+        /*
+         * Output new data value, overwrite relocation codes
+         */
+        sprintf(str, frmt, v);
+        strncpy(rp-1, str, s);
+        if (gcntr == -1) {
+                gcntr = 0;
+        }
+        /*
+         * Output relocated code address
+         */
+        if (gcntr == 0) {
+                if (dgt(r, &rb[n], m)) {
+                        sprintf(str, afrmt, cpc);
+                        strncpy(&rb[n], str, m);
+                }
+        }
+        /*
+         * Output an error line if required
+         */
+        if (err) {
+                switch(ASxxxx_VERSION) {
+                case 3:
+                        fprintf(rfp, "?ASlink-Warning-%s\n", errmsg3[err]);
+                        break;
+
+                default:
+                        break;
+                }
+        }
+        /*
+         * Fix 'u' if [nn], cycles, is specified
+         */
+        if (rb[a + (s*u) - 1] == CYCNT_END) {
+                u -= 1;
+        }
+        /*
+         * Output text line when updates finished
+         */
+        if (++gcntr == u) {
+                fprintf(rfp, "%s", rb);
+                gline = 1;
+                gcntr = -1;
+        }
+}
diff --git a/Kernel/tools/bankld/lkmain.c b/Kernel/tools/bankld/lkmain.c
new file mode 100644 (file)
index 0000000..f68e8f9
--- /dev/null
@@ -0,0 +1,1896 @@
+/* lkmain.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ */
+
+#include "aslink.h"
+
+/*)Module       lkmain.c
+ *
+ *      The module lkmain.c contains the functions which
+ *      (1) input the linker options, parameters, and specifications
+ *      (2) perform a two pass link
+ *      (3) produce the appropriate linked data output and/or
+ *          link map file and/or relocated listing files.
+ *
+ *      lkmain.c contains the following functions:
+ *              FILE *  afile()
+ *              VOID    bassav()
+ *              VOID    gblsav()
+ *              int     intsiz()
+ *              VOID    link_main()
+ *              VOID    lkexit()
+ *              int     fndext()
+ *              int     fndidx()
+ *              int     main()
+ *              VOID    map()
+ *              int     parse()
+ *              VOID    doparse()
+ *              VOID    setgbl()
+ *              VOID    usage()
+ *
+ *      lkmain.c contains the following local variables:
+ *              char *  usetext[]       array of pointers to the
+ *                                      command option tect lines
+ *
+ */
+
+/* sdld 8051 specific */
+/*JCF:  Creates some of the default areas so they are allocated in the right order.*/
+void Areas51 (void)
+{
+        char * rel[] = {
+                "XH",
+                "H 7 areas 0 global symbols",
+                "A _CODE size 0 flags 0",               /*Each .rel has one, so...*/
+                "A REG_BANK_0 size 0 flags 4",  /*Register banks are overlayable*/
+                "A REG_BANK_1 size 0 flags 4",
+                "A REG_BANK_2 size 0 flags 4",
+                "A REG_BANK_3 size 0 flags 4",
+                "A BSEG size 0 flags 80",               /*BSEG must be just before BITS*/
+                "A BSEG_BYTES size 0 flags 0",  /*Size will be obtained from BSEG in lnkarea()*/
+                ""
+        };
+
+        char * rel2[] = {
+                "XH",
+                "H C areas 0 global symbols",
+                "A _CODE size 0 flags 0",               /*Each .rel has one, so...*/
+                "A REG_BANK_0 size 0 flags 4",  /*Register banks are overlayable*/
+                "A REG_BANK_1 size 0 flags 4",
+                "A REG_BANK_2 size 0 flags 4",
+                "A REG_BANK_3 size 0 flags 4",
+                "A BSEG size 0 flags 80",               /*BSEG must be just before BITS*/
+                "A BSEG_BYTES size 0 flags 0",  /*Size will be obtained from BSEG in lnkarea()*/
+                "A BIT_BANK size 0 flags 4",    /*Bit register bank is overlayable*/
+                "A DSEG size 0 flags 0",
+                "A OSEG size 0 flags 4",
+                "A ISEG size 0 flags 0",
+                "A SSEG size 0 flags 4",
+                ""
+        };
+        int j;
+        struct sym * sp;
+
+        if (packflag) {
+                for (j = 0; rel2[j][0] != 0; j++) {
+                        ip = rel2[j];
+                        link_main();
+                }
+        }
+        else {
+                for (j = 0; rel[j][0] != 0; j++) {
+                        ip = rel[j];
+                        link_main();
+                }
+        }
+
+        /*Set the start address of the default areas:*/
+        for (ap = areap; ap; ap = ap->a_ap) {
+                /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr = 0x00; ap->a_bset = 1; }
+                else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr = 0x08; ap->a_bset = 1; }
+                else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr = 0x10; ap->a_bset = 1; }
+                else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr = 0x18; ap->a_bset = 1; }
+                else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr = 0x20; ap->a_bset = 1; }
+                else if (TARGET_IS_8051 && !strcmp(ap->a_id, "SSEG")) {
+                        if (stacksize) ap->a_axp->a_size = stacksize;
+                }
+        }
+
+        sp = lkpsym("l_IRAM", 1);
+        sp->s_addr = ((iram_size>0) && (iram_size<=0x100)) ? iram_size : 0x0100;
+        sp->s_axp = NULL;
+        sp->s_type |= S_DEF;
+}
+/* end sdld 8051 specific */
+
+/*)Function     int     main(argc,argv)
+ *
+ *              int     argc            number of command line arguments + 1
+ *              char *  argv[]          array of pointers to the command line
+ *                                      arguments
+ *
+ *      The function main() evaluates the command line arguments to
+ *      determine if the linker parameters are to input through 'stdin'
+ *      or read from a command file.  The functions nxtline() and parse()
+ *      are to input and evaluate the linker parameters.  The linking process
+ *      proceeds by making the first pass through each .rel file in the order
+ *      presented to the linker.  At the end of the first pass the setarea(),
+ *      lnkarea(), setgbl(), and symdef() functions are called to evaluate
+ *      the base address terms, link all areas, define global variables,
+ *      and look for undefined symbols.  Following these routines a linker
+ *      map file may be produced and the linker output files may be opened.
+ *      The second pass through the .rel files will output the linked data
+ *      in one of the supported formats.
+ *
+ *      local variables:
+ *              int     c               character from argument string
+ *              int     i               loop counter
+ *              int     j               loop counter
+ *              int     k               loop counter
+ *
+ *      global variables:
+ *                                      text line in ib[]
+ *              lfile   *cfp            The pointer *cfp points to the
+ *                                      current lfile structure
+ *              char    ctype[]         array of character types, one per
+ *                                      ASCII character
+ *              lfile   *filep          The pointer *filep points to the
+ *                                      beginning of a linked list of
+ *                                      lfile structures.
+ *              head    *hp             Pointer to the current
+ *                                      head structure
+ *              char    ib[NINPUT]      .rel file text line
+ *              char    *ip             pointer into the .rel file
+ *              lfile   *linkp          pointer to first lfile structure
+ *                                      containing an input .rel file
+ *                                      specification
+ *              int     lkerr           error flag
+ *              int     oflag           Output file type flag
+ *              int     objflg          Linked file/library output object flag
+ *              int     pass            linker pass number
+ *              int     pflag           print linker command file flag
+ *              int     radix           current number conversion radix
+ *              FILE    *sfp            The file handle sfp points to the
+ *                                      currently open file
+ *              lfile   *startp         aslink startup file structure
+ *              FILE *  stdout          c_library
+ *
+ *      functions called:
+ *              VOID    chkbank()       lkbank.c
+ *              int     fclose()        c_library
+ *              int     fprintf()       c_library
+ *              VOID    library()       lklibr.c
+ *              VOID    link_main()     lkmain.c
+ *              VOID    lkexit()        lkmain.c
+ *              VOID    lkfopen()       lkbank.c
+ *              VOID    lnkarea()       lkarea.c
+ *              VOID    map()           lkmain.c
+ *              VOID    new()           lksym.c
+ *              int     nxtline()       lklex.c
+ *              int     parse()         lkmain.c
+ *              VOID    reloc()         lkreloc.c
+ *              VOID    search()        lklibr.c
+ *              VOID    setarea()       lkarea.c
+ *              VOID    setbank()       lkbank.c
+ *              VOID    setgbl()        lkmain.c
+ *              char *  sprintf()       c_library
+ *              VOID    symdef()        lksym.c
+ *              VOID    usage()         lkmain.c
+ *              int     fndidx()        lkmain.c
+ *
+ *      side effects:
+ *              Completion of main() completes the linking process
+ *              and may produce a map file (.map) and/or a linked
+ *              data files (.ihx or .s19) and/or one or more
+ *              relocated listing files (.rst).
+ */
+
+int
+main(int argc, char *argv[])
+{
+        int c, i, j, k;
+
+        if (intsiz() < 4) {
+                fprintf(stderr, "?ASlink-Error-Size of INT32 is not 32 bits or larger.\n\n");
+                exit(ER_FATAL);
+        }
+
+        /* sdas specific */
+        /* sdas initialization */
+        sdld_init(argv[0]);
+
+        /* use these defaults for parsing the .lnk script */
+        a_bytes = 4;
+        a_mask = 0xFFFFFFFF;
+        s_mask = 0x80000000;
+        v_mask = 0x7FFFFFFF;
+        /* end sdas specific */
+
+        if (!is_sdld())
+                fprintf(stdout, "\n");
+
+        startp = (struct lfile *) new (sizeof (struct lfile));
+        startp->f_idp = "";
+
+        pflag = 1;
+
+        for(i=1; i<argc; i++) {
+                ip = ib;
+                if(argv[i][0] == '-') {
+                        j = i;
+                        k = 1;
+                        while((c = argv[j][k]) != '\0') {
+                                ip = ib;
+                                sprintf(ip, "-%c", c);
+                                switch(c) {
+
+                                /*
+                                 * Options with arguments
+                                 */
+                                case 'b':
+                                case 'B':
+
+                                case 'g':
+                                case 'G':
+
+                                case 'k':
+                                case 'K':
+
+                                case 'l':
+                                case 'L':
+
+                                case 'f':
+                                case 'F':
+
+                                case 'I':
+                                case 'X':
+                                case 'C':
+                                case 'S':
+                                        strcat(ip, " ");
+                                        if (i < argc - 1)
+                                                strcat(ip, argv[++i]);
+                                       else
+                                                strcpy(ip, "");
+                                        break;
+                                /*
+                                 * Preprocess these commands
+                                 */
+                                case 'n':
+                                case 'N':
+                                        pflag = 0;
+                                        break;
+
+                                case 'p':
+                                case 'P':
+                                        pflag = 1;
+                                        break;
+
+                                /*
+                                 * Options without arguments
+                                 */
+                                default:
+                                        break;
+                                }
+                                if(pflag)
+                                        fprintf(stdout, "ASlink >> %s\n", ip);
+                                parse();
+                                k++;
+                        }
+                } else {
+                        strcpy(ip, argv[i]);
+                        if(pflag)
+                                fprintf(stdout, "ASlink >> %s\n", ip);
+                        parse();
+                }
+        }
+
+        if (linkp == NULL)
+                usage(ER_FATAL);
+
+        /*
+         * If no input file is specified
+         * then assume a single file with
+         * the same name as the output file.
+         */
+        if (lfp == linkp) {
+                lfp->f_flp = (struct lfile *) new (sizeof (struct lfile));
+                lfp = lfp->f_flp;
+                lfp->f_idp = strsto(linkp->f_idp);
+                lfp->f_idx = fndidx(linkp->f_idp);
+                lfp->f_obj = objflg;
+                lfp->f_type = F_REL;
+        }
+
+        syminit();
+
+#if SDCDB
+        /*
+         * Open SDCC Debug output file
+         */
+        SDCDBfopen();
+#endif
+
+        for (pass=0; pass<2; ++pass) {
+                cfp = NULL;
+                sfp = NULL;
+                filep = linkp->f_flp;
+                hp = NULL;
+                radix = 10;
+
+                /* sdld specific */
+                if (TARGET_IS_8051)
+                        Areas51(); /*JCF: Create the default 8051 areas in the right order*/
+                /* end sdld specific */
+
+                while (nxtline()) {
+                        ip = ib;
+                        link_main();
+                }
+                if (pass == 0) {
+                        /*
+                         * Search libraries for global symbols
+                         */
+                        search();
+
+                        /* sdas specific */
+                        /* use these defaults for parsing the .lk script */
+                        a_bytes = 4;
+                        a_mask = 0xFFFFFFFF;
+                        s_mask = 0x80000000;
+                        v_mask = 0x7FFFFFFF;
+                        /* end sdas specific */
+
+                        /*
+                         * Set area base addresses.
+                         */
+                        setarea();
+                        /*
+                         * Set bank base addresses.
+                         */
+                        setbank();
+                        /*
+                         * Link all area addresses.
+                         */
+                        if (!packflag)
+                                lnkarea();
+                        else {
+                                /* sdld 8051 specific */
+                                lnkarea2();
+                                /* end sdld 8051 specific */
+                        }
+                        /*
+                         * Check bank size limits.
+                         */
+                        chkbank(stderr);
+                        /*
+                         * Process global definitions.
+                         */
+                        setgbl();
+                        /*
+                         * Check for undefined globals.
+                         */
+                        symdef(stderr);
+#if NOICE
+                        /*
+                         * Open NoICE output file
+                         */
+                        NoICEfopen();
+#endif
+                        /*
+                         * Output Link Map.
+                         */
+                        map();
+
+                        /* sdld specific */
+                        if (sflag) {    /*JCF: memory usage summary output*/
+                                if (!packflag) {
+                                        if (summary(areap)) lkexit(1);
+                                }
+                                else {
+                                        /* sdld 8051 specific */
+                                        if (summary2(areap)) lkexit(1);
+                                        /* end sdld 8051 specific */
+                                }
+                        }
+
+                        if ((iram_size) && (!packflag))
+                                iramcheck();
+                        /* end sdld specific */
+
+                        /*
+                         * Open output file(s)
+                         */
+                        lkfopen();
+                } else {
+                        /*
+                         * Link in library files
+                         */
+                        library();
+                        /*
+                         * Complete Processing
+                         */
+                        reloc('E');
+                }
+        }
+        if (TARGET_IS_8051) {
+                //JCF:
+                CreateAOMF51();
+        }
+
+        lkexit(lkerr ? ER_ERROR : ER_NONE);
+        return(0);
+}
+
+/*)Function     int     intsiz()
+ *
+ *      The function intsiz() returns the size of INT32
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              none
+ */
+
+int
+intsiz()
+{
+        return(sizeof(a_uint));
+}
+
+/*)Function     VOID    lkexit(i)
+ *
+ *                      int     i       exit code
+ *
+ *      The function lkexit() explicitly closes all open
+ *      files and then terminates the program.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  jfp             file handle for .noi
+ *              FILE *  mfp             file handle for .map
+ *              FILE *  rfp             file hanlde for .rst
+ *              FILE *  sfp             file handle for .rel
+ *              FILE *  tfp             file handle for .lst
+ *
+ *      functions called:
+ *              int     fclose()        c_library
+ *              VOID    exit()          c_library
+ *              VOID    lkfclose()      lkbank.c
+ *
+ *      side effects:
+ *              All files closed. Program terminates.
+ */
+
+VOID
+lkexit(i)
+int i;
+{
+        lkfclose();
+#if NOICE
+        if (jfp != NULL) fclose(jfp);
+#endif
+        if (mfp != NULL) fclose(mfp);
+        if (rfp != NULL) fclose(rfp);
+        if (sfp != NULL) { if (sfp != stdin) fclose(sfp); }
+        if (tfp != NULL) fclose(tfp);
+#if SDCDB
+        if (yfp != NULL) fclose(yfp);
+#endif
+        exit(i);
+}
+
+/*)Function     link_main()
+ *
+ *      The function link_main() evaluates the directives for each line of
+ *      text read from the .rel file(s).  The valid directives processed
+ *      are:
+ *              X, D, Q, H, M, A, S, T, R, and P.
+ *
+ *      local variables:
+ *              int     c               first non blank character of a line
+ *
+ *      global variables:
+ *              head    *headp          The pointer to the first
+ *                                      head structure of a linked list
+ *              head    *hp             Pointer to the current
+ *                                      head structure
+ *              int     a_bytes         T Line address bytes
+ *              int     hilo            Byte ordering
+ *              int     pass            linker pass number
+ *              int     radix           current number conversion radix
+ *
+ *      functions called:
+ *              char    endline()       lklex.c
+ *              VOID    module()        lkhead.c
+ *              VOID    newarea()       lkarea.c
+ *              VOID    newhead()       lkhead.c
+ *              sym *   newsym()        lksym.c
+ *              VOID    NoICEmagic()    lknoice.c
+ *              VOID    reloc()         lkreloc.c
+ *
+ *      side effects:
+ *              Head, area, and symbol structures are created and
+ *              the radix is set as the .rel file(s) are read.
+ */
+
+VOID
+link_main()
+{
+        char c;
+
+        if ((c=endline()) == 0) { return; }
+        switch (c) {
+
+        /* sdld specific */
+        case 'O': /* For some important sdcc options */
+                if (is_sdld() && pass == 0) {
+                        if (NULL == optsdcc) {
+                                optsdcc = strsto(&ip[1]);
+                                optsdcc_module = hp->m_id;
+                        }
+                        else {
+                                if (strcmp(optsdcc, &ip[1]) != 0) {
+                                        fprintf(stderr,
+                                                "?ASlink-Warning-Conflicting sdcc options:\n"
+                                                "   \"%s\" in module \"%s\" and\n"
+                                                "   \"%s\" in module \"%s\".\n",
+                                                optsdcc, optsdcc_module, &ip[1], hp->m_id);
+                                        lkerr++;
+                                }
+                        }
+                }
+                break;
+        /* end sdld specific */
+
+        case 'X':
+        case 'D':
+        case 'Q':
+                ASxxxx_VERSION = 3;
+                a_bytes = 2;    /* use default if unspecified */
+                hilo = 0;       /* use default if unspecified */
+                if (c == 'X') { radix = 16; } else
+                if (c == 'D') { radix = 10; } else
+                if (c == 'Q') { radix = 8;  }
+
+                while ((c = get()) != 0) {
+                        switch(c) {
+                        case 'H':
+                                hilo = 1;
+                                break;
+
+                        case 'L':
+                                hilo = 0;
+                                break;
+
+                        case '2':
+                                a_bytes = 2;
+                                break;
+
+                        case '3':
+                                a_bytes = 3;
+                                break;
+
+                        case '4':
+                                a_bytes = 4;
+                                break;
+
+                        default:
+                                break;
+                        }
+                }
+#ifdef  LONGINT
+                switch(a_bytes) {
+                default:
+                        a_bytes = 2;
+                case 2:
+                        a_mask = 0x0000FFFFl;
+                        s_mask = 0x00008000l;
+                        v_mask = 0x00007FFFl;
+                        break;
+
+                case 3:
+                        a_mask = 0x00FFFFFFl;
+                        s_mask = 0x00800000l;
+                        v_mask = 0x007FFFFFl;
+                        break;
+
+                case 4:
+                        a_mask = 0xFFFFFFFFl;
+                        s_mask = 0x80000000l;
+                        v_mask = 0x7FFFFFFFl;
+                        break;
+                }
+#else
+                switch(a_bytes) {
+                default:
+                        a_bytes = 2;
+                case 2:
+                        a_mask = 0x0000FFFF;
+                        s_mask = 0x00008000;
+                        v_mask = 0x00007FFF;
+                        break;
+
+                case 3:
+                        a_mask = 0x00FFFFFF;
+                        s_mask = 0x00800000;
+                        v_mask = 0x007FFFFF;
+                        break;
+
+                case 4:
+                        a_mask = 0xFFFFFFFF;
+                        s_mask = 0x80000000;
+                        v_mask = 0x7FFFFFFF;
+                        break;
+                }
+#endif
+                break;
+
+        case 'H':
+                if (pass == 0) {
+                        newhead();
+                } else {
+                        if (hp == 0) {
+                                hp = headp;
+                        } else {
+                                hp = hp->h_hp;
+                        }
+                }
+                sdp.s_area = NULL;
+                sdp.s_areax = NULL;
+                sdp.s_addr = 0;
+                break;
+
+        case 'M':
+                if (pass == 0)
+                        module();
+                break;
+
+        case 'A':
+                if (pass == 0)
+                        newarea();
+                if (sdp.s_area == NULL) {
+                        sdp.s_area = areap;
+                        sdp.s_areax = areap->a_axp;
+                        sdp.s_addr = 0;
+                }
+                break;
+
+        case 'S':
+                if (pass == 0)
+                        newsym();
+                break;
+
+        case 'T':
+        case 'R':
+        case 'P':
+                if (pass == 0)
+                        break;
+                reloc(c);
+                break;
+
+#if NOICE
+        case ';':
+                unget(c);
+                NoICEmagic();
+                break;
+#endif
+
+        default:
+                break;
+        }
+}
+
+/*)Function     VOID    map()
+ *
+ *      The function map() opens the output map file and calls the various
+ *      routines to
+ *      (1) output the variables in each area,
+ *      (2) list the files processed with module names,
+ *      (3) list the libraries file processed,
+ *      (4) list base address definitions,
+ *      (5) list global variable definitions, and
+ *      (6) list any undefined variables.
+ *
+ *      local variables:
+ *              int     i               counter
+ *              head *  hdp             pointer to head structure
+ *              lbfile *lbfh            pointer to library file structure
+ *
+ *      global variables:
+ *              area    *ap             Pointer to the current
+ *                                      area structure
+ *              area    *areap          The pointer to the first
+ *                                      area structure of a linked list
+ *              base    *basep          The pointer to the first
+ *                                      base structure
+ *              base    *bsp            Pointer to the current
+ *                                      base structure
+ *              lfile   *filep          The pointer *filep points to the
+ *                                      beginning of a linked list of
+ *                                      lfile structures.
+ *              globl   *globlp         The pointer to the first
+ *                                      globl structure
+ *              globl   *gsp            Pointer to the current
+ *                                      globl structure
+ *              head    *headp          The pointer to the first
+ *                                      head structure of a linked list
+ *              lbfile  *lbfhead        The pointer to the first
+ *                                      lbfile structure of a linked list
+ *              lfile   *linkp          pointer to first lfile structure
+ *                                      containing an input REL file
+ *                                      specification
+ *              int     lop             current line number on page
+ *              int     mflag           Map output flag
+ *              FILE    *mfp            Map output file handle
+ *              int     page            current page number
+ *
+ *      functions called:
+ *              FILE *  afile()         lkmain.c
+ *              int     fprintf()       c_library
+ *              VOID    lkexit()        lkmain.c
+ *              VOID    lstarea()       lklist.c
+ *              VOID    newpag()        lklist.c
+ *              VOID    chkbank()       lkbank.c
+ *              VOID    symdef()        lksym.c
+ *
+ *      side effects:
+ *              The map file is created.
+ */
+
+VOID
+map(void)
+{
+        int i;
+        struct head *hdp;
+        struct lbfile *lbfh;
+
+        if (mflag == 0) return;
+
+        /*
+         * Open Map File
+         */
+        mfp = afile(linkp->f_idp, "map", 1);
+        if (mfp == NULL) {
+                lkexit(ER_FATAL);
+        }
+
+        /*
+         * Output Map Bank/Area Lists
+         */
+        page = 0;
+        lop  = NLPP;
+        for (bp = bankp; bp != NULL; bp = bp->b_bp) {
+                for (ap = areap; ap != NULL; ap = ap->a_ap) {
+                        if (ap->a_bp == bp)
+                                lstarea(ap, bp);
+                }
+        }
+
+        /*
+         * List Linked Files
+         */
+        newpag(mfp);
+        fprintf(mfp, "\nFiles Linked                              [ module(s) ]\n\n");
+        hdp = headp;
+        filep = linkp->f_flp;
+        while (filep) {
+                if (strlen (filep->f_idp) > 40)
+                        fprintf(mfp, "%s\n%40s  [ ", filep->f_idp, "");
+                else
+                        fprintf(mfp, "%-40.40s  [ ", filep->f_idp);
+                i = 0;
+                while ((hdp != NULL) && (hdp->h_lfile == filep)) {
+                        if (i)
+                                fprintf(mfp, ",\n%44s", "");
+                        fprintf(mfp, "%-.32s", hdp->m_id);
+                        hdp = hdp->h_hp;
+                        i++;
+                }
+                fprintf(mfp, " ]\n");
+                filep = filep->f_flp;
+        }
+        fprintf(mfp, "\n");
+        /*
+         * List Linked Libraries
+         */
+        if (lbfhead != NULL) {
+                fprintf(mfp, "\nLibraries Linked                          [ object file ]\n\n");
+                for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
+                        if (strlen (lbfh->libspc) > 40)
+                                fprintf(mfp, "%s\n%40s  [ %-.32s ]\n",
+                                        lbfh->libspc, "", lbfh->relfil);
+                        else
+                                fprintf(mfp, "%-40.40s  [ %-.32s ]\n",
+                                        lbfh->libspc, lbfh->relfil);
+                }
+                fprintf(mfp, "\n");
+        }
+        /*
+         * List Base Address Definitions
+         */
+        if (basep) {
+                newpag(mfp);
+                fprintf(mfp, "\nUser Base Address Definitions\n\n");
+                bsp = basep;
+                while (bsp) {
+                        fprintf(mfp, "%s\n", bsp->b_strp);
+                        bsp = bsp->b_base;
+                }
+        }
+        /*
+         * List Global Definitions
+         */
+        if (globlp) {
+                newpag(mfp);
+                fprintf(mfp, "\nUser Global Definitions\n\n");
+                gsp = globlp;
+                while (gsp) {
+                        fprintf(mfp, "%s\n", gsp->g_strp);
+                        gsp = gsp->g_globl;
+                }
+        }
+        fprintf(mfp, "\n\f");
+        chkbank(mfp);
+        symdef(mfp);
+}
+
+/*)Function     int     parse()
+ *
+ *      The function parse() evaluates all command line or file input
+ *      linker directives and updates the appropriate variables.
+ *
+ *      local variables:
+ *              int     c               character value
+ *              int     sv_type         save type of processing
+ *              char    fid[]           file id string
+ *
+ *      global variables:
+ *              char    ctype[]         array of character types, one per
+ *                                      ASCII character
+ *              lfile   *lfp            pointer to current lfile structure
+ *                                      being processed by parse()
+ *              lfile   *linkp          pointer to first lfile structure
+ *                                      containing an input REL file
+ *                                      specification
+ *              int     mflag           Map output flag
+ *              int     oflag           Output file type flag
+ *              int     objflg          Linked file/library output object flag
+ *              int     pflag           print linker command file flag
+ *              FILE *  stderr          c_library
+ *              int     uflag           Relocated listing flag
+ *              int     xflag           Map file radix type flag
+ *              int     wflag           Wide listing format
+ *              int     zflag           Disable symbol case sensitivity
+ *
+ *      Functions called:
+ *              VOID    addlib()        lklibr.c
+ *              VOID    addpath()       lklibr.c
+ *              VOID    bassav()        lkmain.c
+ *              VOID    doparse()       lkmain.c
+ *              int     fprintf()       c_library
+ *              VOID    gblsav()        lkmain.c
+ *              VOID    getfid()        lklex.c
+ *              int     get()           lklex.c
+ *              int     getnb()         lklex.c
+ *              VOID    lkexit()        lkmain.c
+ *              char *  strsto()        lksym.c
+ *              int     strlen()        c_library
+ *              int     fndidx()        lkmain.c
+ *
+ *      side effects:
+ *              Various linker flags are updated and the linked
+ *              structure lfile is created.
+ */
+
+int
+parse()
+{
+        int c;
+        int sv_type;
+        char fid[NINPUT];
+
+        while ((c = getnb()) != 0) {
+                /* sdld specific */
+                if ( c == ';')
+                        return(0);
+                /* end sdld specific */
+                if ( c == '-') {
+                        while (ctype[c=get()] & LETTER) {
+                                switch(c) {
+
+                                case 'C':
+                                        if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
+                                                codesav();
+                                                return(0);
+                                        }
+                                        // else fall through
+                                case 'c':
+                                        if (startp->f_type != 0)
+                                                break;
+                                        startp->f_type = F_STD;
+                                        doparse();
+                                        return(0);
+
+                                case 'f':
+                                case 'F':
+                                        if (startp->f_type == F_LNK)
+                                                return(0);
+                                        unget(getnb());
+                                        if (*ip == 0)
+                                                usage(ER_FATAL);
+                                        sv_type = startp->f_type;
+                                        startp->f_idp = strsto(ip);
+                                        startp->f_idx = fndidx(ip);
+                                        startp->f_type = F_LNK;
+                                        doparse();
+                                        if (sv_type == F_STD) {
+                                                cfp = NULL;
+                                                sfp = NULL;
+                                                startp->f_type = F_STD;
+                                                filep = startp;
+                                        }
+                                        return(0);
+
+                                case 'I':
+                                        if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
+                                                iramsav();
+                                                return(0);
+                                        }
+                                        // else fall through
+                                case 'i':
+                                        oflag = 1;
+                                        break;
+
+                                case 'S':
+                                        if (TARGET_IS_8051) {
+                                                unget(getnb());
+                                                if (ip && *ip)
+                                                {
+                                                        stacksize = expr(0);
+                                                        if (stacksize > 256) stacksize = 256;
+                                                        else if (stacksize < 0) stacksize = 0;
+                                                }
+                                                return(0);
+                                        }
+                                        // else fall through
+                                case 's':
+                                        oflag = 2;
+                                        break;
+
+                                case 't':
+                                case 'T':
+                                        oflag = 3;
+                                        break;
+
+                                case 'o':
+                                case 'O':
+                                        objflg = 0;
+                                        break;
+
+                                case 'v':
+                                case 'V':
+                                        objflg = 1;
+                                        break;
+
+                                case 'M':
+                                        /*JCF: memory usage summary output*/
+                                        if (is_sdld()) {
+                                                sflag = 1;
+                                                break;
+                                        }
+                                        // else fall through
+                                case 'm':
+                                        mflag = 1;
+                                        break;
+
+#if NOICE
+                                case 'j':
+                                case 'J':
+                                        jflag = 1;
+                                        break;
+#endif
+
+                                case 'r':
+                                case 'R':
+                                        if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB))
+                                                rflag = 1;
+                                        else
+                                                goto err;
+                                        break;
+
+                                case 'u':
+                                case 'U':
+                                        uflag = 1;
+                                        break;
+
+                                case 'X':
+                                        if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
+                                                xramsav();
+                                                return(0);
+                                        }
+                                        // else fall through
+                                case 'x':
+                                        xflag = 0;
+                                        break;
+
+                                case 'q':
+                                case 'Q':
+                                        xflag = 1;
+                                        break;
+
+                                case 'd':
+                                case 'D':
+                                        xflag = 2;
+                                        break;
+
+                                case 'E':
+                                        if (TARGET_IS_6808) {
+                                                oflag = 4;
+                                                break;
+                                        }
+                                        // else fall through
+                                case 'e':
+                                        return(1);
+
+                                case 'n':
+                                case 'N':
+                                        pflag = 0;
+                                        break;
+
+                                case 'p':
+                                case 'P':
+                                        pflag = 1;
+                                        break;
+
+                                case 'b':
+                                case 'B':
+                                        bassav();
+                                        return(0);
+
+                                case 'g':
+                                case 'G':
+                                        gblsav();
+                                        return(0);
+
+                                case 'k':
+                                case 'K':
+                                        addpath();
+                                        return(0);
+
+                                case 'l':
+                                case 'L':
+                                        addlib();
+                                        return(0);
+
+                                case 'w':
+                                case 'W':
+                                        wflag = 1;
+                                        break;
+
+#if SDCDB
+                                case 'Y':
+                                        if (TARGET_IS_8051) {
+                                                unget(getnb());
+                                                packflag=1;
+                                                break;
+                                        }
+                                        // else fall through
+                                case 'y':
+                                        yflag = 1;
+                                        break;
+#endif
+
+                                case 'z':
+                                case 'Z':
+                                        zflag = 1;
+                                        break;
+
+                                default:
+                                err:
+                                        fprintf(stderr,
+                                            "Unknown option -%c ignored\n", c);
+                                        break;
+                                }
+                        }
+                        /* sdld specific */
+                        if ( c == ';')
+                                return(0);
+                        /* end sdld specific */
+                } else
+                if (!(ctype[c] & ILL)) {
+                        if (linkp == NULL) {
+                                linkp = (struct lfile *)
+                                        new (sizeof (struct lfile));
+                                lfp = linkp;
+                                lfp->f_type = F_OUT;
+                        } else {
+                                lfp->f_flp = (struct lfile *)
+                                                new (sizeof (struct lfile));
+                                lfp = lfp->f_flp;
+                                lfp->f_type = F_REL;
+                        }
+                        getfid(fid, c);
+                        lfp->f_idp = strsto(fid);
+                        lfp->f_obj = objflg;
+                } else {
+                        fprintf(stderr, "Invalid input\n");
+                        lkexit(ER_FATAL);
+                }
+        }
+        return(0);
+}
+
+/*)Function     VOID    doparse()
+ *
+ *      The function doparse() evaluates all interactive
+ *      command line or file input linker directives and
+ *      updates the appropriate variables.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  stdin           standard input
+ *              FILE *  stdout          standard output
+ *              lfile   *cfp            The pointer *cfp points to the
+ *                                      current lfile structure
+ *              FILE    *sfp            The file handle sfp points to the
+ *                                      currently open file
+ *              char    ib[NINPUT]      .rel file text line
+ *              char    *ip             pointer into the .rel file
+ *              lfile   *filep          The pointer *filep points to the
+ *                                      beginning of a linked list of
+ *                                      lfile structures.
+ *              lfile   *startp         asmlnk startup file structure
+ *              int     pflag           print linker command file flag
+ *
+ *      Functions called:
+ *              int     fclose()        c_library
+ *              int     fprintf()       c_library
+ *              VOID    getfid()        lklex.c
+ *              int     nxtline()       lklex.c
+ *              int     parse()         lkmain.c
+ *
+ *      side effects:
+ *              Various linker flags are updated and the linked
+ *              structure lfile may be updated.
+ */
+
+VOID
+doparse()
+{
+        cfp = NULL;
+        sfp = NULL;
+        filep = startp;
+        while (1) {
+                ip = ib;
+                if (nxtline() == 0)
+                        break;
+                if (pflag && cfp->f_type != F_STD)
+                        fprintf(stdout, "ASlink >> %s\n", ip);
+                if (*ip == 0 || parse())
+                        break;
+        }
+        if((sfp != NULL) && (sfp != stdin)) {
+                fclose(sfp);
+        }
+        sfp = NULL;
+        startp->f_idp = "";
+        startp->f_idx = 0;
+        startp->f_type = 0;
+}
+
+/*)Function     VOID    bassav()
+ *
+ *      The function bassav() creates a linked structure containing
+ *      the base address strings input to the linker.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              base    *basep          The pointer to the first
+ *                                      base structure
+ *              base    *bsp            Pointer to the current
+ *                                      base structure
+ *              char    *ip             pointer into the REL file
+ *                                      text line in ib[]
+ *
+ *       functions called:
+ *              int     getnb()         lklex.c
+ *              VOID *  new()           lksym.c
+ *              int     strlen()        c_library
+ *              char *  strcpy()        c_library
+ *              VOID    unget()         lklex.c
+ *
+ *      side effects:
+ *              The basep structure is created.
+ */
+
+VOID
+bassav()
+{
+        if (basep == NULL) {
+                basep = (struct base *)
+                        new (sizeof (struct base));
+                bsp = basep;
+        } else {
+                bsp->b_base = (struct base *)
+                                new (sizeof (struct base));
+                bsp = bsp->b_base;
+        }
+        unget(getnb());
+        bsp->b_strp = (char *) new (strlen(ip)+1);
+        strcpy(bsp->b_strp, ip);
+}
+
+
+/*)Function     VOID    gblsav()
+ *
+ *      The function gblsav() creates a linked structure containing
+ *      the global variable strings input to the linker.
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              globl   *globlp         The pointer to the first
+ *                                      globl structure
+ *              globl   *gsp            Pointer to the current
+ *                                      globl structure
+ *              char    *ip             pointer into the REL file
+ *                                      text line in ib[]
+ *              int     lkerr           error flag
+ *
+ *      functions called:
+ *              int     getnb()         lklex.c
+ *              VOID *  new()           lksym.c
+ *              int     strlen()        c_library
+ *              char *  strcpy()        c_library
+ *              VOID    unget()         lklex.c
+ *
+ *      side effects:
+ *              The globlp structure is created.
+ */
+
+VOID
+gblsav()
+{
+        if (globlp == NULL) {
+                globlp = (struct globl *)
+                        new (sizeof (struct globl));
+                gsp = globlp;
+        } else {
+                gsp->g_globl = (struct globl *)
+                                new (sizeof (struct globl));
+                gsp = gsp->g_globl;
+        }
+        unget(getnb());
+        gsp->g_strp = (char *) new (strlen(ip)+1);
+        strcpy(gsp->g_strp, ip);
+}
+
+
+/*)Function     VOID    setgbl()
+ *
+ *      The function setgbl() scans the global variable lines in the
+ *      globlp structure, evaluates the arguments, and sets a variable
+ *      to this value.
+ *
+ *      local variables:
+ *              int     v               expression value
+ *              char    id[]            base id string
+ *              sym *   sp              pointer to a symbol structure
+ *
+ *      global variables:
+ *              char    *ip             pointer into the REL file
+ *                                      text line in ib[]
+ *              globl   *globlp         The pointer to the first
+ *                                      globl structure
+ *              globl   *gsp            Pointer to the current
+ *                                      globl structure
+ *              FILE *  stderr          c_library
+ *              int     lkerr           error flag
+ *
+ *       functions called:
+ *              a_uint  expr()          lkeval.c
+ *              int     fprintf()       c_library
+ *              VOID    getid()         lklex.c
+ *              int     getnb()         lklex.c
+ *              sym *   lkpsym()        lksym.c
+ *
+ *      side effects:
+ *              The value of a variable is set.
+ */
+
+VOID
+setgbl()
+{
+        int v;
+        struct sym *sp;
+        char id[NCPS];
+
+        gsp = globlp;
+        while (gsp) {
+                ip = gsp->g_strp;
+                getid(id, -1);
+                if (getnb() == '=') {
+                        v = (int) expr(0);
+                        sp = lkpsym(id, 0);
+                        if (sp == NULL) {
+                                fprintf(stderr,
+                                "No definition of symbol %s\n", id);
+                                lkerr++;
+                        } else {
+                                if (sp->s_type & S_DEF) {
+                                        fprintf(stderr,
+                                        "Redefinition of symbol %s\n", id);
+                                        lkerr++;
+                                        sp->s_axp = NULL;
+                                }
+                                sp->s_addr = v;
+                                sp->s_type |= S_DEF;
+                        }
+                } else {
+                        fprintf(stderr, "No '=' in global expression");
+                        lkerr++;
+                }
+                gsp = gsp->g_globl;
+        }
+}
+
+/*)Function     FILE *  afile(fn, ft, wf)
+ *
+ *              char *  fn              file specification string
+ *              char *  ft              file type string
+ *              int     wf              0 ==>> read
+ *                                      1 ==>> write
+ *                                      2 ==>> binary write
+ *
+ *      The function afile() opens a file for reading or writing.
+ *              (1)     If the file type specification string ft
+ *                      is not NULL then a file specification is
+ *                      constructed with the file path\name in fn
+ *                      and the extension in ft.
+ *              (2)     If the file type specification string ft
+ *                      is NULL then the file specification is
+ *                      constructed from fn.  If fn does not have
+ *                      a file type then the default .rel file
+ *                      type is appended to the file specification.
+ *
+ *      afile() returns a file handle for the opened file or aborts
+ *      the assembler on an open error.
+ *
+ *      local variables:
+ *              int     c               character value
+ *              FILE *  fp              filehandle for opened file
+ *              char *  p1              pointer to filespec string fn
+ *              char *  p2              pointer to filespec string fb
+ *              char *  p3              pointer to filetype string ft
+ *
+ *      global variables:
+ *              char    afspec[]        constructed file specification string
+ *              int     lkerr           error flag
+ *
+ *      functions called:
+ *              int     fndidx()        lkmain.c
+ *              FILE *  fopen()         c_library
+ *              int     fprintf()       c_library
+ *
+ *      side effects:
+ *              File is opened for read or write.
+ */
+
+FILE *
+afile(char *fn, char *ft, int wf)
+{
+        char *p1, *p2;
+        int c;
+        char * frmt;
+        FILE *fp;
+
+        if (strlen(fn) > (FILSPC-7)) {
+                fprintf(stderr, "?ASlink-Error-<filspc too long> : \"%s\"\n", fn);
+                lkerr++;
+                return(NULL);
+        }
+
+        /*
+         * Skip The Path
+         */
+        strcpy(afspec, fn);
+        c = fndidx(afspec);
+
+        /*
+         * Skip to File Extension separator
+         */
+        p1 = strrchr(&afspec[c], FSEPX);
+
+        /*
+         * Copy File Extension
+         */
+        p2 = ft ? ft : "";
+        if (*p2 == 0) {
+                if (p1 == NULL) {
+                        p2 = LKOBJEXT;
+                } else {
+                        p2 = strrchr(&fn[c], FSEPX) + 1;
+                }
+        }
+        if (p1 == NULL) {
+                p1 = &afspec[strlen(afspec)];
+        }
+        *p1++ = FSEPX;
+        while ((c = *p2++) != 0) {
+                if (p1 < &afspec[FILSPC-1])
+                        *p1++ = c;
+        }
+        *p1++ = 0;
+
+        /*
+         * Select Read/Write/Binary Write
+         */
+        switch(wf) {
+        default:
+        case 0: frmt = "r";     break;
+        case 1: frmt = "w";     break;
+#ifdef  DECUS
+        case 2: frmt = "wn";    break;
+#else
+        case 2: frmt = "wb";    break;
+#endif
+        }
+        if ((fp = fopen(afspec, frmt)) == NULL && strcmp(ft,"adb") != 0) { /* Do not complain for optional adb files */
+                fprintf(stderr, "?ASlink-Error-<cannot %s> : \"%s\"\n", wf?"create":"open", afspec);
+                lkerr++;
+        }
+        return (fp);
+}
+
+/*)Function     int     fndidx(str)
+ *
+ *              char *  str             file specification string
+ *
+ *      The function fndidx() scans the file specification string
+ *      to find the index to the file name.  If the file
+ *      specification contains a 'path' then the index will
+ *      be non zero.
+ *
+ *      fndidx() returns the index value.
+ *
+ *      local variables:
+ *              char *  p1              temporary pointer
+ *              char *  p2              temporary pointer
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              char *  strrchr()       c_library
+ *
+ *      side effects:
+ *              none
+ */
+
+int
+fndidx(str)
+char *str;
+{
+        char *p1, *p2;
+
+        /*
+         * Skip Path Delimiters
+         */
+        p1 = str;
+        if ((p2 = strrchr(p1,  ':')) != NULL) { p1 = p2 + 1; }
+        if ((p2 = strrchr(p1,  '/')) != NULL) { p1 = p2 + 1; }
+        if ((p2 = strrchr(p1, '\\')) != NULL) { p1 = p2 + 1; }
+
+        return((int) (p1 - str));
+}
+
+/*)Function     int     fndext(str)
+ *
+ *              char *  str             file specification string
+ *
+ *      The function fndext() scans the file specification string
+ *      to find the file.ext separater.
+ *
+ *      fndext() returns the index to FSEPX or the end of the string.
+ *
+ *      local variables:
+ *              char *  p1              temporary pointer
+ *              char *  p2              temporary pointer
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              char *  strrchr()       c_library
+ *
+ *      side effects:
+ *              none
+ */
+
+int
+fndext(str)
+char * str;
+{
+        char *p1, *p2;
+
+        /*
+         * Find the file separator
+         */
+        p1 = str + strlen(str);
+        if ((p2 = strrchr(str,  FSEPX)) != NULL) { p1 = p2; }
+
+        return((int) (p1 - str));
+}
+
+/* sdld specific */
+/*)Function     VOID    iramsav()
+ *
+ *      The function iramsav() stores the size of the chip's internal RAM.
+ *      This is used after linking to check that variable assignment to this
+ *      dataspace didn't overflow into adjoining segments.      Variables in the
+ *      DSEG, OSEG, and ISEG are assigned to this dataspace.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              char    *ip             pointer into the REL file
+ *                                      text line in ib[]
+ *              unsigned int            size of chip's internal
+ *              iram_size               RAM segment
+ *
+ *       functions called:
+ *              int     getnb()         lklex.c
+ *              VOID    unget()         lklex.c
+ *              a_uint  expr()          lkeval.c
+ *
+ *      side effects:
+ *              The iram_size may be modified.
+ */
+
+VOID
+iramsav()
+{
+  unget(getnb());
+  if (ip && *ip)
+        iram_size = expr(0);    /* evaluate size expression */
+  else
+        iram_size = 128;                /* Default is 128 (0x80) bytes */
+  if ((iram_size<=0) || (iram_size>256))
+        iram_size = 128;                /* Default is 128 (0x80) bytes */
+}
+
+/*Similar to iramsav but for xram memory*/
+VOID
+xramsav()
+{
+  unget(getnb());
+  if (ip && *ip)
+        xram_size = expr(0);    /* evaluate size expression */
+  else
+        xram_size = rflag?0x1000000:0x10000;
+}
+
+/*Similar to iramsav but for code memory*/
+VOID
+codesav()
+{
+  unget(getnb());
+  if (ip && *ip)
+        code_size = expr(0);    /* evaluate size expression */
+  else
+        code_size = rflag?0x1000000:0x10000;
+}
+
+
+/*)Function     VOID    iramcheck()
+ *
+ *      The function iramcheck() is used at the end of linking to check that
+ *      the internal RAM area wasn't overflowed by too many variable
+ *      assignments.  Variables in the DSEG, ISEG, and OSEG are assigned to
+ *      the chip's internal RAM.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              unsigned int            size of chip's internal
+ *              iram_size               RAM segment
+ *              struct area             linked list of memory
+ *              *areap                  areas
+ *
+ *       functions called:
+ *
+ *      side effects:
+ */
+
+VOID
+iramcheck()
+{
+  register unsigned int last_addr;
+  register struct area *ap;
+
+  for (ap = areap; ap; ap=ap->a_ap) {
+        if ((ap->a_size != 0) &&
+                (!strcmp(ap->a_id, "DSEG") ||
+                 !strcmp(ap->a_id, "OSEG") ||
+                 !strcmp(ap->a_id, "ISEG")
+                )
+           )
+        {
+          last_addr = ap->a_addr + ap->a_size - 1;
+          if (last_addr >= iram_size)
+                fprintf(stderr,
+                  "\nWARNING! Segment %s extends past the end\n"
+                  "         of internal RAM.  Check map file.\n",
+                  ap->a_id);
+        }
+  }
+}
+/* end sdld specific */
+
+char *usetxt[] = {
+        "Usage: [-Options] [-Option with arg] file",
+        "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
+        "Startup:",
+        "  -p   Echo commands to stdout (default)",
+        "  -n   No echo of commands to stdout",
+        "Alternates to Command Line Input:",
+        "  -c                   ASlink >> prompt input",
+        "  -f   file[.lk]       Command File input",
+        "Libraries:",
+        "  -k   Library path specification, one per -k",
+        "  -l   Library file specification, one per -l",
+        "Relocation:",
+        "  -b   area base address = expression",
+        "  -g   global symbol = expression",
+        "Map format:",
+        "  -m   Map output generated as (out)file[.map]",
+        "  -w   Wide listing format for map file",
+        "  -x   Hexadecimal (default)",
+        "  -d   Decimal",
+        "  -q   Octal",
+        "Output:",
+        "  -i   Intel Hex as (out)file[.ihx]",
+        "  -s   Motorola S Record as (out)file[.s19]",
+//      "  -t   Tandy CoCo Disk BASIC binary as (out)file[.bi-]",
+#if NOICE
+        "  -j   NoICE Debug output as (out)file[.noi]",
+#endif
+#if SDCDB
+        "  -y   SDCDB Debug output as (out)file[.cdb]",
+#endif
+//      "  -o   Linked file/library object output enable (default)",
+//      "  -v   Linked file/library object output disable",
+        "List:",
+        "  -u   Update listing file(s) with link data as file(s)[.rst]",
+        "Case Sensitivity:",
+        "  -z   Disable Case Sensitivity for Symbols",
+        "End:",
+        "  -e   or null line terminates input",
+        "",
+        0
+};
+
+char *usetxt_8051[] = {
+        "Usage: [-Options] [-Option with arg] file",
+        "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
+        "Startup:",
+        "  -p   Echo commands to stdout (default)",
+        "  -n   No echo of commands to stdout",
+        "Alternates to Command Line Input:",
+        "  -c                   ASlink >> prompt input",
+        "  -f   file[.lk]       Command File input",
+        "Libraries:",
+        "  -k   Library path specification, one per -k",
+        "  -l   Library file specification, one per -l",
+        "Relocation:",
+        "  -b   area base address = expression",
+        "  -g   global symbol = expression",
+        "Map format:",
+        "  -m   Map output generated as (out)file[.map]",
+        "  -w   Wide listing format for map file",
+        "  -x   Hexadecimal (default)",
+        "  -d   Decimal",
+        "  -q   Octal",
+        "Output:",
+        "  -i   Intel Hex as (out)file[.ihx]",
+        "  -s   Motorola S Record as (out)file[.s19]",
+#if NOICE
+        "  -j   NoICE Debug output as (out)file[.noi]",
+#endif
+#if SDCDB
+        "  -y   SDCDB Debug output as (out)file[.cdb]",
+#endif
+        "List:",
+        "  -u   Update listing file(s) with link data as file(s)[.rst]",
+        "Case Sensitivity:",
+        "  -z   Disable Case Sensitivity for Symbols",
+        "Miscellaneous:\n"
+        "  -I   [iram-size] Check for internal RAM overflow",
+        "  -X   [xram-size] Check for external RAM overflow",
+        "  -C   [code-size] Check for code overflow",
+        "  -M   Generate memory usage summary file[.mem]",
+        "  -Y   Pack internal ram",
+        "  -S   [stack-size] Allocate space for stack",
+        "End:",
+        "  -e   or null line terminates input",
+        "",
+        0
+};
+
+char *usetxt_6808[] = {
+        "Usage: [-Options] [-Option with arg] file",
+        "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
+        "Startup:",
+        "  -p   Echo commands to stdout (default)",
+        "  -n   No echo of commands to stdout",
+        "Alternates to Command Line Input:",
+        "  -c                   ASlink >> prompt input",
+        "  -f   file[.lk]       Command File input",
+        "Libraries:",
+        "  -k   Library path specification, one per -k",
+        "  -l   Library file specification, one per -l",
+        "Relocation:",
+        "  -b   area base address = expression",
+        "  -g   global symbol = expression",
+        "Map format:",
+        "  -m   Map output generated as (out)file[.map]",
+        "  -w   Wide listing format for map file",
+        "  -x   Hexadecimal (default)",
+        "  -d   Decimal",
+        "  -q   Octal",
+        "Output:",
+        "  -i   Intel Hex as (out)file[.ihx]",
+        "  -s   Motorola S Record as (out)file[.s19]",
+        "  -E   ELF executable as file[.elf]",
+#if NOICE
+        "  -j   NoICE Debug output as (out)file[.noi]",
+#endif
+#if SDCDB
+        "  -y   SDCDB Debug output as (out)file[.cdb]",
+#endif
+        "List:",
+        "  -u   Update listing file(s) with link data as file(s)[.rst]",
+        "Case Sensitivity:",
+        "  -z   Disable Case Sensitivity for Symbols",
+        "Miscellaneous:\n"
+        "  -I   [iram-size] Check for internal RAM overflow",
+        "  -X   [xram-size] Check for external RAM overflow",
+        "  -C   [code-size] Check for code overflow",
+        "  -M   Generate memory usage summary file[.mem]",
+        "End:",
+        "  -e   or null line terminates input",
+        "",
+        0
+};
+
+char *usetxt_z80_gb[] = {
+        "Usage: [-Options] [-Option with arg] file",
+        "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
+        "Startup:",
+        "  -p   Echo commands to stdout (default)",
+        "  -n   No echo of commands to stdout",
+        "Alternates to Command Line Input:",
+        "  -c                   ASlink >> prompt input",
+        "  -f   file[.lk]       Command File input",
+        "Libraries:",
+        "  -k   Library path specification, one per -k",
+        "  -l   Library file specification, one per -l",
+        "Relocation:",
+        "  -b   area base address = expression",
+        "  -g   global symbol = expression",
+        "Map format:",
+        "  -m   Map output generated as (out)file[.map]",
+        "  -w   Wide listing format for map file",
+        "  -x   Hexadecimal (default)",
+        "  -d   Decimal",
+        "  -q   Octal",
+        "Output:",
+        "  -i   Intel Hex as (out)file[.ihx]",
+        "  -s   Motorola S Record as (out)file[.s19]",
+#if SDCDB
+        "  -y   SDCDB Debug output as (out)file[.cdb]",
+#endif
+        "List:",
+        "  -u   Update listing file(s) with link data as file(s)[.rst]",
+        "Case Sensitivity:",
+        "  -z   Disable Case Sensitivity for Symbols",
+        "End:",
+        "  -e   or null line terminates input",
+        "",
+        0
+};
+
+/*)Function     VOID    usage(n)
+ *
+ *              int     n               exit code
+ *
+ *      The function usage() outputs to the stderr device the
+ *      linker name and version and a list of valid linker options.
+ *
+ *      local variables:
+ *              char ** dp              pointer to an array of
+ *                                      text string pointers.
+ *
+ *      global variables:
+ *              FILE *  stderr          c_library
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *
+ *      side effects:
+ *              none
+ */
+
+VOID
+usage(int n)
+{
+        char    **dp;
+
+        /* sdld specific */
+        fprintf(stderr, "\n%s Linker %s\n\n", is_sdld() ? "sdld" : "ASxxxx", VERSION);
+        for (dp = TARGET_IS_8051 ? usetxt_8051 : (TARGET_IS_6808 ? usetxt_6808 : ((TARGET_IS_Z80 || TARGET_IS_GB) ? usetxt_z80_gb : usetxt)); *dp; dp++)
+                fprintf(stderr, "%s\n", *dp);
+        /* end sdld specific */
+        lkexit(n);
+}
+
+/*)Function     VOID    copyfile()
+ *
+ *              FILE    *dest           destination file
+ *              FILE    *src            source file
+ *
+ *              function will copy source file to destination file
+ *
+ *
+ *      functions called:
+ *              int     fgetc()                 c_library
+ *              int     fputc()                 c_library
+ *
+ *      side effects:
+ *              none
+ */
+VOID
+copyfile (FILE *dest, FILE *src)
+{
+        int ch;
+
+        while ((ch = fgetc(src)) != EOF) {
+                fputc(ch,dest);
+        }
+}
diff --git a/Kernel/tools/bankld/lkmem.c b/Kernel/tools/bankld/lkmem.c
new file mode 100644 (file)
index 0000000..0e87c2d
--- /dev/null
@@ -0,0 +1,702 @@
+/* lkmem.c - Create a memory summary file with extension .mem
+
+   Copyright (C) 2002 Jesus Calvino-Fraga, jesusc at ieee dot org
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "sdld.h"
+#include "aslink.h"
+
+int summary(struct area * areap)
+{
+  if (TARGET_IS_8051 || TARGET_IS_6808) {
+    /* only for 8051 and 6808 targets */
+
+    #define EQ(A,B) !strcasecmp((A),(B))
+    #define MIN_STACK 16
+    #define REPORT_ERROR(A, H) \
+    {\
+        fprintf(of, "%s%s", (H)?"*** ERROR: ":"", (A)); \
+        fprintf(stderr, "%s%s", (H)?"\n?ASlink-Error-":"",(A)); \
+        toreturn=1; \
+    }
+
+    #define REPORT_WARNING(A, H) \
+    { \
+        fprintf(of, "%s%s", (H)?"*** WARNING: ":"", (A)); \
+        fprintf(stderr, "%s%s",(H)?"\n?ASlink-Warning-":"", (A)); \
+    }
+
+    char buff[128];
+    int j, toreturn=0;
+    unsigned int Total_Last=0, k;
+
+    struct area * xp;
+    FILE * of;
+
+    /*Artifacts used for printing*/
+    char start[15], end[15], size[15], max[15];
+    char format[]="   %-16.16s %-8.8s %-8.8s %-8.8s %-8.8s\n";
+    char line[]="---------------------";
+
+    typedef struct
+    {
+        unsigned long Start;
+        unsigned long Size;
+        unsigned long Max;
+        char Name[NCPS];
+        unsigned long flag;
+    } _Mem;
+
+    unsigned int dram[0x100];
+    _Mem Ram8051[] = {
+        {0,     8,  8,   "REG_BANK_0", 0x0001},
+        {0x8,   8,  8,   "REG_BANK_1", 0x0002},
+        {0x10,  8,  8,   "REG_BANK_2", 0x0004},
+        {0x18,  8,  8,   "REG_BANK_3", 0x0008},
+        {0x20,  0,  16,  "BSEG_BYTES", 0x0010},
+        {0,     0,  128, "UNUSED",     0x0000},
+        {0x7f,  0,  128, "DATA",       0x0020},
+        {0,     0,  128, "TOTAL:",     0x0000}
+    };
+
+    _Mem IRam8051 =  {0xff,   0,   128, "INDIRECT RAM",       0x0080};
+    _Mem Stack8051 = {0xff,   0,     1, "STACK",              0x0000};
+    _Mem XRam8051 =  {0xffff, 0, 65536, "EXTERNAL RAM",       0x0100};
+    _Mem Rom8051 =   {0xffff, 0, 65536, "ROM/EPROM/FLASH",    0x0200};
+
+    _Mem Ram6808[] = {
+        {0,     0,      0,       "REG_BANK_0", 0x0001},
+        {0x0,   0,      0,       "REG_BANK_1", 0x0002},
+        {0x0,   0,      0,       "REG_BANK_2", 0x0004},
+        {0x0,   0,      0,       "REG_BANK_3", 0x0008},
+        {0x0,   0,      0,       "BSEG_BYTES", 0x0010},
+        {0,     0,      256,    "UNUSED",     0x0000},
+        {0xff,  0,      256,    "DATA",       0x0020},
+        {0,             0,      256, "TOTAL:",     0x0000}
+    };
+
+    _Mem IRam6808 =  {0xff,   0,     0, "INDIRECT RAM",           0x0080};
+    _Mem Stack6808 = {0xff,   0,     1, "STACK",                  0x0000};
+    _Mem XRam6808 =  {0xffff, 0, 65536, "EXTERNAL RAM",           0x0100};
+    _Mem Rom6808 =   {0xffff, 0, 65536, "ROM/EPROM/FLASH",        0x0200};
+
+    _Mem *Ram = NULL;
+
+    _Mem IRam =  {0, 0, 0, "", 0};
+    _Mem Stack = {0, 0, 0, "", 0};
+    _Mem XRam =  {0, 0, 0, "", 0};
+    _Mem Rom =   {0, 0, 0, "", 0};
+
+    if (TARGET_IS_8051) {
+        Ram = Ram8051;
+        memcpy(&IRam, &IRam8051, sizeof (_Mem));
+        memcpy(&Stack, &Stack8051, sizeof (_Mem));
+        memcpy(&XRam, &XRam8051, sizeof (_Mem));
+        memcpy(&Rom, &Rom8051, sizeof (_Mem));
+    }
+    else {
+        Ram = Ram6808;
+        memcpy(&IRam, &IRam6808, sizeof (_Mem));
+        memcpy(&Stack, &Stack6808, sizeof (_Mem));
+        memcpy(&XRam, &XRam6808, sizeof (_Mem));
+        memcpy(&Rom, &Rom6808, sizeof (_Mem));
+    }
+
+    if (stacksize == 0) stacksize = MIN_STACK;
+
+    if (TARGET_IS_8051) {
+        if(rflag) /*For the DS390*/
+        {
+            XRam.Max=0x1000000; /*24 bits*/
+            XRam.Start=0xffffff;
+            Rom.Max=0x1000000;
+            Rom.Start=0xffffff;
+        }
+
+        if((iram_size<=0)||(iram_size>0x100)) /*Default: 8052 like memory*/
+        {
+            Ram[5].Max=0x80;
+            Ram[6].Max=0x80;
+            Ram[7].Max=0x80;
+            IRam.Max=0x80;
+            iram_size=0x100;
+        }
+        else if(iram_size<0x80)
+        {
+            Ram[5].Max=iram_size;
+            Ram[6].Max=iram_size;
+            Ram[7].Max=iram_size;
+            IRam.Max=0;
+        }
+        else
+        {
+            Ram[5].Max=0x80;
+            Ram[6].Max=0x80;
+            Ram[7].Max=0x80;
+            IRam.Max=iram_size-0x80;
+        }
+    }
+
+    for(j=0; j<(int)iram_size; j++) dram[j]=0;
+    for(; j<0x100; j++) dram[j]=0x8000; /*Memory not available*/
+
+    /* Open Memory Summary File*/
+    of = afile(linkp->f_idp, "mem", 1);
+    if (of == NULL)
+    {
+        lkexit(1);
+    }
+
+    xp=areap;
+    while (xp)
+    {
+        /**/ if (EQ(xp->a_id, "REG_BANK_0"))
+        {
+            Ram[0].Size=xp->a_size;
+        }
+        else if (EQ(xp->a_id, "REG_BANK_1"))
+        {
+            Ram[1].Size=xp->a_size;
+        }
+        else if (EQ(xp->a_id, "REG_BANK_2"))
+        {
+            Ram[2].Size=xp->a_size;
+        }
+        else if (EQ(xp->a_id, "REG_BANK_3"))
+        {
+            Ram[3].Size=xp->a_size;
+        }
+        else if (EQ(xp->a_id, "BSEG_BYTES"))
+        {
+            if (TARGET_IS_8051)
+               Ram[4].Size+=xp->a_size;
+            else
+                Ram[4].Size=xp->a_size;
+        }
+
+        else if (EQ(xp->a_id, "SSEG"))
+        {
+            Stack.Size+=xp->a_size;
+            if(xp->a_addr<Stack.Start) Stack.Start=xp->a_addr;
+        }
+
+        else if (EQ(xp->a_id, "ISEG"))
+        {
+            IRam.Size+=xp->a_size;
+            if(xp->a_addr<IRam.Start) IRam.Start=xp->a_addr;
+        }
+
+        else if (TARGET_IS_8051)
+        {
+            if(xp->a_flag & A_XDATA)
+            {
+                if(xp->a_size>0)
+                {
+                    XRam.Size+=xp->a_size;
+                    if(xp->a_addr<XRam.Start) XRam.Start=xp->a_addr;
+                }
+            }
+
+            else if (EQ(xp->a_id, "BIT_BANK"))
+            {
+                Ram[4].Size+=xp->a_size;
+            }
+
+            else if(xp->a_flag & A_CODE)
+            {
+                if(xp->a_size>0)
+                {
+                    Rom.Size+=xp->a_size;
+                    if(xp->a_addr<Rom.Start) Rom.Start=xp->a_addr;
+                }
+            }
+        }
+
+        else if(TARGET_IS_6808)
+        {
+            if ( EQ(xp->a_id, "DSEG") || EQ(xp->a_id, "OSEG") )
+            {
+                Ram[6].Size+=xp->a_size;
+                if(xp->a_addr<Ram[6].Start) Ram[6].Start=xp->a_addr;
+            }
+
+            else if( EQ(xp->a_id, "CSEG") || EQ(xp->a_id, "GSINIT") ||
+                         EQ(xp->a_id, "GSFINAL") || EQ(xp->a_id, "HOME") )
+            {
+                Rom.Size+=xp->a_size;
+                if(xp->a_addr<Rom.Start) Rom.Start=xp->a_addr;
+            }
+
+            else if (EQ(xp->a_id, "XSEG") || EQ(xp->a_id, "XISEG"))
+            {
+                    XRam.Size+=xp->a_size;
+                    if(xp->a_addr<XRam.Start) XRam.Start=xp->a_addr;
+            }
+        }
+
+        /*If is not a register bank, bit, stack, or idata, then it should be data*/
+        else if((TARGET_IS_8051 && xp->a_flag & (A_CODE|A_BIT|A_XDATA))==0)
+        {
+            if(xp->a_size)
+            {
+                Ram[6].Size+=xp->a_size;
+                if(xp->a_addr<Ram[6].Start) Ram[6].Start=xp->a_addr;
+            }
+        }
+
+        xp=xp->a_ap;
+    }
+
+    for(j=0; j<7; j++)
+        for(k=Ram[j].Start; (k<(Ram[j].Start+Ram[j].Size))&&(k<0x100); k++)
+            dram[k]|=Ram[j].flag; /*Mark as used*/
+
+    if (TARGET_IS_8051) {
+        for(k=IRam.Start; (k<(IRam.Start+IRam.Size))&&(k<0x100); k++)
+            dram[k]|=IRam.flag; /*Mark as used*/
+    }
+
+    /*Compute the amount of unused memory in direct data Ram.  This is the
+    gap between the last register bank or bit segment and the data segment.*/
+    for(k=Ram[6].Start-1; (dram[k]==0) && (k>0); k--);
+    Ram[5].Start=k+1;
+    Ram[5].Size=Ram[6].Start-Ram[5].Start; /*It may be zero (which is good!)*/
+
+    /*Compute the data Ram totals*/
+    for(j=0; j<7; j++)
+    {
+        if(Ram[7].Start>Ram[j].Start) Ram[7].Start=Ram[j].Start;
+        Ram[7].Size+=Ram[j].Size;
+    }
+    Total_Last=Ram[6].Size+Ram[6].Start-1;
+
+    /*Report the Ram totals*/
+    fprintf(of, "Direct Internal RAM:\n");
+    fprintf(of, format, "Name", "Start", "End", "Size", "Max");
+
+    for(j=0; j<8; j++)
+    {
+        if((j==0) || (j==7)) fprintf(of, format, line, line, line, line, line);
+        if((j!=5) || (Ram[j].Size>0))
+        {
+            sprintf(start, "0x%02lx", Ram[j].Start);
+            if(Ram[j].Size==0)
+                end[0]=0;/*Empty string*/
+            else
+                sprintf(end,  "0x%02lx", j==7?Total_Last:Ram[j].Size+Ram[j].Start-1);
+            sprintf(size, "%5lu", Ram[j].Size);
+            sprintf(max, "%5lu", Ram[j].Max);
+            fprintf(of, format, Ram[j].Name, start, end, size, max);
+        }
+    }
+
+    if (TARGET_IS_8051) {
+        for(k=Ram[6].Start; (k<(Ram[6].Start+Ram[6].Size))&&(k<0x100); k++)
+        {
+            if(dram[k]!=Ram[6].flag)
+            {
+                sprintf(buff, "Internal memory overlap starting at 0x%02x.\n", k);
+                REPORT_ERROR(buff, 1);
+                break;
+            }
+        }
+
+        if(Ram[4].Size>Ram[4].Max)
+        {
+            k=Ram[4].Size-Ram[4].Max;
+            sprintf(buff, "Insufficient bit addressable memory.  "
+                        "%d byte%s short.\n", k, (k==1)?"":"s");
+            REPORT_ERROR(buff, 1);
+        }
+
+        if(Ram[5].Size!=0)
+        {
+            sprintf(buff, "%ld bytes in data memory wasted.  "
+                        "SDCC link could use: --data-loc 0x%02lx\n",
+                        Ram[5].Size, Ram[6].Start-Ram[5].Size);
+            REPORT_WARNING(buff, 1);
+        }
+
+        if((Ram[6].Start+Ram[6].Size)>Ram[6].Max)
+        {
+            k=(Ram[6].Start+Ram[6].Size)-Ram[6].Max;
+            sprintf(buff, "Insufficient space in data memory.   "
+                        "%d byte%s short.\n", k, (k==1)?"":"s");
+            REPORT_ERROR(buff, 1);
+        }
+    }
+
+    /*Report the position of the beginning of the stack*/
+    fprintf(of, "\n%stack starts at: 0x%02lx (sp set to 0x%02lx)",
+        rflag ? "16 bit mode initial s" : "S", Stack.Start, Stack.Start-1);
+
+    if (TARGET_IS_8051) {
+        /*Check that the stack pointer is landing in a safe place:*/
+        if( (dram[Stack.Start] & 0x8000) == 0x8000 )
+        {
+            fprintf(of, ".\n");
+            sprintf(buff, "Stack set to unavailable memory.\n");
+            REPORT_ERROR(buff, 1);
+        }
+        else if(dram[Stack.Start])
+        {
+            fprintf(of, ".\n");
+            sprintf(buff, "Stack overlaps area ");
+            REPORT_ERROR(buff, 1);
+            for(j=0; j<7; j++)
+            {
+                if(dram[Stack.Start]&Ram[j].flag)
+                {
+                    sprintf(buff, "'%s'\n", Ram[j].Name);
+                    break;
+                }
+            }
+            if(dram[Stack.Start]&IRam.flag)
+            {
+                sprintf(buff, "'%s'\n", IRam.Name);
+            }
+            REPORT_ERROR(buff, 0);
+        }
+        else
+        {
+            for(j=Stack.Start, k=0; (j<(int)iram_size)&&(dram[j]==0); j++, k++);
+            fprintf(of, " with %d bytes available\n", k);
+            if ((int)k<stacksize)
+            {
+                sprintf(buff, "Only %d byte%s available for stack.\n",
+                    k, (k==1)?"":"s");
+                REPORT_WARNING(buff, 1);
+            }
+        }
+    }
+
+    fprintf(of, "\nOther memory:\n");
+    fprintf(of, format, "Name", "Start", "End", "Size", "Max");
+    fprintf(of, format, line, line, line, line, line);
+
+    /*Report IRam totals:*/
+    if(IRam.Size==0)
+    {
+        start[0]=0;/*Empty string*/
+        end[0]=0;/*Empty string*/
+    }
+    else
+    {
+        sprintf(start, "0x%02lx", IRam.Start);
+        sprintf(end,  "0x%02lx", IRam.Size+IRam.Start-1);
+    }
+    sprintf(size, "%5lu", IRam.Size);
+    sprintf(max, "%5lu", IRam.Max);
+    fprintf(of, format, IRam.Name, start, end, size, max);
+
+    /*Report XRam totals:*/
+    if(XRam.Size==0)
+    {
+        start[0]=0;/*Empty string*/
+        end[0]=0;/*Empty string*/
+    }
+    else
+    {
+        sprintf(start, "0x%04lx", XRam.Start);
+        sprintf(end,  "0x%04lx", XRam.Size+XRam.Start-1);
+    }
+    sprintf(size, "%5lu", XRam.Size);
+    sprintf(max, "%5lu", xram_size<0?XRam.Max:xram_size);
+    fprintf(of, format, XRam.Name, start, end, size, max);
+
+    /*Report Rom/Flash totals:*/
+    if(Rom.Size==0)
+    {
+        start[0]=0;/*Empty string*/
+        end[0]=0;/*Empty string*/
+    }
+    else
+    {
+        sprintf(start, "0x%04lx", Rom.Start);
+        sprintf(end,  "0x%04lx", Rom.Size+Rom.Start-1);
+    }
+    sprintf(size, "%5lu", Rom.Size);
+    sprintf(max, "%5lu", code_size<0?Rom.Max:code_size);
+    fprintf(of, format, Rom.Name, start, end, size, max);
+
+    /*Report any excess:*/
+    if (TARGET_IS_8051) {
+        if((IRam.Start+IRam.Size)>(IRam.Max+0x80))
+        {
+            sprintf(buff, "Insufficient INDIRECT RAM memory.\n");
+            REPORT_ERROR(buff, 1);
+        }
+    }
+    if( ((XRam.Start+XRam.Size)>XRam.Max) ||
+        (((int)XRam.Size>xram_size)&&(xram_size>=0)) )
+    {
+        sprintf(buff, "Insufficient EXTERNAL RAM memory.\n");
+        REPORT_ERROR(buff, 1);
+    }
+    if( ((Rom.Start+Rom.Size)>Rom.Max) ||
+        (((int)Rom.Size>code_size)&&(code_size>=0)) )
+    {
+        sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n");
+        REPORT_ERROR(buff, 1);
+    }
+
+    fclose(of);
+    return toreturn;
+  }
+  else {
+    assert (0);
+    return 0;
+  }
+}
+
+int summary2(struct area * areap)
+{
+  if (TARGET_IS_8051) {
+    /* only for 8051 target */
+
+    #define EQ(A,B) !strcasecmp((A),(B))
+
+    char buff[128];
+    int toreturn = 0;
+    unsigned int j;
+    unsigned long int Stack_Start=0, Stack_Size;
+
+    struct area * xp;
+    struct area * xstack_xp = NULL;
+    FILE * of;
+
+    /*Artifacts used for printing*/
+    char start[15], end[15], size[15], max[15];
+    char format[]="   %-16.16s %-8.8s %-8.8s %-8.8s %-8.8s\n";
+    char line[]="---------------------";
+
+    typedef struct
+    {
+        unsigned long Start;
+        unsigned long End;
+        unsigned long Size;
+        unsigned long Max;
+        char Name[NCPS];
+        unsigned long flag;
+    } _Mem;
+
+    _Mem Stack={0xff,   0, 0,     1, "STACK",           0x0000};
+    _Mem Paged={0xffff, 0, 0,   256, "PAGED EXT. RAM",  A3_PAG};
+    _Mem XRam= {0xffff, 0, 0, 65536, "EXTERNAL RAM",    0x0100};
+    _Mem Rom=  {0xffff, 0, 0, 65536, "ROM/EPROM/FLASH", 0x0200};
+
+    if(rflag) /*For the DS390*/
+    {
+        XRam.Max=0x1000000; /*24 bits*/
+        XRam.Start=0xffffff;
+        Rom.Max=0x1000000;
+        Rom.Start=0xffffff;
+    }
+
+    /* Open Memory Summary File*/
+    of = afile(linkp->f_idp, "mem", 1);
+    if (of == NULL)
+    {
+        lkexit(1);
+    }
+
+    xp=areap;
+    while (xp)
+    {
+        if (xp->a_flag & A_CODE)
+        {
+            if(xp->a_size)
+            {
+                Rom.Size += xp->a_size;
+                if(xp->a_addr < Rom.Start)
+                    Rom.Start = xp->a_addr;
+                if(xp->a_addr + xp->a_size > Rom.End)
+                    Rom.End = xp->a_addr + xp->a_size;
+            }
+        }
+
+        else if (EQ(xp->a_id, "SSEG"))
+        {
+            Stack.Size += xp->a_size;
+            if(xp->a_addr < Stack.Start)
+                Stack.Start = xp->a_addr;
+            if(xp->a_addr + xp->a_size > Stack.End)
+                Stack.End = xp->a_addr + xp->a_size;
+        }
+
+        else if (EQ(xp->a_id, "PSEG"))
+        {
+            Paged.Size += xp->a_size;
+            if(xp->a_addr < Paged.Start)
+                Paged.Start = xp->a_addr;
+            if(xp->a_addr + xp->a_size > Paged.End)
+                Paged.End = xp->a_addr + xp->a_size;
+        }
+
+        else if (EQ(xp->a_id, "XSTK"))
+        {
+            xstack_xp = xp;
+            Paged.Size += xp->a_size;
+            if(xp->a_addr < Paged.Start)
+                Paged.Start = xp->a_addr;
+            if(xp->a_addr + xp->a_size > Paged.End)
+                Paged.End = xp->a_addr + xp->a_size;
+        }
+
+        else if (xp->a_flag & A_XDATA)
+        {
+            if(xp->a_size)
+            {
+                XRam.Size += xp->a_size;
+                if(xp->a_addr < XRam.Start)
+                    XRam.Start = xp->a_addr;
+                if(xp->a_addr + xp->a_size > XRam.End)
+                    XRam.End = xp->a_addr + xp->a_size;
+            }
+        }
+
+        xp = xp->a_ap;
+    }
+
+    /*Report the Ram totals*/
+    fprintf(of, "Internal RAM layout:\n");
+    fprintf(of, "      0 1 2 3 4 5 6 7 8 9 A B C D E F");
+    for(j=0; j<256; j++)
+    {
+        if(j%16==0) fprintf(of, "\n0x%02x:|", j);
+        fprintf(of, "%c|", idatamap[j]);
+    }
+    fprintf(of, "\n0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute\n");
+
+    for(j=0; j<256; j++)
+    {
+        if(idatamap[j]=='S')
+        {
+            Stack_Start=j;
+            break;
+        }
+    }
+
+    for(j=Stack_Start, Stack_Size=0; j<((iram_size)?iram_size:256); j++)
+    {
+        if((idatamap[j]=='S')||(idatamap[j]==' ')) Stack_Size++;
+        else break;
+    }
+
+    xp=areap;
+    while (xp)
+    {
+        if(xp->a_unaloc>0)
+        {
+            fprintf(of, "\nERROR: Couldn't get %d byte%s allocated"
+                        " in internal RAM for area %s.",
+                        xp->a_unaloc, xp->a_unaloc>1?"s":"", xp->a_id);
+            toreturn=1;
+        }
+        xp=xp->a_ap;
+    }
+
+    /*Report the position of the begining of the stack*/
+    if(Stack_Start!=256)
+        fprintf(of, "\n%s starts at: 0x%02lx (sp set to 0x%02lx) with %ld bytes available.",
+            rflag ? "16 bit mode initial stack" : "Stack", Stack_Start, Stack_Start-1, Stack_Size);
+    else
+        fprintf(of, "\nI don't have a clue where the stack ended up! Sorry...");
+
+    /*Report about xstack*/
+    if (xstack_xp)
+    {
+        Stack_Start = xstack_xp->a_addr;
+        Stack_Size = xstack_xp->a_size;
+        fprintf(of, "\nXstack starts at: 0x%04lx with %ld bytes available.",
+            Stack_Start, Stack_Size);
+    }
+
+    fprintf(of, "\n\nOther memory:\n");
+    fprintf(of, format, "Name", "Start", "End", "Size", "Max");
+    fprintf(of, format, line, line, line, line, line);
+
+    /*Report Paged XRam totals:*/
+    if(Paged.Size==0)
+    {
+        start[0]=0;/*Empty string*/
+        end[0]=0;/*Empty string*/
+    }
+    else
+    {
+        sprintf(start, "0x%04lx", Paged.Start);
+        sprintf(end,  "0x%04lx", Paged.End-1);
+    }
+    sprintf(size, "%5lu", Paged.Size);
+    sprintf(max, "%5lu", xram_size<0 ? Paged.Max : xram_size<256 ? xram_size : 256);
+    fprintf(of, format, Paged.Name, start, end, size, max);
+
+    /*Report XRam totals:*/
+    if(XRam.Size==0)
+    {
+        start[0]=0;/*Empty string*/
+        end[0]=0;/*Empty string*/
+    }
+    else
+    {
+        sprintf(start, "0x%04lx", XRam.Start);
+        sprintf(end,  "0x%04lx", XRam.End-1);
+    }
+    sprintf(size, "%5lu", XRam.Size);
+    sprintf(max, "%5lu", xram_size<0?XRam.Max:xram_size);
+    fprintf(of, format, XRam.Name, start, end, size, max);
+
+    /*Report Rom/Flash totals:*/
+    if(Rom.Size==0)
+    {
+        start[0]=0;/*Empty string*/
+        end[0]=0;/*Empty string*/
+    }
+    else
+    {
+        sprintf(start, "0x%04lx", Rom.Start);
+        sprintf(end,  "0x%04lx", Rom.End-1);
+    }
+    sprintf(size, "%5lu", Rom.Size);
+    sprintf(max, "%5lu", code_size<0?Rom.Max:code_size);
+    fprintf(of, format, Rom.Name, start, end, size, max);
+
+    /*Report any excess:*/
+    if( ((XRam.End) > XRam.Max) ||
+        (((int)XRam.Size>xram_size)&&(xram_size>=0)) )
+    {
+        sprintf(buff, "Insufficient EXTERNAL RAM memory.\n");
+        REPORT_ERROR(buff, 1);
+    }
+    if( ((Rom.End) > Rom.Max) ||
+        (((int)Rom.Size>code_size)&&(code_size>=0)) )
+    {
+        sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n");
+        REPORT_ERROR(buff, 1);
+    }
+
+    fclose(of);
+    return toreturn;
+  }
+  else {
+    assert (0);
+    return 0;
+  }
+}
+
diff --git a/Kernel/tools/bankld/lknoice.c b/Kernel/tools/bankld/lknoice.c
new file mode 100644 (file)
index 0000000..3972541
--- /dev/null
@@ -0,0 +1,656 @@
+/* lknoice.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ *
+ * Extensions to produce NoICE debug files
+ *
+ * 31-Oct-1997 by John Hartman
+ * 30-Jan-98 JLH add page to DefineNoICE for 8051
+ *  2-Feb-98 JLH Allow optional .nest on local vars - C scoping rules...
+ * 27-May-01 ARB Updated for ASxxxx V4
+ */
+
+#include "aslink.h"
+
+
+#if NOICE
+
+/*Module        lknoice.c
+ *
+ *      The module lknoice.c contains the functions
+ *      required to create a NoICE debug file.
+ *
+ *      lknoice.c contains the following functions:
+ *              VOID    NoICEfopen()
+ *              VOID    NoICEmagic()
+ *              VOID    DefineNoICE()
+ *              VOID    DefineGlobal()
+ *              VOID    DefineScoped()
+ *              VOID    DefineFile()
+ *              VOID    DefineFunction()
+ *              VOID    DefineStaticFunction()
+ *              VOID    DefineEndFunction()
+ *              VOID    DefineLine()
+ *              VOID    PagedAddress()
+ *
+ *      lknoice.c contains these local variables:
+ *              struct noicebn *noicebnp        pointer to linked structure of
+ *                                              ';!FILE' specifications
+ *              char currentFile[]              file being processed
+ *              char currentFunction[]          function being processed
+ */
+
+struct  noicefn {
+        struct  noicefn *n_np;  /* noicefn link */
+        char *  n_id;           /* file name */
+};
+
+static struct noicefn *noicefnp = NULL;
+
+static char currentFile[NCPS];
+static char currentFunction[NCPS];
+
+
+/*)Function     VOID    NoICEfopen()
+ *
+ *      The function NoICEfopen() opens the NoICE output file
+ *      and sets the map flag, mflag, to create a map file.
+ *      NoICE processing is performed during map generation.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              int     jflag           NoICE Debug flag
+ *              FILE *  jfp             NoICE Debug File handle
+ *              struct lfile *linkp     Pointer to the Linker output file name
+ *              int     mflag           Map output flag
+ *
+ *      functions called:
+ *              FILE *  afile()         lkmain.c
+ *              VOID    lkexit()        lkmain.c
+ *
+ *      side effects:
+ *              The NoICE output file is opened.
+ *              Failure to open the file will
+ *              terminate the linker.
+ */
+
+VOID NoICEfopen(void)
+{
+        if (jflag) {
+                jfp = afile(linkp->f_idp, "noi", 1);
+                if (jfp == NULL) {
+                        lkexit(1);
+                }
+                mflag = 1;
+        }
+}
+
+
+/*)Function     VOID    NoICEmagic()
+ *
+ *      The function NoICEmagic() passes any "magic Comments"
+ *      to the NoICE output file.  Magic comments are those
+ *      beginning with ";!".  Also a linked list of file names
+ *      specified in ";!FILE" magic comments is created.  These
+ *      file names are used to verify that symbols in the
+ *      ASxxxx .rel files of the form str1.str2 are NoICE symbols.
+ *
+ *      local variables:
+ *              char    id[]            id string
+ *              struct noicefn * np     pointer to new structure
+ *              char *  p1              temporary string pointer
+ *              char *  p2              temporary string pointer
+ *              struct noicefn * tnp    temporary pointer to noicefn structure
+ *
+ *      global variables:
+ *              char *  ip              position into the current
+ *                                      input text line
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              VOID    getid()         lklex.c
+ *              VOID *  new()           lksym.c
+ *              int     fprintf()       c_library
+ *              char *  strrchr()       c_library
+ *              char *  strsto()        lksym.c
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              The NoICE "magic comments" are passed
+ *              to the output file.  A list of assembler
+ *              file names is created.
+ */
+
+VOID NoICEmagic(void)
+{
+        char id[NCPS];
+        char *p1, *p2;
+        struct noicefn *np, *tnp;
+
+        /*
+         * Pass any "magic comments" to NoICE output
+         */
+        if ((ip[0] == ';') && (ip[1] == '!')) {
+                if (jfp) {
+                        fprintf(jfp, "%s\n", &ip[2]);
+                }
+                if (pass == 0) {
+                        getid(id, -1);
+                        if (symeq(id, ";!FILE", 1)) {
+                                getid(id, -1);
+                                /*
+                                 * The name starts after the last
+                                 * '/' (Unices) or
+                                 * ':' or '\' (DOS)
+                                 *
+                                 * and ends at the last
+                                 * separator 'FSEPX'
+                                 */
+                                p1 = id;
+                                if ((p2 = strrchr(p1,  '\\')) != NULL)  p1 = ++p2;
+                                if ((p2 = strrchr(p1,   '/')) != NULL)  p1 = ++p2;
+                                if ((p2 = strrchr(p1,   ':')) != NULL)  p1 = ++p2;
+                                if ((p2 = strrchr(p1, FSEPX)) != NULL) *p2 = 0;
+
+                                np = (struct noicefn *) new (sizeof(struct noicefn));
+                                if (noicefnp == NULL) {
+                                        noicefnp = np;
+                                } else {
+                                        tnp = noicefnp;
+                                        while (tnp->n_np)
+                                                tnp = tnp->n_np;
+                                        tnp->n_np = np;
+                                }
+                                np->n_id = strsto(p1);
+                        }
+                }
+        }
+}
+
+
+/*)Function     VOID    DefineNoICE()
+ *
+ *              char *          name    pointer to the symbol string
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function DefineNoICE() processes the symbols into
+ *      NoICE commands for inclusion in the NoICE output file.
+ *
+ *      The function is called from lstarea in lklist.c
+ *      for each symbol.
+ *
+ *      local variables:
+ *              int     j               parsed argument count
+ *              int     k               parsed argument count
+ *              int     level           function level
+ *              char    token1[]        parsed string
+ *              char    token2[]        parsed string
+ *              char    token2[]        parsed string
+ *              char    sep1            parsed character
+ *              char    sep2            parsed character
+ *              struct noicefn * tnp    temporary pointer to noicefn structure
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              VOID    DefineFile()            lknoice.c
+ *              VOID    DefineFunction()        lknoice.c
+ *              VOID    DefineStaticFunction()  lknoice.c
+ *              VOID    DefineEndFunction()     lknoice.c
+ *              VOID    DefineScoped()          lknoice.c
+ *              VOID    DefineLine()            lknoice.c
+ *              VOID    DefineGlobal()          lknoice.c
+ *              VOID    PagedAddress()          lknoice.c
+ *              int     sprintf()               c_library
+ *              int     sscanf()                c_library
+ *              int     symeq()                 lksym.c
+ *
+ *      side effects:
+ *              NoICE debug commands are placed
+ *              into the output file.
+ */
+
+void DefineNoICE( char *name, a_uint value, struct bank *yp )
+{
+        char token1[NCPS];                      /* parse for file.function.symbol */
+        char token2[NCPS];
+        char token3[NCPS];
+        char sep1, sep2;
+        int  j, k, level;
+        struct noicefn *np;
+
+        /* no output if file is not open */
+        if (jfp == NULL) return;
+
+        j = sscanf( name, "%[^.]%c%[^.]%c%s", token1, &sep1, token2, &sep2, token3 );
+        if (j > 1) {
+                /* verify that first token is a file name */
+                k = 1;
+                np = noicefnp;
+                while (np != NULL) {
+                        if (symeq(token1, np->n_id, 1)) {
+                                k = j;
+                                break;
+                        }
+                        np = np->n_np;
+                }
+                j = k;
+        }
+
+        switch (j)
+        {
+                /* file.function.symbol, or file.function..SPECIAL */
+                case 5:
+                        DefineFile( token1, 0, NULL );
+                        if (token3[0] == '.')
+                        {
+                                if (symeq( token3, ".FN", 1 ) != 0)
+                                {
+                                        /* Global function */
+                                        DefineFunction( token2, value, yp );
+                                }
+                                else if (symeq( token3, ".SFN", 1 ) != 0)
+                                {
+                                        /* Static (file-scope) function */
+                                        DefineStaticFunction( token2, value, yp );
+                                }
+                                else if (symeq( token3, ".EFN", 1 ) != 0)
+                                {
+                                        /* End of function */
+                                        DefineEndFunction( value, yp );
+                                }
+                        }
+                        else
+                        {
+                                /* Function-scope var. */
+                                DefineFunction( token2, 0, NULL );
+
+                                /* Look for optional level integer */
+                                j = sscanf( token3, "%[^.]%c%u", token1, &sep1, &level );
+                                if ((j == 3) && (level != 0))
+                                {
+                                        sprintf( &token1[ strlen(token1) ], "_%u", level );
+                                }
+                                DefineScoped( token1, value, yp );
+                        }
+                        break;
+
+                /* either file.symbol or file.line# */
+                case 3:
+                        DefineFile( token1, 0, NULL );
+                        if ((token2[0] >= '0') && (token2[0] <= '9'))
+                        {
+                                /* Line number */
+                                DefineLine( token2, value, yp );
+                        }
+                        else
+                        {
+                                /* File-scope symbol.  (Kill any function) */
+                                DefineEndFunction( 0, NULL );
+                                DefineScoped( token2, value, yp );
+                        }
+                        break;
+
+                /* NoICE file.func. is illegal */
+                case 4:
+
+                /* NoICE symbol. is illegal */
+                case 2:
+
+                /* just a symbol */
+                case 1:
+
+                /* NoICE .symbol is illegal */
+                case 0:
+                default:
+                        DefineGlobal( name, value, yp );
+                        break;
+        }
+}
+
+
+/*)Function     VOID    DefineGlobal()
+ *
+ *              char *          name    pointer to the symbol string
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function DefineGlobal() places a DEF statement
+ *      in the .noi debug file for the global symbol.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    PagedAddress()  lknoice.c
+ *
+ *      side effects:
+ *              A global symbol definition is
+ *              placed in the .noi debug file.
+ */
+
+void DefineGlobal( char *name, a_uint value, struct bank *yp )
+{
+        fprintf( jfp, "DEF %s ", name );
+        PagedAddress( value, yp );
+}
+
+
+/*)Function     VOID    DefineScoped()
+ *
+ *              char *          name    pointer to the symbol string
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function DefineScoped() places a DEFS statement
+ *      in the .noi debug file for the scoped symbol.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    PagedAddress()  lknoice.c
+ *
+ *      side effects:
+ *              A scoped symbol definition is
+ *              placed in the .noi debug file.
+ */
+
+void DefineScoped( char *name, a_uint value, struct bank *yp )
+{
+        fprintf( jfp, "DEFS %s ", name );
+        PagedAddress( value, yp );
+}
+
+
+/*)Function     VOID    DefineFile()
+ *
+ *              char *          name    pointer to the symbol string
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function DefineFile() places a FILE statement
+ *      in the .noi debug file for the processed file.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    PagedAddress()  lknoice.c
+ *              char *  strcpy()        c_library
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              A file name definition is
+ *              placed in the .noi debug file.
+ */
+
+void DefineFile( char *name, a_uint value, struct bank *yp )
+{
+        if (symeq( name, currentFile, 1 ) == 0)
+        {
+                strcpy( currentFile, name );
+                if (value != 0)
+                {
+                        fprintf( jfp, "FILE %s ", name );
+                        PagedAddress( value, yp );
+                }
+                else
+                {
+                        fprintf( jfp, "FILE %s\n", name );
+                }
+        }
+}
+
+
+/*)Function     VOID    DefineFunction()
+ *
+ *              char *          name    pointer to the symbol string
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function DefineFunction() places a FUNC statement
+ *      in the .noi debug file for the processed symbol.  If
+ *      a vaulue is present then a preceeding DEF statement is
+ *      also placed in the .noi debug file.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    PagedAddress()  lknoice.c
+ *              char *  strcpy()        c_library
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              A function definition is
+ *              placed in the .noi debug file.
+ */
+
+void DefineFunction( char *name, a_uint value, struct bank *yp )
+{
+        if (symeq( name, currentFunction, 1 ) == 0)
+        {
+                strcpy( currentFunction, name );
+                if (value != 0)
+                {
+                        fprintf( jfp, "DEF %s ", name );
+                        PagedAddress( value, yp );
+                        fprintf( jfp, "FUNC %s ", name );
+                        PagedAddress( value, yp );
+                }
+                else
+                {
+                        fprintf( jfp, "FUNC %s\n", name );
+                }
+        }
+}
+
+
+/*)Function     VOID    DefineStaticFunction()
+ *
+ *              char *          name    pointer to the symbol string
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function DefineStaticFunction() places a SFUNC statement
+ *      in the .noi debug file for the processed file.  If
+ *      a value is present then a preceeding DEFS statement is
+ *      also placed in the .noi debug file.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    PagedAddress()  lknoice.c
+ *              char *  strcpy()        c_library
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              A static function definition is
+ *              placed in the .noi debug file.
+ */
+
+void DefineStaticFunction( char *name, a_uint value, struct bank *yp )
+{
+        if (symeq( name, currentFunction, 1 ) == 0)
+        {
+                strcpy( currentFunction, name );
+                if (value != 0)
+                {
+                        fprintf( jfp, "DEFS %s ", name );
+                        PagedAddress( value, yp );
+                        fprintf( jfp, "SFUNC %s ", name );
+                        PagedAddress( value, yp );
+                }
+                else
+                {
+                        fprintf( jfp, "SFUNC %s\n", name );
+                }
+        }
+}
+
+
+/*)Function     VOID    DefineEndFunction()
+ *
+ *              char *          name    pointer to the symbol string
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function DefineEndFunction() places an ENDF statement
+ *      in the .noi debug file for the processed file.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    PagedAddress()  lknoice.c
+ *              char *  strcpy()        c_library
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              An end function definition is
+ *              placed in the .noi debug file.
+ */
+
+void DefineEndFunction( a_uint value, struct bank *yp )
+{
+        if (currentFunction[0] != 0)
+        {
+                if (value != 0)
+                {
+                        fprintf( jfp, "ENDF " );
+                        PagedAddress( value, yp );
+                }
+                else
+                {
+                        fprintf( jfp, "ENDF\n" );
+                }
+
+                currentFunction[0] = 0;
+        }
+}
+
+
+/*)Function     VOID    DefineLine()
+ *
+ *              char *          name    pointer to the symbol string
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function DefineLine() places a LINE statement
+ *      in the .noi debug file for the processed file.
+ *
+ *      local variables:
+ *              int     indigit         converted digit
+ *              int     lineNumber      converted line number
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    PagedAddress()  lknoice.c
+ *              int     digit()         lkeval.c
+ *
+ *      side effects:
+ *              A Line definition is
+ *              placed in the .noi debug file.
+ */
+
+void DefineLine( char *lineString, a_uint value, struct bank *yp )
+{
+        int indigit, lineNumber;
+
+        lineNumber = 0;
+        while( (indigit=digit( *lineString++, 10 )) >= 0)
+        {
+                lineNumber = 10*lineNumber + indigit;
+        }
+        fprintf( jfp, "LINE %u ", lineNumber );
+        PagedAddress( value, yp );
+}
+
+
+/*)Function     VOID    PagedAddress()
+ *
+ *              a_uint          value   value of symbol
+ *              struct bank *   yp      pointer to associated bank
+ *
+ *      The function PagedAddress() places the value
+ *      in the .noi debug file for the processed value.
+ *      If the current bank is "mapped" then the page
+ *      number preceeds the value as xx:.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              FILE *  jfp             NoICE Debug File handle
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *
+ *      side effects:
+ *              A value is appended to the current
+ *              line placed in the .noi debug file.
+ */
+
+void PagedAddress( a_uint value, struct bank *yp )
+{
+        if (yp->b_flag & B_MAP) {
+                fprintf( jfp, "%X:0x%X\n", yp->b_map, value );
+        } else {
+                fprintf( jfp, "0x%X\n", value );
+        }
+}
+
+#endif
diff --git a/Kernel/tools/bankld/lkout.c b/Kernel/tools/bankld/lkout.c
new file mode 100644 (file)
index 0000000..090ee6a
--- /dev/null
@@ -0,0 +1,957 @@
+/* lkout.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ *   With enhancements by
+ *
+ *      G. Osborn
+ *      gary@s-4.com.
+ */
+
+#include "aslink.h"
+
+/*)Module       lkout.c
+ *
+ *      The module lkout.c contains the dispatch
+ *      function to create the relocated object
+ *      code output in the required format.
+ *
+ *      lkout.c contains the following functions:
+ *              VOID    lkout()
+ *              VOID    lkflush()
+ *              VOID    ixx()
+ *              VOID    iflush()
+ *              VOID    dbx()
+ *              VOID    dflush()
+ *
+ *      lkout.c contains no local variables.
+ */
+
+/*)Function     lkout(i)
+ *
+ *              int     i               1 - process data
+ *                                      0 - end of data
+ *
+ *      The function lkout() dispatches to the
+ *      required output format routine.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              int     oflag           output type flag
+ *              int     obj_flag        Output enabled flag
+ *              FILE *  ofp             output file handle
+ *              a_uint  pc              Current relocation address
+ *              int     pcb             Current pc bytes per address
+ *
+ *      functions called:
+ *              VOID    ixx()           lkout.c
+ *              VOID    s19()           lks19.c
+ *              VOID    dbx()           lkout.c
+ *              VOID    elf()           lkelf.c
+ *
+ *      side effects:
+ *              The REL data is output in the required format.
+ */
+
+VOID
+lkout(int i, int b)
+{
+        int j;
+
+        if (i && obj_flag) { return; }
+        if (ofp == NULL)   { return; }
+
+        /*
+         * Create the Byte Output Address
+         */
+        for (j=1; j<pcb; j++) {
+                adb_xb(pc, 0);
+        }
+
+        /*
+         * Intel Formats
+         */
+        if (oflag == 1) {
+                ixx(i, b);
+        } else
+        /*
+         * Motorola Formats
+         */
+        if (oflag == 2) {
+                s19(i);
+        } else
+        /*
+         * Disk Basic Formats
+         */
+        if (oflag == 3) {
+                dbx(i);
+        } else
+        /*
+         * Elf Formats
+         */
+        if (oflag == 4) {
+                elf(i);
+        }
+}
+
+
+/*)Function     lkflush()
+ *
+ *      The function lkflush() dispatches
+ *      to the required data flushing routine.
+ *
+ *      local variables:
+ *              none
+ *
+ *      global variables:
+ *              int     oflag           output type flag
+ *              FILE *  ofp             output file handle
+ *
+ *      functions called:
+ *              VOID    iflush()        lkout.c
+ *              VOID    sflush()        lks19.c
+ *              VOID    dflush()        lkout.c
+ *
+ *      side effects:
+ *              Any remaining REL data is flushed
+ *              to the output file.
+ */
+
+VOID
+lkflush()
+{
+        if (ofp == NULL)   { return; }
+
+        /*
+         * Intel Formats
+         */
+        if (oflag == 1) {
+                iflush();
+        } else
+        /*
+         * Motorola Formats
+         */
+        if (oflag == 2) {
+                sflush();
+        } else
+        /*
+         * Disk Basic Formats
+         */
+        if (oflag == 3) {
+                dflush();
+        }
+}
+
+
+/*Intel Format
+ *      Record Mark Field    -  This  field  signifies  the  start  of a
+ *                              record, and consists of an  ascii  colon
+ *                              (:).
+ *
+ *      Record Length Field  -  This   field   consists   of  two  ascii
+ *                              characters which indicate the number  of
+ *                              data   bytes   in   this   record.   The
+ *                              characters are the result of  converting
+ *                              the  number  of  bytes  in binary to two
+ *                              ascii characters, high digit first.   An
+ *                              End  of  File  record contains two ascii
+ *                              zeros in this field.
+ *
+ *      Load Address Field   -  This  field  consists  of the four ascii
+ *                              characters which result from  converting
+ *                              the  the  binary value of the address in
+ *                              which to begin loading this record.  The
+ *                              order is as follows:
+ *
+ *                                  High digit of high byte of address.
+ *                                  Low digit of high byte of address.
+ *                                  High digit of low byte of address.
+ *                                  Low digit of low byte of address.
+ *
+ *                              In an End of File record this field con-
+ *                              sists of four ascii zeros, in a start
+ *                              address record this is the program entry
+ *                              address (low), or in a segment record
+ *                              this is the high order address.
+ *
+ *      Record Type Field    -  This  field  identifies the record type,
+ *                              which is either 0 for data records,  1
+ *                              for an End of File record, 3 for a
+ *                              start address, or 4 for a
+ *                              segment record.  It consists
+ *                              of two ascii characters, with  the  high
+ *                              digit of the record type first, followed
+ *                              by the low digit of the record type.
+ *
+ *      Data Field           -  This  field consists of the actual data,
+ *                              converted to two ascii characters,  high
+ *                              digit first.  There are no data bytes in
+ *                              the End of File record.
+ *
+ *      Checksum Field       -  The  checksum  field is the 8 bit binary
+ *                              sum of the record length field, the load
+ *                              address  field,  the  record type field,
+ *                              and the data field.  This  sum  is  then
+ *                              negated  (2's  complement) and converted
+ *                              to  two  ascii  characters,  high  digit
+ *                              first.
+ */
+
+/*)Function     ixx(i, b)
+ *
+ *              int     i               1 - process data
+ *                                      0 - end of data
+ *             int     b               - bank tag
+ *
+ *      The function ixx() loads the output buffer with
+ *      the relocated data.
+ *
+ *      local variables:
+ *              a_uint  chksum          byte checksum
+ *              a_uint  lo_addr         address within segment
+ *              a_uint  hi_addr         segment number
+ *              int     i               loop counter
+ *              a_uint  j               temporary
+ *              int     k               loop counter
+ *              struct sym *sp          symbol pointer
+ *              a_uint  symadr          symbol address
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *              int     hilo            byte order
+ *              FILE *  ofp             output file handle
+ *              int     rtaflg          first output flag
+ *              int     rtcnt           count of data words
+ *              int     rtflg[]         output the data flag
+ *              a_uint  rtval[]         relocated data
+ *              char    rtbuf[]         output buffer
+ *              a_uint  rtadr0          address temporary
+ *              a_uint  rtadr1          address temporary
+ *              a_uint  rtadr2          address temporary
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    iflush()        lkout.c
+ *
+ *      side effects:
+ *              The data is placed into the output buffer.
+ */
+
+/*
+ * The number of Data Field bytes is:
+ *
+ *      1       Record Mark Field
+ *      2       Record Length Field
+ *      4       Load Address Field
+ *      2       Record Type Field
+ *      2       Checksum Field
+ *
+ *      Plus 32 data bytes (64 characters)
+ */
+
+static int i_lb = -1;
+
+VOID
+ixx(int i, int b)
+{
+        int k;
+        struct sym *sp;
+        a_uint j, symadr, chksum;
+
+        if (i) {
+                if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD)
+                        return;
+
+                if (hilo == 0) {
+                        switch(a_bytes){
+                        default:
+                        case 2:
+                                j = rtval[0];
+                                rtval[0] = rtval[1];
+                                rtval[1] = j;
+                                break;
+                        case 3:
+                                j = rtval[0];
+                                rtval[0] = rtval[2];
+                                rtval[2] = j;
+                                break;
+                        case 4:
+                                j = rtval[0];
+                                rtval[0] = rtval[3];
+                                rtval[3] = j;
+                                j = rtval[2];
+                                rtval[2] = rtval[1];
+                                rtval[1] = j;
+                                break;
+                        }
+                }
+                for (i=0,rtadr2=0; i<a_bytes; i++) {
+                        rtadr2 = (rtadr2 << 8) | rtval[i];
+                }
+                if ((rtadr2 != rtadr1) || rtaflg || b != i_lb) {
+                        /*
+                         * data bytes not contiguous between records
+                         */
+                        iflush();
+                        i_lb = b;
+                        rtadr0 = rtadr1 = rtadr2;
+                        rtaflg = 0;
+                }
+                for (k=a_bytes; k<rtcnt; k++) {
+                        if (rtflg[k]) {
+                                rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
+                                if ((rtadr1 & 0xffff) == 0) {
+                                        iflush();
+                                }
+                                if (rtadr1 - rtadr0 == IXXMAXBYTES) {
+                                        iflush();
+                                }
+                        }
+                }
+        } else {
+                sp = lkpsym(".__.END.", 0);
+                if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
+                        symadr = symval(sp);
+                        chksum =  0x04;
+                        chksum += 0x05;
+                        chksum += symadr;
+                        chksum += symadr >> 8;
+                        chksum += symadr >> 16;
+                        chksum += symadr >> 24;
+#ifdef  LONGINT
+                        fprintf(ofp, ":04000005%08lX%02lX\n", symadr, (~chksum + 1) & 0x00ff);
+#else
+                        fprintf(ofp, ":04000005%08X%02X\n", symadr, (~chksum + 1) & 0x00ff);
+#endif
+                }
+
+                fprintf(ofp, ":00000001FF\n");
+        }
+}
+
+
+/*)Function     iflush()
+ *
+ *      The function iflush() outputs the relocated data
+ *      in the standard Intel format.
+ *
+ *      local variables:
+ *              a_uint  chksum          byte checksum
+ *              a_uint  lo_addr         address within segment
+ *              a_uint  hi_addr         segment number
+ *              int     i               loop counter
+ *              int     max             number of data bytes
+ *              int     reclen          record length
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *              FILE *  ofp             output file handle
+ *              int     rtaflg          first output flag
+ *              char    rtbuf[]         output buffer
+ *              a_uint  rtadr0          address temporary
+ *              a_uint  rtadr1          address temporary
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *
+ *      side effects:
+ *              The data is output to the file defined by ofp.
+ */
+
+/*
+ * This function derived from the work
+ * of G. Osborn, gary@s-4.com.
+ * The new version concatenates the assembler
+ * output records when they represent contiguous
+ * memory segments to produce IXXMAXBYTES data byte
+ * Intel Hex output lines whenever possible, resulting
+ * in a substantial reduction in file size.
+ * More importantly, the download time
+ * to the target system is much improved.
+ */
+
+VOID
+iflush(void)
+{
+        int i, max, reclen;
+        a_uint chksum, lo_addr, hi_addr;
+
+        max = (int) (rtadr1 - rtadr0);
+        if (max) {
+                if (a_bytes > 2) {
+                        static a_uint prev_hi_addr = 0;
+
+                        hi_addr = (rtadr0 >> 16) & 0xffff;
+                        if ((hi_addr != prev_hi_addr) || rtaflg) {
+                                chksum =  0x02;
+                                chksum += 0x04;
+                                chksum += hi_addr;
+                                chksum += hi_addr >> 8;
+#ifdef  LONGINT
+                                fprintf(ofp, "%02X:02000004%04lX%02lX\n", i_lb, hi_addr, (~chksum + 1) & 0x00ff);
+#else
+                                fprintf(ofp, "%02X:02000004%04X%02X\n", i_lb, hi_addr, (~chksum + 1) & 0x00ff);
+#endif
+                                prev_hi_addr = hi_addr;
+                        }
+                }
+
+                /*
+                 * Only the ":" and the checksum itself are excluded
+                 * from the checksum.  The record length includes
+                 * only the data bytes.
+                 */
+                lo_addr = rtadr0 & 0xffff;
+                reclen = max;
+                chksum = reclen;
+                chksum += lo_addr;
+                chksum += lo_addr >> 8;
+#ifdef  LONGINT
+                fprintf(ofp, "%02X:%02X%04lX00", i_lb, reclen, lo_addr);
+#else
+                fprintf(ofp, "%02X:%02X%04X00", i_lb, reclen, lo_addr);
+#endif
+                for (i=0; i<max; i++) {
+                        chksum += rtbuf[i];
+                        fprintf(ofp, "%02X", rtbuf[i] & 0x00ff);
+                }
+                /*
+                 * 2's complement
+                 */
+#ifdef  LONGINT
+                fprintf(ofp, "%02lX\n", (~chksum + 1) & 0x00ff);
+#else
+                fprintf(ofp, "%02X\n", (~chksum + 1) & 0x00ff);
+#endif
+                rtadr0 = rtadr1;
+        }
+
+}
+
+#if 0
+/*)S19/S28/S37 Formats
+ *      Record Type Field    -  This  field  signifies  the  start  of a
+ *                              record and  identifies  the  the  record
+ *                              type as follows:
+ *
+ *             2-Byte Address:      Ascii S1 - Data Record
+ *                                  Ascii S9 - End of File Record
+ *             3-Byte Address:      Ascii S2 - Data Record
+ *                                  Ascii S8 - End of File Record
+ *             4-Byte Address:      Ascii S3 - Data Record
+ *                                  Ascii S7 - End of File Record
+ *
+ *      Record Length Field  -  This  field  specifies the record length
+ *                              which includes the  address,  data,  and
+ *                              checksum   fields.   The  8  bit  record
+ *                              length value is converted to  two  ascii
+ *                              characters, high digit first.
+ *
+ *      Load Address Field   -  This  field  consists  of the 4/6/8 ascii
+ *                              characters which result from  converting
+ *                              the  the  binary value of the address in
+ *                              which to begin loading this record.  The
+ *                              order is as follows:
+ *
+ *           S37:                   High digit of fourth byte of address.
+ *                                  Low digit of fourth byte of address.
+ *           S28/S37:               High digit of third byte of address.
+ *                                  Low digit of third byte of address.
+ *           S19/S28/S37:           High digit of high byte of address.
+ *                                  Low digit of high byte of address.
+ *                                  High digit of low byte of address.
+ *                                  Low digit of low byte of address.
+ *
+ *                              In an End of File record this field con-
+ *                              sists of either 4/6/8 ascii zeros or  the
+ *                              program  entry  address.
+ *
+ *      Data Field           -  This  field consists of the actual data,
+ *                              converted to two ascii characters,  high
+ *                              digit first.  There are no data bytes in
+ *                              the End of File record.
+ *
+ *      Checksum Field       -  The  checksum  field is the 8 bit binary
+ *                              sum of the record length field, the load
+ *                              address field, and the data field.  This
+ *                              sum is then  complemented  (1's  comple-
+ *                              ment)   and   converted   to  two  ascii
+ *                              characters, high digit first.
+ */
+
+/*)Function     sxx(i)
+ *
+ *              int     i               1 - process data
+ *                                      0 - end of data
+ *
+ *      The function s19() loads the output buffer with
+ *      the relocated data.
+ *
+ *      local variables:
+ *              a_uint  addr            address temporary
+ *              a_uint  chksum          byte checksum
+ *              char *  frmt            format string pointer
+ *              int     i               loop counter
+ *              a_uint  j               temporary
+ *              int     k               loop counter
+ *              int     max             number of data bytes
+ *              int     reclen          record length
+ *              struct sym *sp          symbol pointer
+ *              a_uint  symadr          symbol address
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *              int     hilo            byte order
+ *              FILE *  ofp             output file handle
+ *              int     rtcnt           count of data words
+ *              int     rtflg[]         output the data flag
+ *              a_uint  rtval[]         relocated data
+ *              char    rtbuf[]         output buffer
+ *              a_uint  rtadr0          address temporary
+ *              a_uint  rtadr1          address temporary
+ *              a_uint  rtadr2          address temporary
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    sflush()        lkout.c
+ *
+ *      side effects:
+ *              The data is placed into the output buffer.
+ */
+
+/*
+ * Number of Data Field bytes is:
+ *
+ *      2       Record Type Field
+ *      2       Record Length Field
+ *      4/6/8   Load Address Field
+ *      2       Checksum Field
+ *
+ *      Plus 32 data bytes (64 characters)
+ */
+
+VOID
+sxx(i)
+int i;
+{
+        struct sym *sp;
+        char *frmt;
+        int k, reclen;
+        a_uint  j, addr, symadr, chksum;
+
+        if (i) {
+                if (hilo == 0) {
+                        switch(a_bytes){
+                        default:
+                        case 2:
+                                j = rtval[0];
+                                rtval[0] = rtval[1];
+                                rtval[1] = j;
+                                break;
+                        case 3:
+                                j = rtval[0];
+                                rtval[0] = rtval[2];
+                                rtval[2] = j;
+                                break;
+                        case 4:
+                                j = rtval[0];
+                                rtval[0] = rtval[3];
+                                rtval[3] = j;
+                                j = rtval[2];
+                                rtval[2] = rtval[1];
+                                rtval[1] = j;
+                                break;
+                        }
+                }
+                for (i=0,rtadr2=0; i<a_bytes; i++) {
+                        rtadr2 = (rtadr2 << 8) | rtval[i];
+                }
+
+                if (rtadr2 != rtadr1) {
+                        /*
+                         * data bytes not contiguous between records
+                         */
+                        sflush();
+                        rtadr0 = rtadr1 = rtadr2;
+                }
+                for (k=a_bytes; k<rtcnt; k++) {
+                        if (rtflg[k]) {
+                                rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
+                                if (rtadr1 - rtadr0 == SXXMAXBYTES) {
+                                        sflush();
+                                }
+                        }
+                }
+        } else {
+                /*
+                 * Only the "S_" and the checksum itself are excluded
+                 * from the checksum.  The record length does not
+                 * include "S_" and the pair count.  It does
+                 * include the address bytes, the data bytes,
+                 * and the checksum.
+                 */
+                reclen = 1 + a_bytes;
+                chksum = reclen;
+                sp = lkpsym(".__.END.", 0);
+                if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
+                        symadr = symval(sp);
+                        for (i=0,addr=symadr; i<a_bytes; i++,addr>>=8) {
+                                chksum += addr;
+                        }
+                } else {
+                        symadr = 0;
+                }
+#ifdef  LONGINT
+                switch(a_bytes) {
+                default:
+                case 2: frmt = "S9%02X%04lX"; addr = symadr & 0x0000ffffl; break;
+                case 3: frmt = "S8%02X%06lX"; addr = symadr & 0x00ffffffl; break;
+                case 4: frmt = "S7%02X%08lX"; addr = symadr & 0xffffffffl; break;
+                }
+#else
+                switch(a_bytes) {
+                default:
+                case 2: frmt = "S9%02X%04X"; addr = symadr & 0x0000ffff; break;
+                case 3: frmt = "S8%02X%06X"; addr = symadr & 0x00ffffff; break;
+                case 4: frmt = "S7%02X%08X"; addr = symadr & 0xffffffff; break;
+                }
+#endif
+                fprintf(ofp, frmt, reclen, addr);
+                /*
+                 * 1's complement
+                 */
+#ifdef  LONGINT
+                fprintf(ofp, "%02lX\n", (~chksum) & 0x00ff);
+#else
+                fprintf(ofp, "%02X\n", (~chksum) & 0x00ff);
+#endif
+        }
+}
+
+
+/*)Function     sflush()
+ *
+ *      The function sflush() outputs the relocated data
+ *      in the standard Motorola format.
+ *
+ *      local variables:
+ *              a_uint  addr            address temporary
+ *              a_uint  chksum          byte checksum
+ *              char *  frmt            format string pointer
+ *              int     i               loop counter
+ *              int     max             number of data bytes
+ *              int     reclen          record length
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *              FILE *  ofp             output file handle
+ *              char    rtbuf[]         output buffer
+ *              a_uint  rtadr0          address temporary
+ *              a_uint  rtadr1          address temporary
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *
+ *      side effects:
+ *              The data is output to the file defined by ofp.
+ */
+
+/*
+ * Written by G. Osborn, gary@s-4.com, 6-17-98.
+ * The new version concatenates the assembler
+ * output records when they represent contiguous
+ * memory segments to produce SXXMAXBYTES data byte
+ * S_ output lines whenever possible, resulting
+ * in a substantial reduction in file size.
+ * More importantly, the download time
+ * to the target system is much improved.
+ */
+
+VOID
+sflush()
+{
+        char *frmt;
+        int i, max, reclen;
+        a_uint  addr, chksum;
+
+        max = (int) (rtadr1 - rtadr0);
+        if (max == 0) {
+                return;
+        }
+
+        /*
+         * Only the "S_" and the checksum itself are excluded
+         * from the checksum.  The record length does not
+         * include "S_" and the pair count.  It does
+         * include the address bytes, the data bytes,
+         * and the checksum.
+         */
+        reclen = max + 1 + a_bytes;
+        chksum = reclen;
+        for (i=0,addr=rtadr0; i<a_bytes; i++,addr>>=8) {
+                chksum += addr;
+        }
+#ifdef  LONGINT
+        switch(a_bytes) {
+        default:
+        case 2: frmt = "S1%02X%04lX"; addr = rtadr0 & 0x0000ffffl; break;
+        case 3: frmt = "S2%02X%06lX"; addr = rtadr0 & 0x00ffffffl; break;
+        case 4: frmt = "S3%02X%08lX"; addr = rtadr0 & 0xffffffffl; break;
+        }
+#else
+        switch(a_bytes) {
+        default:
+        case 2: frmt = "S1%02X%04X"; addr = rtadr0 & 0x0000ffff; break;
+        case 3: frmt = "S2%02X%06X"; addr = rtadr0 & 0x00ffffff; break;
+        case 4: frmt = "S3%02X%08X"; addr = rtadr0 & 0xffffffff; break;
+        }
+#endif
+        fprintf(ofp, frmt, reclen, addr);
+        for (i=0; i<max; i++) {
+                chksum += rtbuf[i];
+                fprintf(ofp, "%02X", rtbuf[i] & 0x00ff);
+        }
+        /*
+         * 1's complement
+         */
+#ifdef  LONGINT
+        fprintf(ofp, "%02lX\n", (~chksum) & 0x00ff);
+#else
+        fprintf(ofp, "%02X\n", (~chksum) & 0x00ff);
+#endif
+        rtadr0 = rtadr1;
+}
+#endif
+
+/*)Disk BASIC Format
+ *
+ * Each code segment starts with the following record:
+ *
+ *      Record Preamble      -  This field is either $00 (for start of new
+ *                              record) or $FF (for last record in file).
+ *
+ *      Record Length Field  -  This field specifies the record length
+ *                              that follows the Load Address Field.
+ *
+ *           16-Bit Length   -  2-bytes
+ *           24-Bit Length   -  3-bytes
+ *           32-Bit Length   -  4-bytes
+ *
+ *      Load Address Field   -  This field consists of the address where
+ *                              the record will be loaded into memory.
+ *
+ *           16-Bit Address  -  2-bytes
+ *           24-Bit Address  -  3-bytes
+ *           32-Bit Address  -  4-bytes
+ *
+ *      Binary Data Bytes    -  Record Length data bytes.
+ *
+ * After the last code segment, a final record like the one above is
+ * placed.  In this final segment, the Record Preamble is $FF, the
+ * Record Length Field is $0000 and the Load Adress Field is the
+ * execution address.
+ */
+
+/*)Function     dbx(i)
+ *
+ *              int     i               1 - process data
+ *                                      0 - end of data
+ *
+ *      The function decb() loads the output buffer with
+ *      the relocated data.
+ *
+ *      local variables:
+ *              int     k               loop counter
+ *              struct sym *sp          symbol pointer
+ *              a_uint  symadr          start address
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *              FILE *  ofp             output file handle
+ *              int     rtcnt           count of data words
+ *              int     rtflg[]         output the data flag
+ *              a_uint  rtval[]         relocated data
+ *              char    rtbuf[]         output buffer
+ *              a_uint  rtadr0          address temporary
+ *              a_uint  rtadr1          address temporary
+ *              a_uint  rtadr2          address temporary
+ *
+ *      functions called:
+ *              int     putc()          c_library
+ *              VOID    dflush()        lkout.c
+ *
+ *      side effects:
+ *              The data is placed into the output buffer.
+ */
+
+VOID
+dbx(i)
+int i;
+{
+        struct sym *sp;
+        int k;
+        a_uint  j, symadr;
+
+        if (i) {
+                if (hilo == 0) {
+                        switch(a_bytes){
+                        default:
+                        case 2:
+                                j = rtval[0];
+                                rtval[0] = rtval[1];
+                                rtval[1] = j;
+                                break;
+                        case 3:
+                                j = rtval[0];
+                                rtval[0] = rtval[2];
+                                rtval[2] = j;
+                                break;
+                        case 4:
+                                j = rtval[0];
+                                rtval[0] = rtval[3];
+                                rtval[3] = j;
+                                j = rtval[2];
+                                rtval[2] = rtval[1];
+                                rtval[1] = j;
+                                break;
+                        }
+                }
+                for (i=0,rtadr2=0; i<a_bytes; i++) {
+                        rtadr2 = (rtadr2 << 8) | rtval[i];
+                }
+
+                if (rtadr2 != rtadr1) {
+                        /*
+                         * data bytes not contiguous between records
+                         */
+                        dflush();
+                        rtadr0 = rtadr1 = rtadr2;
+                }
+                for (k=a_bytes; k<rtcnt; k++) {
+                        if (rtflg[k]) {
+                                rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
+                                if (rtadr1 - rtadr0 == (unsigned) (DBXMAXBYTES - (2 * a_bytes) - 1)) {
+                                        dflush();
+                                }
+                        }
+                }
+        } else {
+                /* Disk BASIC BIN Trailer */
+                sp = lkpsym(".__.END.", 0);
+                if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
+                        symadr = symval(sp);
+                } else {
+                        symadr = 0;
+                }
+                /* Terminator */
+                putc(0xFF, ofp);
+
+                /* Size (0) */
+                switch(a_bytes) {
+                case 4: putc((int) (0 >> 24) & 0xFF, ofp);
+                case 3: putc((int) (0 >> 16) & 0xFF, ofp);
+                default:
+                case 2: putc((int) (0 >>  8) & 0xFF, ofp);
+                        putc((int) (0 >>  0) & 0xFF, ofp);
+                        break;
+                }
+
+                /* Starting Address */
+                switch(a_bytes) {
+                case 4: putc((int) (symadr >> 24) & 0xFF, ofp);
+                case 3: putc((int) (symadr >> 16) & 0xFF, ofp);
+                default:
+                case 2: putc((int) (symadr >>  8) & 0xFF, ofp);
+                        putc((int) (symadr >>  0) & 0xFF, ofp);
+                        break;
+                }
+        }
+}
+
+
+/*)Function     dflush()
+ *
+ *      The function dflush() outputs the relocated data
+ *      in the Disk BASIC loadable format
+ *
+ *      local variables:
+ *              int     i               loop counter
+ *              int     max             number of data bytes
+ *
+ *      global variables:
+ *              FILE *  ofp             output file handle
+ *              char    rtbuf[]         output buffer
+ *              a_uint  rtadr0          address temporary
+ *              a_uint  rtadr1          address temporary
+ *
+ *      functions called:
+ *              int     putc()          c_library
+ *
+ *      side effects:
+ *              The data is output to the file defined by ofp.
+ */
+
+/*
+ * Written by Boisy G. Pitre, boisy@boisypitre.com, 6-7-04
+ */
+
+VOID
+dflush()
+{
+        int i, max;
+
+        max = (int) (rtadr1 - rtadr0);
+        if (max == 0) {
+                return;
+        }
+
+        /* Preamble Byte */
+        putc(0, ofp);
+
+        /* Record Size */
+        switch(a_bytes){
+        case 4: putc((int) (max >> 24) & 0xFF, ofp);
+        case 3: putc((int) (max >> 16) & 0xFF, ofp);
+        default:
+        case 2: putc((int) (max >>  8) & 0xFF, ofp);
+                putc((int) (max >>  0) & 0xFF, ofp);
+                break;
+        }
+
+        /* Load Address */
+        switch(a_bytes){
+        case 4: putc((int) (rtadr0 >> 24) & 0xFF, ofp);
+        case 3: putc((int) (rtadr0 >> 16) & 0xFF, ofp);
+        default:
+        case 2: putc((int) (rtadr0 >>  8) & 0xFF, ofp);
+                putc((int) (rtadr0 >>  0) & 0xFF, ofp);
+                break;
+        }
+
+        for (i = 0; i < max; i++) {
+                putc(rtbuf[i], ofp);
+        }
+
+        rtadr0 = rtadr1;
+}
diff --git a/Kernel/tools/bankld/lkrel.c b/Kernel/tools/bankld/lkrel.c
new file mode 100644 (file)
index 0000000..2210fec
--- /dev/null
@@ -0,0 +1,156 @@
+/* lkrel.c - .rel object file handling
+
+   Copyright (C) 1989-1995 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+   Copyright (C) 2008-2010 Borut Razem, borut dot razem at siol dot net
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <assert.h>
+
+#include "lk_readnl.h"
+#include "aslink.h"
+#include "lkrel.h"
+
+int
+is_rel (FILE * libfp)
+{
+  int c;
+  long pos = ftell (libfp);
+  int ret = 0;
+
+  /* [XDQ][HL][234] */
+  if (((c = getc (libfp)) == 'X' || c == 'D' || c == 'Q') && ((c = getc (libfp)) == 'H' || c == 'L'))
+    {
+      switch (getc (libfp))
+        {
+        case '2':
+        case '3':
+        case '4':
+          switch (getc (libfp))
+            {
+            case '\r':
+              if (getc (libfp) == '\n')
+                ret = 1;
+              break;
+
+            case '\n':
+              ret = 1;
+            }
+          break;
+
+        case '\r':
+          if (getc (libfp) == '\n')
+            ret = 1;
+          break;
+
+        case '\n':
+          ret = 1;
+        }
+    }
+  else if (c == ';')
+    {
+      char buf[6];
+
+      if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, "!FILE ", 6) == 0)
+        ret = 1;
+    }
+  fseek (libfp, pos, SEEK_SET);
+  return ret;
+}
+
+/* Load a standalone or embedded .rel */
+int
+load_rel (FILE * libfp, long size)
+{
+  if (is_rel (libfp))
+    {
+      char str[NINPUT];
+      long end;
+
+      end = (size >= 0) ? ftell (libfp) + size : -1;
+
+      while ((end < 0 || ftell (libfp) < end) && lk_readnl (str, sizeof (str), libfp) != NULL)
+        {
+          if (0 == strcmp (str, "</REL>"))
+            return 1;
+
+          ip = str;
+          link_main ();
+        }
+
+      return 1;
+    }
+  else
+    return 0;
+}
+
+int
+enum_symbols (FILE * fp, long size, int (*func) (const char *symvoid, void *param), void *param)
+{
+  char buf[NINPUT];
+  long end = (size >= 0) ? ftell (fp) + size : -1;
+
+  assert (func != NULL);
+
+  /*
+   * Read in the object file.  Look for lines that
+   * begin with "S" and end with "D".  These are
+   * symbol table definitions.  If we find one, see
+   * if it is our symbol.  Make sure we only read in
+   * our object file and don't go into the next one.
+   */
+
+  while ((end < 0 || ftell (fp) < end) && lk_readnl (buf, sizeof (buf), fp) != NULL)
+    {
+      char symname[NINPUT];
+      char c;
+
+      /*
+       * When a 'T line' is found terminate file scan.
+       * All 'S line's preceed 'T line's in .REL files.
+       */
+      if (buf[0] == 'T')
+        break;
+
+      /*
+       * Skip everything that's not a symbol record.
+       */
+      if (buf[0] != 'S')
+        continue;
+
+      sscanf (buf, "S %s %c", symname, &c);
+
+      /* If it's an actual symbol, record it */
+      if (c == 'D')
+        {
+          if ((*func) (symname, param))
+            return 1;
+        }
+    }
+
+  return 0;
+}
diff --git a/Kernel/tools/bankld/lkrel.h b/Kernel/tools/bankld/lkrel.h
new file mode 100644 (file)
index 0000000..ec846e8
--- /dev/null
@@ -0,0 +1,51 @@
+/* lkrel.h - .rel object file handling
+
+   Copyright (C) 1989-1995 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+   Copyright (C) 2008-2009 Borut Razem, borut dot razem at siol dot net
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#ifndef __LKREL_H
+#define __LKREL_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+  int is_rel (FILE * libfp);
+  int load_rel (FILE * libfp, long size);
+  int enum_symbols (FILE * fp, long size, int (*func) (const char *symvoid, void *param), void *param);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif                          /* __LKREL_H */
diff --git a/Kernel/tools/bankld/lkrloc.c b/Kernel/tools/bankld/lkrloc.c
new file mode 100644 (file)
index 0000000..30f01a7
--- /dev/null
@@ -0,0 +1,414 @@
+/* lkrloc.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ *   With enhancements from:
+ *
+ *      John L. Hartman (JLH)
+ *      jhartman@compuserve.com
+ *
+ *      Bill McKinnon (BM)
+ *      w_mckinnon@conknet.com
+ */
+
+#include <ctype.h>
+#include "aslink.h"
+
+/*)Module       lkrloc.c
+ *
+ *      The module lkrloc.c contains the functions which
+ *      perform the relocation calculations.
+ *
+ *      lkrloc.c contains the following functions:
+ *              a_uint  adb_1b()
+ *              a_uint  adb_2b()
+ *              a_uint  adb_3b()
+ *              a_uint  adb_4b()
+ *              a_uint  adb_xb()
+ *              a_uint  evword()
+ *              VOID    prntval()
+ *              VOID    reloc()
+ *
+ *
+ */
+
+/*)Function VOID        reloc(c)
+ *
+ *                      int c           process code
+ *
+ *      The function reloc() calls the proper version
+ *      of the linker code.
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              ASxxxx_VERSION          ASxxxx REL file version
+ *
+ *      called functions:
+ *              VOID    reloc3()        lkrloc3.c
+ *              VOID    reloc4()        lkrloc4.c
+ *
+ *      side effects:
+ *              Refer to the called relocation functions.
+ *
+ */
+
+VOID
+reloc(int c)
+{
+        switch(ASxxxx_VERSION) {
+        case 3:
+                reloc3(c);
+                break;
+
+//      case 4:
+//              reloc4(c);
+//              break;
+
+        default:
+                fprintf(stderr, "Internal Version Error");
+                lkexit(ER_FATAL);
+                break;
+        }
+}
+
+
+/*)Function a_uint              evword()
+ *
+ *      The function evword() combines two byte values
+ *      into a single word value.
+ *
+ *      local variable:
+ *              a_uint  v               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              int eval()              lkeval.c
+ *
+ *      side effects:
+ *              Relocation text line is scanned to combine
+ *              two byte values into a single word value.
+ *
+ */
+
+a_uint
+evword(void)
+{
+        a_uint v;
+
+        if (hilo) {
+                v =  (eval() << 8);
+                v +=  eval();
+        } else {
+                v =   eval();
+                v += (eval() << 8);
+        }
+        return(v);
+}
+
+/*)Function a_uint              adb_1b(v, i)
+ *
+ *              a_uint v        value to add to byte
+ *              int i           rtval[] index
+ *
+ *      The function adb_1b() adds the value of v to
+ *      the single byte value contained in rtval[i].
+ *      The new value of rtval[i] is returned.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              none
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_1b(a_uint v, int i)
+{
+        a_uint j;
+
+        j = v + rtval[i];
+        rtval[i] = j & ((a_uint) 0x000000FF);
+
+        return(j);
+}
+
+/*)Function     a_uint  adb_2b(v, i)
+ *
+ *              a_uint  v               value to add to word
+ *              int     i               rtval[] index
+ *
+ *      The function adb_2b() adds the value of v to the
+ *      2 byte value contained in rtval[i] and rtval[i+1].
+ *      The new value of rtval[i] / rtval[i+1] is returned.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The 2 byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_2b(a_uint v, int i)
+{
+        a_uint j;
+
+        if (hilo) {
+                j = v + (rtval[i+0] << 8) +
+                        (rtval[i+1] << 0);
+                rtval[i+0] = (j >> 8) & ((a_uint) 0x000000FF);
+                rtval[i+1] = (j >> 0) & ((a_uint) 0x000000FF);
+        } else {
+                j = v + (rtval[i+0] << 0) +
+                        (rtval[i+1] << 8);
+                rtval[i+0] = (j >> 0) & ((a_uint) 0x000000FF);
+                rtval[i+1] = (j >> 8) & ((a_uint) 0x000000FF);
+        }
+        return(j);
+}
+
+/*)Function     a_uint  adb_3b(v, i)
+ *
+ *              a_uint  v               value to add to word
+ *              int     i               rtval[] index
+ *
+ *      The function adb_3b() adds the value of v to the
+ *      three byte value contained in rtval[i], rtval[i+1], and rtval[i+2].
+ *      The new value of rtval[i] / rtval[i+1] / rtval[i+2] is returned.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The 3 byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_3b(a_uint v, int i)
+{
+        a_uint j;
+
+        if (hilo) {
+                j = v + (rtval[i+0] << 16) +
+                        (rtval[i+1] <<  8) +
+                        (rtval[i+2] <<  0);
+                rtval[i+0] = (j >> 16) & ((a_uint) 0x000000FF);
+                rtval[i+1] = (j >>  8) & ((a_uint) 0x000000FF);
+                rtval[i+2] = (j >>  0) & ((a_uint) 0x000000FF);
+        } else {
+                j = v + (rtval[i+0] <<  0) +
+                        (rtval[i+1] <<  8) +
+                        (rtval[i+2] << 16);
+                rtval[i+0] = (j >>  0) & ((a_uint) 0x000000FF);
+                rtval[i+1] = (j >>  8) & ((a_uint) 0x000000FF);
+                rtval[i+2] = (j >> 16) & ((a_uint) 0x000000FF);
+        }
+        return(j);
+}
+
+/*)Function     a_uint  adb_4b(v, i)
+ *
+ *              a_uint  v               value to add to word
+ *              int     i               rtval[] index
+ *
+ *      The function adb_4b() adds the value of v to the
+ *      four byte value contained in rtval[i], ..., rtval[i+3].
+ *      The new value of rtval[i], ...,  rtval[i+3] is returned.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The 4 byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_4b(a_uint v, int i)
+{
+        a_uint j;
+
+        if (hilo) {
+                j = v + (rtval[i+0] << 24) +
+                        (rtval[i+1] << 16) +
+                        (rtval[i+2] <<  8) +
+                        (rtval[i+3] <<  0);
+                rtval[i+0] = (j >> 24) & ((a_uint) 0x000000FF);
+                rtval[i+1] = (j >> 16) & ((a_uint) 0x000000FF);
+                rtval[i+2] = (j >>  8) & ((a_uint) 0x000000FF);
+                rtval[i+3] = (j >>  0) & ((a_uint) 0x000000FF);
+        } else {
+                j = v + (rtval[i+0] <<  0) +
+                        (rtval[i+1] <<  8) +
+                        (rtval[i+2] << 16) +
+                        (rtval[i+3] << 24);
+                rtval[i+0] = (j >>  0) & ((a_uint) 0x000000FF);
+                rtval[i+1] = (j >>  8) & ((a_uint) 0x000000FF);
+                rtval[i+2] = (j >> 16) & ((a_uint) 0x000000FF);
+                rtval[i+3] = (j >> 24) & ((a_uint) 0x000000FF);
+        }
+        return(j);
+}
+
+/*)Function     a_uint  adb_xb(v, i)
+ *
+ *              a_uint  v               value to add to x-bytes
+ *              int     i               rtval[] index
+ *
+ *      The function adb_xb() adds the value of v to
+ *      the value contained in rtval[i] for x-bytes.
+ *      The new value of rtval[i] for x-bytes is returned.
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              int     a_bytes         T Line Address Bytes
+ *
+ *      called functions:
+ *              a_uint  adb_1b()        lkrloc.c
+ *              a_uint  adb_2b()        lkrloc.c
+ *              a_uint  adb_3b()        lkrloc.c
+ *              a_uint  adb_4b()        lkrloc.c
+ *
+ *      side effects:
+ *              The x-byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_xb(a_uint v, int i)
+{
+        a_uint j;
+
+        switch(a_bytes){
+        case 1:
+                j = adb_1b(v, i);
+                j = (j & ((a_uint) 0x00000080) ? j | ~((a_uint) 0x0000007F) : j & ((a_uint) 0x0000007F));
+                break;
+        case 2:
+                j = adb_2b(v, i);
+                j = (j & ((a_uint) 0x00008000) ? j | ~((a_uint) 0x00007FFF) : j & ((a_uint) 0x00007FFF));
+                break;
+        case 3:
+                j = adb_3b(v, i);
+                j = (j & ((a_uint) 0x00800000) ? j | ~((a_uint) 0x007FFFFF) : j & ((a_uint) 0x007FFFFF));
+                break;
+        case 4:
+                j = adb_4b(v, i);
+                j = (j & ((a_uint) 0x80000000) ? j | ~((a_uint) 0x7FFFFFFF) : j & ((a_uint) 0x7FFFFFFF));
+                break;
+        default:
+                j = 0;
+                break;
+        }
+        return(j);
+}
+
+/*)Function VOID prntval(fptr, v)
+ *
+ *              FILE    *fptr           output file handle
+ *              a_uint  v               value to output
+ *
+ *      The function prntval() outputs the value v, in the
+ *      currently selected radix, to the device specified
+ *      by fptr.
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              int xflag               current radix
+ *
+ *      called functions:
+ *              int fprintf()   c_library
+ *
+ *      side effects:
+ *              none
+ *
+ */
+
+VOID
+prntval(FILE *fptr, a_uint v)
+{
+        char *frmt;
+
+        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;
+        }
+        fprintf(fptr, frmt, v & a_mask);
+}
diff --git a/Kernel/tools/bankld/lkrloc3.c b/Kernel/tools/bankld/lkrloc3.c
new file mode 100644 (file)
index 0000000..033057f
--- /dev/null
@@ -0,0 +1,1357 @@
+/* lkrloc3.c */
+
+/*
+ *  Copyright (C) 1989-2010  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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ *   With enhancements from:
+ *
+ *      John L. Hartman (JLH)
+ *      jhartman@compuserve.com
+ *
+ *      Bill McKinnon (BM)
+ *      w_mckinnon@conknet.com
+ */
+
+#include "aslink.h"
+
+/*)Module       lkrloc3.c
+ *
+ *      The module lkrloc3.c contains the functions which
+ *      perform the version 3 relocation calculations.
+ *
+ *      lkrloc3.c contains the following functions:
+ *              a_uint  adb_lo()
+ *              a_uint  adb_hi()
+ *              VOID    erpdmp3()
+ *              VOID    errdmp3()
+ *              VOID    rele3()
+ *              VOID    relerr3()
+ *              VOID    relerp3()
+ *              VOID    reloc3()
+ *              VOID    relp3()
+ *              VOID    relr3()
+ *              VOID    relt3()
+ *
+ *      lkrloc3.c the local variable errmsg3[].
+ *
+ */
+
+/*)Function VOID        reloc3(c)
+ *
+ *                      int c           process code
+ *
+ *      The function reloc3() calls a particular relocation
+ *      function determined by the process code.
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              int lkerr                       error flag
+ *
+ *      called functions:
+ *              int fprintf()           c_library
+ *              VOID    rele3()         lkrloc3.c
+ *              VOID    relp3()         lkrloc3.c
+ *              VOID    relr3()         lkrloc3.c
+ *              VOId    relt3()         lkrloc3.c
+ *
+ *      side effects:
+ *              Refer to the called relocation functions.
+ *
+ */
+
+VOID
+reloc3(int c)
+{
+        switch(c) {
+
+        case 'T':
+                relt3();
+                break;
+
+        case 'R':
+                relr3();
+                break;
+
+        case 'P':
+                relp3();
+                break;
+
+        case 'E':
+                rele3();
+                break;
+
+        default:
+                fprintf(stderr, "Undefined Relocation Operation\n");
+                lkerr++;
+                break;
+
+        }
+}
+
+
+/*)Function VOID        relt3()
+ *
+ *      The function relt3() evaluates a T line read by
+ *      the linker. Each byte value read is saved in the
+ *      rtval[] array, rtflg[] is set, and the number of
+ *      evaluations is maintained in rtcnt.
+ *
+ *              T Line
+ *
+ *              T xx xx nn nn nn nn nn ...
+ *
+ *
+ *              In: "T n0 n1 n2 n3 ... nn"
+ *
+ *              Out:     0       1        2    ..  rtcnt
+ *                        +----+----+----+----+----+
+ *              rtval | n0 | n1 | n2 | .. | nn |
+ *                        +----+----+----+----+----+
+ *              rtflag|  1 |  1 |  1 |  1 |  1 |
+ *                        +----+----+----+----+----+
+ *
+ *      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.
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              int rtcnt               number of values evaluated
+ *              int rtflg[]             array of evaluation flags
+ *              int rtval[]             array of evaluation values
+ *
+ *      called functions:
+ *              int eval()              lkeval.c
+ *              int more()              lklex.c
+ *
+ *      side effects:
+ *              Linker input T line evaluated.
+ *
+ */
+
+VOID
+relt3(void)
+{
+        rtcnt = 0;
+        while (more()) {
+                if (rtcnt < NTXT) {
+                        rtval[rtcnt] = eval();
+                        rtflg[rtcnt] = 1;
+                        rterr[rtcnt] = 0;
+                        rtcnt++;
+                }
+        }
+}
+
+/* Fuzix _CODE1, _CODE2, _CODE3 indicate magic banking values */
+static int bankmagic(struct areax *ax)
+{
+        struct area *a = ax->a_bap;
+        int c;
+        
+        /* Hack: fix me up */
+        if (strcmp(a->a_id, "_FONT") == 0)
+                return 3;
+        if (strcmp(a->a_id, "_VIDEO") == 0)
+                return 3;
+        if (strcmp(a->a_id, "_DISCARD") == 0)
+                return 3;
+        if (strncmp(a->a_id, "_CODE", 5))
+                return 0;
+        if (a->a_id[5] == 0)   /* We count _CODE and _CODE1 both as first bank */
+                return 1;
+        c = a->a_id[5] - '0';
+        if (c < 1 || c > 9)
+                return 0;
+        return c;
+}
+
+static void bankingstub(struct sym *s, struct areax *bx, int bmagic, int addr)
+{
+        struct areax *ax = s->s_axp;
+        struct area *a = ax->a_bap;
+        int bxm = bankmagic(bx);
+        
+        if (bxm == bmagic)
+                return;
+
+        if (ofp) {
+                fprintf(ofp, "; Banking Stub %s:%s(%s)\n",
+                        a->a_id, s->s_id, s->m_id);
+                fprintf(ofp, "; From area %s\n", bx->a_bap->a_id);
+                fprintf(ofp, "B %02X %04X %02X %s\n",
+                        bxm, addr,
+                        bmagic, bx->a_bap->a_id);
+        }
+        return;
+}
+        
+/*)Function     VOID    relr3()
+ *
+ *      The function relr3() evaluates a R line read by
+ *      the linker.  The R line data is combined with the
+ *      previous T line data to perform the relocation of
+ *      code and data bytes.  The S19 / IHX output and
+ *      translation of the LST files to RST files may be
+ *      performed.
+ *
+ *              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) 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
+ *
+ *      2.  n2  is  a byte index into the corresponding (i.e.  pre-
+ *              ceeding) 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.
+ *
+ *      local variable:
+ *              areax   **a             pointer to array of area pointers
+ *              int     aindex          area index
+ *              char    *errmsg3[]      array of pointers to error strings
+ *              int     error           error code
+ *              int     mode            relocation mode
+ *              adrr_t  paga            paging base area address
+ *              a_uint  pags            paging symbol address
+ *              a_uint  r               PCR relocation value
+ *              a_uint  reli            relocation initial value
+ *              a_uint  relv            relocation final value
+ *              int     rindex          symbol / area index
+ *              a_uint  rtbase          base code address
+ *              a_uint  rtofst          rtval[] index offset
+ *              int rtp                 index into T data
+ *              sym **s                 pointer to array of symbol pointers
+ *
+ *      global variables:
+ *              head    *hp             pointer to the head structure
+ *              int     lkerr           error flag
+ *              a_uint  pc              relocated base address
+ *              int     pcb             bytes per instruction word
+ *              rerr    rerr            linker error structure
+ *              FILE    *stderr         standard error device
+ *
+ *      called functions:
+ *              a_uint  adb_1b()        lkrloc.c
+ *              a_uint  adb_2b()        lkrloc.c
+ *              a_uint  adb_lo()        lkrloc3.c
+ *              a_uint  adb_hi()        lkrloc3.c
+ * sdld specific
+ *              VOID    elf()           lkelf.c
+ *              VOID    gb()            lkgb.c
+ * end sdld specific
+ *              a_uint  evword()        lkrloc.c
+ *              int     eval()          lkeval.c
+ *              int     fprintf()       c_library
+ *              VOID    ihx()           lkihx.c
+ *              VOID    s19()           lks19.c
+ *              VOID    lkulist         lklist.c
+ *              int     more()          lklex.c
+ *              VOID    relerr3()       lkrloc3.c
+ *              int     symval()        lksym.c
+ *
+ *      side effects:
+ *              The R and T lines are combined to produce
+ *              relocated code and data.  Output Sxx / Ixx
+ *              and relocated listing files may be produced.
+ *
+ */
+
+VOID
+relr3(void)
+{
+        int mode;
+        a_uint reli, relv;
+        int aindex, rindex, rtp, error, i;
+        a_uint r, rtbase, rtofst, paga = 0, pags = 0;
+        struct areax **a;
+        struct sym **s;
+        int bmagic = 0;
+        int mybank;
+
+        /*
+         * Get area and symbol lists
+         */
+        a = hp->a_list;
+        s = hp->s_list;
+
+        /*
+         * Verify Area Mode
+         */
+        if (eval() != (R3_WORD | R3_AREA) || eval()) {
+                fprintf(stderr, "R input error\n");
+                lkerr++;
+                return;
+        }
+
+        /*
+         * Get area pointer
+         */
+        aindex = (int) evword();
+        if (aindex >= hp->h_narea) {
+                fprintf(stderr, "R area error\n");
+                lkerr++;
+                return;
+        }
+
+        /*
+         * Select Output File
+         */
+        if (oflag != 0) {
+                ap = a[aindex]->a_bap;
+                if (ofp != NULL) {
+                        rtabnk->b_rtaflg = rtaflg;
+                        if (ofp != ap->a_ofp) {
+                                lkflush();
+                        }
+                }
+                ofp = ap->a_ofp;
+                rtabnk = ap->a_bp;
+                rtaflg = rtabnk->b_rtaflg;
+        }
+
+        /*
+         * Base values
+         */
+        rtbase = adb_xb(0, 0);
+        rtofst = a_bytes;
+
+        /*
+         * Relocate address
+         */
+        pc = adb_xb(a[aindex]->a_addr, 0);
+
+        /*
+         * Number of 'bytes' per PC address
+         */
+        pcb = 1;
+        
+        mybank = bankmagic(a[aindex]);
+
+        #if 0
+        printf("area %d base address: 0x%x size: 0x%x rtbase: 0x%x\n", aindex,
+                a[aindex]->a_addr, a[aindex]->a_size, rtbase);
+        #endif
+        /*
+         * Do remaining relocations
+         */
+        while (more()) {
+                error = 0;
+                bmagic = 0;
+                mode = (int) eval();
+
+                if ((mode & R_ESCAPE_MASK) == R_ESCAPE_MASK)
+                {
+                        mode = ((mode & ~R_ESCAPE_MASK) << 8) | eval();
+                        /* printf("unescaping rmode\n"); */
+                }
+
+                rtp = (int) eval();
+                rindex = (int) evword();
+
+                /*
+                 * R3_SYM or R3_AREA references
+                 */
+                if (mode & R3_SYM) {
+                        if (rindex >= hp->h_nsym) {
+                                fprintf(stderr, "R symbol error\n");
+                                lkerr++;
+                                return;
+                        }
+                        reli = symval(s[rindex]);
+                        /* Check if this symbol is magic */
+                        bmagic = bankmagic(s[rindex]->s_axp);
+                }
+/* sdld specific */
+                else if ((IS_R_J11(mode) || IS_R_J19(mode)) && (rindex == 0xFFFF)) {
+                        /* absolute acall/ajmp address */
+                        reli = 0;
+                }
+/* end sdld specific */
+                else {
+                        if (rindex >= hp->h_narea) {
+                                fprintf(stderr, "R area error\n");
+                                lkerr++;
+                                return;
+                        }
+                        reli = a[rindex]->a_addr;
+                }
+
+                /*
+                 * R3_PCR addressing
+                 */
+                if (mode & R3_PCR) {
+                        if (mode & R3_BYTE) {
+                                reli -= (pc + (rtp-rtofst) + 1);
+                        } else {
+                                reli -= (pc + (rtp-rtofst) + 2);
+                        }
+                }
+
+                /*
+                 * R3_PAG0 or R3_PAG addressing
+                 */
+                if (mode & (R3_PAG0 | R3_PAG)) {
+                        paga  = sdp.s_area->a_addr;
+                        pags  = sdp.s_addr;
+                        reli -= paga + pags;
+                }
+
+                /*
+                 * R3_BYTE or R3_WORD operation
+                 */
+                if (mode & R3_BYTE) {
+                        if (mode & R_BYT3)
+                        {
+                                /* This is a three byte address, of which
+                                 * we will select one byte.
+                                 */
+/* sdld specific */
+                                if (mode & R_BIT)
+                                {
+                                        relv = adb_24_bit(reli, rtp);
+                                }
+/* sdld specific */
+                                else if (mode & R_HIB)
+                                {
+                                        /* printf("24 bit address selecting hi byte.\n"); */
+                                        relv = adb_24_hi(reli, rtp);
+                                }
+                                else if (mode & R3_MSB)
+                                {
+                                        /* Note that in 24 bit mode, R3_MSB
+                                         * is really the middle byte, not
+                                         * the most significant byte.
+                                         *
+                                         * This is ugly and I can only apologize
+                                         * for any confusion.
+                                         */
+                                        /* printf("24 bit address selecting middle byte.\n"); */
+                                        relv = adb_24_mid(reli, rtp);
+                                }
+                                else
+                                {
+                                        /* printf("24 bit address selecting lo byte.\n"); */
+                                        relv = adb_24_lo(reli, rtp);
+                                }
+                        }
+                        else if (mode & R3_BYTX) {
+                                /* This is a two byte address, of
+                                 * which we will select one byte.
+                                 */
+                                if (mode & R_BIT) {
+                                        relv = adb_bit(reli, rtp);
+                                } else if (mode & R3_MSB) {
+                                        relv = adb_hi(reli, rtp);
+                                } else {
+                                        relv = adb_lo(reli, rtp);
+                                }
+                        } else {
+                                relv = adb_1b(reli, rtp);
+                        }
+                } else if (IS_R_J11(mode)) {
+                        /*
+                         * JLH: 11 bit jump destination for 8051.
+                         * Forms two byte instruction with
+                         * op-code bits in the MIDDLE!
+                         * rtp points at 3 byte locus:
+                         * first two will get the address,
+                         * third one has raw op-code
+                        */
+
+                        /*
+                         * Calculate absolute destination
+                         * relv must be on same 2K page as pc
+                        */
+                        relv = adb_2b(reli, rtp);
+
+                        if ((relv & ~((a_uint) 0x000007FF)) !=
+                            ((pc + rtp - rtofst) & ~((a_uint) 0x000007FF))) {
+                                        error = 6;
+                        }
+
+                        /*
+                         * Merge MSB with op-code,
+                         * ignoring top 5 bits of address.
+                         * Then hide the op-code.
+                        */
+                        rtval[rtp] = ((rtval[rtp] & 0x07)<<5) | rtval[rtp+2];
+                        rtflg[rtp + 2] = 0;
+                        rtofst += 1;
+                }
+                else if (IS_R_J19(mode)) {
+                        /*
+                         * BK: 19 bit jump destination for DS80C390.
+                         * Forms four byte instruction with
+                         * op-code bits in the MIDDLE!
+                         * rtp points at 4 byte locus:
+                         * first three will get the address,
+                         * fourth one has raw op-code
+                         */
+                        relv = adb_3b(reli, rtp);
+
+                        /*
+                         * Calculate absolute destination
+                         *  relv must be on same 512K page as pc
+                        */
+                        if ((relv & ~((a_uint) 0x0007FFFF)) !=
+                            ((pc + rtp - rtofst) & ~((a_uint) 0x0007FFFF))) {
+                                error = 7;
+                        }
+
+                        /*
+                         * Merge MSB with op-code,
+                         * ignoring top 5 bits of address.
+                         * Then hide the op-code.
+                        */
+                        rtval[rtp] = ((rtval[rtp] & 0x07)<<5) | rtval[rtp+3];
+                        rtflg[rtp + 3] = 0;
+                        rtofst += 1;
+                }
+                else if (IS_C24(mode))
+                {
+                        /*
+                         * 24 bit destination
+                         */
+                        relv = adb_3b(reli, rtp);
+                        }
+                else
+                {
+                        /* 16 bit address. */
+                        if (bmagic)
+                                bankingstub(s[rindex], a[aindex], bmagic, a[aindex]->a_addr + rtbase + rtp - rtofst);
+                        relv = adb_2b(reli, rtp);
+                }
+
+                /*
+                 * R3_BYTE with R3_BYTX offset adjust
+                 */
+                if (mode & R3_BYTE) {
+                        if (mode & R3_BYTX) {
+                                rtofst += (a_bytes - 1);
+                        }
+                }
+
+                /*
+                 * Unsigned Byte Checking
+                 */
+                if (mode & R3_USGN && mode & R3_BYTE && relv & ~((a_uint) 0x000000FF))
+                        error = 1;
+
+                /*
+                 * PCR Relocation Error Checking
+                 */
+                if (mode & R3_PCR && mode & R3_BYTE) {
+                        r = relv & ~0x7F;
+                        if (r != (a_uint) ~0x7F && r != 0)
+                                error = 2;
+                }
+
+                /*
+                 * Page Relocation Error Checking
+                 */
+                if ((TARGET_IS_GB || TARGET_IS_Z80) &&
+                        mode & R3_PAG0 && (relv & ~0xFF || paga || pags))
+                        error = 4;
+                if (mode & R3_PAG  && (relv & ~0xFF))
+                        error = 5;
+/* sdld specific */
+                if ((mode & R_BIT) && (relv & ~0x87FF))
+                        error = 10;
+/* end sdld specific */
+
+                /*
+                 * Error Processing
+                 */
+                if (error) {
+                        rerr.aindex = aindex;
+                        rerr.mode = mode;
+                        rerr.rtbase = rtbase + rtp - rtofst - 1;
+                        rerr.rindex = rindex;
+                        rerr.rval = relv - reli;
+                        relerr3(errmsg3[error]);
+
+                        for (i=rtp; i<rtp+a_bytes; i++) {
+                                if (rtflg[i]) {
+                                        rterr[i] = error;
+                                        break;
+                                }
+                        }
+                }
+        }
+        if (uflag != 0) {
+                lkulist(1);
+        }
+        if (oflag != 0) {
+                lkout(1, mybank);
+        }
+}
+
+char *errmsg3[] = {
+/* 0 */ "LKRLOC3 Error List",
+/* 1 */ "Unsigned Byte error",
+/* 2 */ "Byte PCR relocation error",
+/* 3 */ "",
+/* 4 */ "Page0 relocation error",
+/* 5 */ "Page Mode relocation error",
+/* 6 */ "2K Page relocation error",
+/* 7 */ "512K Page relocation error",
+/* 8 */ "",
+/* 9 */ "",
+/* sdld specific */
+/* 10 */        "Bit-addressable relocation error"
+/* end sdld specific */
+};
+
+
+/*)Function VOID        relp3()
+ *
+ *      The function relp3() evaluates a P line read by
+ *      the linker.  The P line data is combined with the
+ *      previous T line data to set the base page address
+ *      and test the paging boundary and length.
+ *
+ *              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.
+ *
+ *      local variable:
+ *              areax   **a             pointer to array of area pointers
+ *              int aindex              area index
+ *              int mode                relocation mode
+ *              a_uint  relv    relocation value
+ *              int rindex              symbol / area index
+ *              int rtp                 index into T data
+ *              sym **s                 pointer to array of symbol pointers
+ *
+ *      global variables:
+ *              head *hp                pointer to the head structure
+ *              int lkerr               error flag
+ *              sdp sdp                 base page structure
+ *              FILE *stderr    standard error device
+ *
+ *      called functions:
+ *              a_uint adb_2b() lkrloc.c
+ *              a_uint evword() lkrloc.c
+ *              int eval()              lkeval.c
+ *              int fprintf()   c_library
+ *              int more()              lklex.c
+ *              int symval()    lksym.c
+ *
+ *      side effects:
+ *              The P and T lines are combined to set
+ *              the base page address and report any
+ *              paging errors.
+ *
+ */
+
+VOID
+relp3()
+{
+        int aindex, rindex;
+        int mode, rtp;
+        a_uint relv;
+        struct areax **a;
+        struct sym **s;
+
+        /*
+         * Get area and symbol lists
+         */
+        a = hp->a_list;
+        s = hp->s_list;
+
+        /*
+         * Verify Area Mode
+         */
+        if (eval() != (R3_WORD | R3_AREA) || eval()) {
+                fprintf(stderr, "P input error\n");
+                lkerr++;
+        }
+
+        /*
+         * Get area pointer
+         */
+        aindex = (int) evword();
+        if (aindex >= hp->h_narea) {
+                fprintf(stderr, "P area error\n");
+                lkerr++;
+                return;
+        }
+
+        /*
+         * Do remaining relocations
+         */
+        while (more()) {
+                mode = (int) eval();
+                rtp = (int) eval();
+                rindex = (int) evword();
+
+                /*
+                 * R3_SYM or R3_AREA references
+                 */
+                if (mode & R3_SYM) {
+                        if (rindex >= hp->h_nsym) {
+                                fprintf(stderr, "P symbol error\n");
+                                lkerr++;
+                                return;
+                        }
+                        relv = symval(s[rindex]);
+                } else {
+                        if (rindex >= hp->h_narea) {
+                                fprintf(stderr, "P area error\n");
+                                lkerr++;
+                                return;
+                        }
+                        relv = a[rindex]->a_addr;
+                }
+                adb_2b(relv, rtp);
+        }
+
+        /*
+         * Paged values
+         */
+        aindex = (int) adb_2b(0, 2);
+        if (aindex >= hp->h_narea) {
+                fprintf(stderr, "P area error\n");
+                lkerr++;
+                return;
+        }
+        sdp.s_areax = a[aindex];
+        sdp.s_area = sdp.s_areax->a_bap;
+        sdp.s_addr = adb_2b(0, 4);
+        if (sdp.s_area->a_addr & 0xFF || sdp.s_addr & 0xFF)
+                relerp3("Page Definition Boundary Error");
+}
+
+/*)Function VOID        rele3()
+ *
+ *      The function rele3() closes all open output files
+ *      at the end of the linking process.
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              int oflag               output type flag
+ *              int uflag               relocation listing flag
+ *
+ *      called functions:
+ *              VOID    lkfclose()      lkbank.c
+ *              VOID    lkflush()       lkout.c
+ *              VOID    lkulist()       lklist.c
+ *
+ *      side effects:
+ *              All open output files are closed.
+ *
+ */
+
+VOID
+rele3()
+{
+        if (uflag != 0) {
+                lkulist(0);
+        }
+        if (oflag != 0) {
+                lkflush();
+                lkfclose();
+        }
+}
+
+/*)Function VOID        relerr3(str)
+ *
+ *              char    *str            error string
+ *
+ *      The function relerr3() outputs the error string to
+ *      stderr and to the map file (if it is open).
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              FILE    *mfp            handle for the map file
+ *
+ *      called functions:
+ *              VOID    errdmp3()       lkrloc3.c
+ *
+ *      side effects:
+ *              Error message inserted into map file.
+ *
+ */
+
+VOID
+relerr3(char *str)
+{
+        errdmp3(stderr, str);
+        if (mfp)
+                errdmp3(mfp, str);
+}
+
+/*)Function VOID        errdmp3(fptr, str)
+ *
+ *              FILE    *fptr           output file handle
+ *              char    *str            error string
+ *
+ *      The function errdmp3() outputs the error string str
+ *      to the device specified by fptr.  Additional information
+ *      is output about the definition and referencing of
+ *      the symbol / area error.
+ *
+ *      local variable:
+ *              int mode                error mode
+ *              int aindex              area index
+ *              int lkerr               error flag
+ *              int rindex              error index
+ *              sym **s         pointer to array of symbol pointers
+ *              areax   **a             pointer to array of area pointers
+ *              areax   *raxp           error area extension pointer
+ *
+ *      global variables:
+ *              sdp sdp         base page structure
+ *
+ *      called functions:
+ *              int fprintf()   c_library
+ *              VOID    prntval()       lkrloc.c
+ *
+ *      side effects:
+ *              Error reported.
+ *
+ */
+
+const char errdmp3_null_srcname[] = "<missing>";
+
+VOID
+errdmp3(FILE *fptr, char *str)
+{
+        int mode, aindex, rindex;
+        struct sym **s;
+        struct areax **a;
+        struct areax *raxp;
+
+        a = hp->a_list;
+        s = hp->s_list;
+
+        mode = rerr.mode;
+        aindex = rerr.aindex;
+        rindex = rerr.rindex;
+
+        /*
+         * Print Error
+         */
+        fprintf(fptr, "\n?ASlink-Warning-%s", str);
+        lkerr++;
+
+        /*
+         * Print symbol if symbol based
+         */
+        if (mode & R3_SYM) {
+                fprintf(fptr, " for symbol  %s\n",
+                        &s[rindex]->s_id[0]);
+        } else {
+                fprintf(fptr, "\n");
+        }
+
+        /*
+         * Print Ref Info
+         */
+/*         11111111112222222222333333333344444444445555555555666666666677777*/
+/*12345678901234567890123456789012345678901234567890123456789012345678901234*/
+/*        |                 |                 |                 |           */
+        fprintf(fptr,
+"         file              module            area              offset\n");
+        fprintf(fptr,
+"  Refby  %-14.14s    %-14.14s    %-14.14s    ",
+                        (hp->h_lfile && hp->h_lfile->f_idp) ? hp->h_lfile->f_idp : errdmp3_null_srcname,
+                        &hp->m_id[0],
+                        &a[aindex]->a_bap->a_id[0]);
+        prntval(fptr, rerr.rtbase);
+
+        /*
+         * Print Def Info
+         */
+        if (mode & R3_SYM) {
+                raxp = s[rindex]->s_axp;
+        } else {
+                raxp = a[rindex];
+        }
+/*         11111111112222222222333333333344444444445555555555666666666677777*/
+/*12345678901234567890123456789012345678901234567890123456789012345678901234*/
+/*        |                 |                 |                 |           */
+        fprintf(fptr,
+"  Defin  %-14.14s    %-14.14s    %-14.14s    ",
+                        (raxp->a_bhp->h_lfile && raxp->a_bhp->h_lfile->f_idp) ? raxp->a_bhp->h_lfile->f_idp : errdmp3_null_srcname,
+                        &raxp->a_bhp->m_id[0],
+                        &raxp->a_bap->a_id[0]);
+        if (mode & R3_SYM) {
+                prntval(fptr, s[rindex]->s_addr);
+        } else {
+                prntval(fptr, rerr.rval);
+        }
+}
+
+/*)Function VOID        relerp3(str)
+ *
+ *              char    *str            error string
+ *
+ *      The function relerp3() outputs the paging error string to
+ *      stderr and to the map file (if it is open).
+ *
+ *      local variable:
+ *              none
+ *
+ *      global variables:
+ *              FILE    *mfp            handle for the map file
+ *
+ *      called functions:
+ *              VOID    erpdmp3()       lkrloc3.c
+ *
+ *      side effects:
+ *              Error message inserted into map file.
+ *
+ */
+
+VOID
+relerp3(char *str)
+{
+        erpdmp3(stderr, str);
+        if (mfp)
+                erpdmp3(mfp, str);
+}
+
+/*)Function VOID        erpdmp3(fptr, str)
+ *
+ *              FILE    *fptr           output file handle
+ *              char    *str            error string
+ *
+ *      The function erpdmp3() outputs the error string str
+ *      to the device specified by fptr.
+ *
+ *      local variable:
+ *              head    *thp            pointer to head structure
+ *
+ *      global variables:
+ *              int             lkerr           error flag
+ *              sdp             sdp                     base page structure
+ *
+ *      called functions:
+ *              int fprintf()           c_library
+ *              VOID    prntval()       lkrloc.c
+ *
+ *      side effects:
+ *              Error reported.
+ *
+ */
+
+VOID
+erpdmp3(FILE *fptr, char *str)
+{
+        struct head *thp;
+
+        thp = sdp.s_areax->a_bhp;
+
+        /*
+         * Print Error
+         */
+        fprintf(fptr, "\n?ASlink-Warning-%s\n", str);
+        lkerr++;
+
+        /*
+         * Print PgDef Info
+         */
+/*         111111111122222222223333333333444444444455555555556666666666777*/
+/*123456789012345678901234567890123456789012345678901234567890123456789012*/
+        fprintf(fptr,
+"         file              module            pgarea            pgoffset\n");
+        fprintf(fptr,
+"  PgDef  %-14.14s    %-14.14s    %-14.14s    ",
+                        thp->h_lfile->f_idp,
+                        &thp->m_id[0],
+                        &sdp.s_area->a_id[0]);
+        prntval(fptr, sdp.s_area->a_addr + sdp.s_addr);
+}
+
+/* sdld specific */
+/*)Function a_uint              adb_bit(v, i)
+ *
+ *              a_uint v        value to add to byte
+ *              int i           rtval[] index
+ *
+ *      The function adb_bit() converts the single
+ *      byte address value contained in rtval[i] to bit-
+ *      addressable space and adds the value of v to it.
+ *      The new value of rtval[i] is returned.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              none
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_bit(a_uint v, int i)
+{
+        a_uint j;
+
+        j = adb_lo(v, i) & 0xFF;
+        if ((j >= 0x20) && (j <= 0x2F)) {
+                j = (j - 0x20) * 8;
+        } else if ((j < 0x80) || ((j & 0x07) != 0)) {
+                return(0x100);//error
+        }
+
+        if (hilo) {
+                j = rtval[i+1] = j + (rtval[i] & 0x07);
+        } else {
+                j = rtval[i] = j + (rtval[i+1] & 0x07);
+        }
+        return(j);
+}
+/* end sdld specific */
+
+/*)Function     a_uint  adb_lo(v, i)
+ *
+ *              int     v               value to add to byte
+ *              int     i               rtval[] index
+ *
+ *      The function adb_lo() adds the value of v to the
+ *      value contained in rtval[i] through rtval[i + a_bytes - 1].
+ *      The new value of rtval[i] ... is returned.
+ *      The rtflg[] flags are cleared for all rtval[i] ... except
+ *      the LSB.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The value of rtval[] is changed.
+ *              The rtflg[] values corresponding to all bytes
+ *              except the LSB of the value are cleared to reflect
+ *              the fact that the LSB is the selected byte.
+ *
+ */
+
+a_uint
+adb_lo(v, i)
+a_uint  v;
+int     i;
+{
+        a_uint j;
+        int m, n;
+
+        j = adb_xb(v, i);
+        /*
+         * LSB is lowest order byte of data
+         */
+        m = (hilo ? a_bytes-1 : 0);
+        for (n=0; n<a_bytes; n++) {
+                if(n != m) rtflg[i+n] = 0;
+        }
+        return (j);
+}
+
+/*)Function     a_uint  adb_hi(v, i)
+ *
+ *              int     v               value to add to byte
+ *              int     i               rtval[] index
+ *
+ *      The function adb_hi() adds the value of v to the
+ *      value contained in rtval[i] through rtval[i + a_bytes - 1].
+ *      The new value of rtval[i] .... is returned.
+ *      The LSB rtflg[] is cleared.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The value of rtval[] is changed.
+ *              The rtflg[] values corresponding to all bytes
+ *              except the 2nd byte (MSB) are cleared to reflect
+ *              the fact that the MSB is the selected byte.
+ *
+ */
+
+a_uint
+adb_hi(v, i)
+a_uint  v;
+int     i;
+{
+        a_uint j;
+        int m, n;
+
+        j = adb_xb(v, i);
+        /*
+         * MSB is next lowest order byte of data
+         */
+        m = (hilo ? a_bytes-2 : 1);
+        for (n=0; n<a_bytes; n++) {
+                if(n != m) rtflg[i+n] = 0;
+        }
+        return (j);
+}
+
+/* sdld specific */
+/*)Function a_uint              adb_24_bit(v, i)
+ *
+ *              a_uint v        value to add to byte
+ *              int i           rtval[] index
+ *
+ *      The function adb_24_bit() converts the single
+ *      byte address value contained in rtval[i] to bit-
+ *      addressable space and adds the value of v to it.
+ *      The new value of rtval[i] is returned.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              none
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_24_bit(v, i)
+a_uint v;
+int i;
+{
+        a_uint j;
+
+        j = adb_24_lo(v, i) & 0xFF;
+        if ((j >= 0x20) && (j <= 0x2F)) {
+                j = (j - 0x20) * 8;
+        } else if ((j < 0x80) || ((j & 0x07) != 0)) {
+                return(0x100);//error
+        }
+
+        if (hilo) {
+                j = rtval[i+2] = j + (rtval[i+1] & 0x07);
+        } else {
+                j = rtval[i] = j + (rtval[i+1] & 0x07);
+        }
+        return(j);
+}
+
+/*)Function a_uint              adb_24_hi(v, i)
+ *
+ *              a_uint v        value to add to byte
+ *              int i           rtval[] index
+ *
+ *      The function adb_24_hi() adds the value of v to the
+ *      24 bit value contained in rtval[i] - rtval[i+2].
+ *      The new value of rtval[i] / rtval[i+1] is returned.
+ *      The LSB & middle byte rtflg[] is cleared.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The value of rtval[] is changed.
+ *              The rtflg[] value corresponding to the
+ *              LSB & middle byte of the word value is cleared to
+ *              reflect the fact that the MSB is the selected byte.
+ *
+ */
+
+a_uint
+adb_24_hi(v, i)
+a_uint v;
+int i;
+{
+        a_uint j;
+
+        j = adb_3b(v, i);
+
+        /* Remove the lower two bytes. */
+        if (hilo)
+        {
+                rtflg[i+2] = 0;
+        }
+        else
+        {
+                rtflg[i] = 0;
+        }
+        rtflg[i+1] = 0;
+
+        return (j);
+}
+
+/*)Function a_uint              adb_24_mid(v, i)
+ *
+ *              a_uint v        value to add to byte
+ *              int i           rtval[] index
+ *
+ *      The function adb_24_mid() adds the value of v to the
+ *      24 bit value contained in rtval[i] - rtval[i+2].
+ *      The new value of rtval[i] / rtval[i+1] is returned.
+ *      The LSB & MSB byte rtflg[] is cleared.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The value of rtval[] is changed.
+ *              The rtflg[] value corresponding to the
+ *              LSB & MSB of the 24 bit value is cleared to reflect
+ *              the fact that the middle byte is the selected byte.
+ *
+ */
+
+a_uint
+adb_24_mid(v, i)
+a_uint v;
+int i;
+{
+        a_uint j;
+
+        j = adb_3b(v, i);
+
+        /* remove the MSB & LSB. */
+        rtflg[i+2] = 0;
+        rtflg[i] = 0;
+
+        return (j);
+}
+
+/*)Function a_uint              adb_24_lo(v, i)
+ *
+ *              a_uint v        value to add to byte
+ *              int i           rtval[] index
+ *
+ *      The function adb_24_lo() adds the value of v to the
+ *      24 bit value contained in rtval[i] - rtval[i+2].
+ *      The new value of rtval[i] / rtval[i+1] is returned.
+ *      The MSB & middle byte rtflg[] is cleared.
+ *
+ *      local variable:
+ *              a_uint  j               temporary evaluation variable
+ *
+ *      global variables:
+ *              hilo                    byte ordering parameter
+ *
+ *      called functions:
+ *              none
+ *
+ *      side effects:
+ *              The value of rtval[] is changed.
+ *              The rtflg[] value corresponding to the
+ *              MSB & middle byte  of the word value is cleared to
+ *              reflect the fact that the LSB is the selected byte.
+ *
+ */
+
+a_uint
+adb_24_lo(v, i)
+a_uint v;
+int i;
+{
+        a_uint j;
+
+        j = adb_3b(v, i);
+
+        /* Remove the upper two bytes. */
+        if (hilo)
+        {
+                rtflg[i] = 0;
+        }
+        else
+        {
+                rtflg[i+2] = 0;
+        }
+        rtflg[i+1] = 0;
+
+        return (j);
+}
+
+/* end sdld specific */
diff --git a/Kernel/tools/bankld/lks19.c b/Kernel/tools/bankld/lks19.c
new file mode 100644 (file)
index 0000000..517fc2d
--- /dev/null
@@ -0,0 +1,226 @@
+/* lks19.c
+
+   Copyright (C) 1989-1998 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+#include "sdld.h"
+#include "aslink.h"
+
+/*)Module       lks19.c
+ *
+ *      The module lks19.c contains the functions to
+ *      output the relocated object code in the
+ *      Motorola S19 format.
+ *
+ *      lks19.c contains the following functions:
+ *              VOID    s19()
+ *              VOID    sflush()
+ *
+ *      lks19.c contains no local variables.
+ */
+
+/*)S19 Format
+ *      Record Type Field    -  This  field  signifies  the  start  of a
+ *                              record and  identifies  the  the  record
+ *                              type as follows:
+ *
+ *                                  Ascii S1 - Data Record
+ *                                  Ascii S9 - End of File Record
+ *
+ *      Record Length Field  -  This  field  specifies the record length
+ *                              which includes the  address,  data,  and
+ *                              checksum   fields.   The  8  bit  record
+ *                              length value is converted to  two  ascii
+ *                              characters, high digit first.
+ *
+ *      Load Address Field   -  This  field  consists  of the four ascii
+ *                              characters which result from  converting
+ *                              the  the  binary value of the address in
+ *                              which to begin loading this record.  The
+ *                              order is as follows:
+ *
+ *                                  High digit of high byte of address.
+ *                                  Low digit of high byte of address.
+ *                                  High digit of low byte of address.
+ *                                  Low digit of low byte of address.
+ *
+ *                              In an End of File record this field con-
+ *                              sists of either four ascii zeros or  the
+ *                              program  entry  address.   Currently the
+ *                              entry address option is not supported.
+ *
+ *      Data Field           -  This  field consists of the actual data,
+ *                              converted to two ascii characters,  high
+ *                              digit first.  There are no data bytes in
+ *                              the End of File record.
+ *
+ *      Checksum Field       -  The  checksum  field is the 8 bit binary
+ *                              sum of the record length field, the load
+ *                              address field, and the data field.  This
+ *                              sum is then  complemented  (1's  comple-
+ *                              ment)   and   converted   to  two  ascii
+ *                              characters, high digit first.
+ */
+
+/*)Function     s19(i)
+ *
+ *              int     i               0 - process data
+ *                                      1 - end of data
+ *
+ *      The function s19() loads the output buffer with
+ *      the relocated data.
+ *
+ *      local variables:
+ *              a_uint  j               temporary
+ *
+ *      global variables:
+ *              int     hilo            byte order
+ *              FILE *  ofp             output file handle
+ *              int     rtcnt           count of data words
+ *              int     rtflg[]         output the data flag
+ *              a_uint  rtval[]         relocated data
+ *              char    rtbuf[]         output buffer
+ *              a_uint  rtadr0          address temporary
+ *              a_uint  rtadr1          address temporary
+ *              a_uint  rtadr2          address temporary
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID    sflush()        lks19.c
+ *
+ *      side effects:
+ *              The data is placed into the output buffer.
+ */
+
+/*
+ * The maximum number of Data Field bytes is NMAX less:
+ *      2       Record Type Field
+ *      2       Record Length Field
+ *      4       Load Address Field
+ *      2       Checksum Field
+ *
+ *      Divided by 2 (2 characters per byte)
+ */
+
+#define MAXBYTES        ((NMAX - 10)/2)
+
+VOID
+s19(int i)
+{
+        a_uint j;
+        int k;
+
+        if (i) {
+                if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD)
+                        return;
+
+                if (hilo == 0) {
+                        j = rtval[0];
+                        rtval[0] = rtval[1];
+                        rtval[1] = j;
+                }
+                rtadr2 = rtval[0] << 8 | rtval[1];
+                if (rtadr2 != rtadr1) {
+                        /*
+                         * data bytes not contiguous between records
+                         */
+                        sflush();
+                        rtadr0 = rtadr1 = rtadr2;
+                }
+                for (k=2; k<rtcnt; k++) {
+                        if (rtflg[k]) {
+                                rtbuf[rtadr1++ - rtadr0] = rtval[k];
+                                if (rtadr1 - rtadr0 == MAXBYTES) {
+                                        sflush();
+                                }
+                        }
+                }
+        } else {
+                sflush();
+                fprintf(ofp, "S9030000FC\n");
+        }
+}
+
+/*)Function     sflush()
+ *
+ *      The function sflush() outputs the relocated data
+ *      in the standard Motorola S19 format.
+ *
+ *      local variables:
+ *              a_uint  chksum          byte checksum
+ *              int     i               loop counter
+ *              int     max             number of data bytes
+ *              int     reclen          record length
+ *
+ *      global variables:
+ *              FILE *  ofp             output file handle
+ *              char    rtbuf[]         output buffer
+ *              a_uint  rtadr0          address temporary
+ *              a_uint  rtadr1          address temporary
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *
+ *      side effects:
+ *              The data is output to the file defined by ofp.
+ */
+
+/*
+ * Written by G. Osborn, gary@s-4.com, 6-17-98.
+ * The new version concatenates the assembler
+ * output records when they represent contiguous
+ * memory segments to produces NMAX character
+ * S-19 output lines whenever possible, resulting
+ * in a substantial reduction in file size.
+ * More importantly, the download time
+ * to the target system is much improved.
+ */
+
+VOID
+sflush()
+{
+        a_uint chksum;
+        a_uint i, max, reclen;
+
+        max = rtadr1 - rtadr0;
+        if (max == 0) {
+                return;
+        }
+
+        /*
+         * Only the "S1" and the checksum itself are excluded
+         * from the checksum.  The record length does not
+         * include "S1" and the pair count.  It does
+         * include the two address bytes, the data bytes,
+         * and the checksum.
+         */
+        reclen = max + 3;
+        chksum = reclen;
+        chksum += rtadr0;
+        chksum += rtadr0 >> 8;
+        fprintf(ofp, "S1%02X%04X", reclen, rtadr0);
+        for (i=0; i<max; i++) {
+                chksum += rtbuf[i];
+                fprintf(ofp, "%02X", rtbuf[i] & 0x00ff);
+        }
+        /*
+         * 1's complement
+         */
+        fprintf(ofp, "%02X\n", (~chksum) & 0x00ff);
+        rtadr0 = rtadr1;
+}
diff --git a/Kernel/tools/bankld/lksdcclib.c b/Kernel/tools/bankld/lksdcclib.c
new file mode 100644 (file)
index 0000000..7f0c687
--- /dev/null
@@ -0,0 +1,405 @@
+/* lksdcclib.c - sdcc library format handling
+
+   Copyright (C) 1989-1995 Alan R. Baldwin
+   721 Berkeley St., Kent, Ohio 44240
+   Copyright (C) 2008 Borut Razem, borut dot razem at siol dot net
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "sdld.h"
+#include "lk_readnl.h"
+#include "aslink.h"
+#include "lklibr.h"
+#include "lkrel.h"
+
+#define EQ(A,B) !strcmp((A),(B))
+#define MAXLINE 254             /* when using lk_readnl */
+
+
+static int
+is_sdcclib (FILE * libfp)
+{
+#define SDCCLIB_MAGIC "<SDCCLIB>"
+#define SDCCLIB_MAGIC_LEN (sizeof ("<SDCCLIB>") - 1)
+
+  char buf[SDCCLIB_MAGIC_LEN];
+
+  if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, SDCCLIB_MAGIC, SDCCLIB_MAGIC_LEN) == 0)
+    {
+      switch (getc (libfp))
+        {
+        case '\r':
+          if (getc (libfp) == '\n')
+            return 1;
+
+        case '\n':
+          return 1;
+        }
+    }
+  rewind (libfp);
+  return 0;
+}
+
+/* Load a .rel file embedded in a sdcclib file */
+static int
+LoadRel (char *libfname, FILE * libfp, char *ModName)
+{
+  char str[NINPUT];
+  int state = 0;
+
+  while (lk_readnl (str, sizeof (str), libfp) != NULL)
+    {
+      switch (state)
+        {
+        case 0:
+          if (EQ (str, "<FILE>"))
+            {
+              if (NULL != lk_readnl (str, sizeof (str), libfp) && EQ (str, ModName))
+                state = 1;
+              else
+                return 0;
+            }
+          else
+            return 0;
+          break;
+
+        case 1:
+          return EQ (str, "<REL>") ? load_rel (libfp, -1) : 0;
+        }
+    }
+
+  return 0;
+}
+
+#ifdef INDEXLIB
+static pmlibraryfile
+buildlibraryindex_sdcclib (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
+{
+  char FLine[MAXLINE];
+  int state = 0;
+  long IndexOffset = 0;
+  pmlibrarysymbol ThisSym = NULL;
+
+  while (lk_readnl (FLine, sizeof (FLine), libfp))
+    {
+      switch (state)
+        {
+        case 0:
+          if (EQ (FLine, "<INDEX>"))
+            {
+              /*The next line has the size of the index */
+              lk_readnl (FLine, sizeof (FLine), libfp);
+              IndexOffset = atol (FLine);
+              state = 1;
+            }
+          break;
+
+        case 1:
+          if (EQ (FLine, "<MODULE>"))
+            {
+              char buff[PATH_MAX];
+              char ModName[NCPS] = "";
+              long FileOffset;
+
+              /* The next line has the name of the module and the offset
+                 of the corresponding embedded file in the library */
+              lk_readnl (FLine, sizeof (FLine), libfp);
+              sscanf (FLine, "%s %ld", ModName, &FileOffset);
+              state = 2;
+
+              /* Create a new libraryfile object for this module */
+              if (libr == NULL)
+                {
+                  libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+                }
+              else
+                {
+                  This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+                  This = This->next;
+                }
+              This->next = NULL;
+              This->loaded = -1;
+              This->offset = FileOffset + IndexOffset;
+              This->libspc = lbnh->libspc;
+              This->relfil = strdup (ModName);
+              sprintf (buff, "%s%s%c%s", lbnh->path, ModName, FSEPX, LKOBJEXT);
+              This->filspc = strdup (buff);
+              This->type = type;
+
+              This->symbols = ThisSym = NULL;   /* Start a new linked list of symbols */
+            }
+          else if (EQ (FLine, "</INDEX>"))
+            {
+              return This;      /* Finish, get out of here */
+            }
+          break;
+
+        case 2:
+          if (EQ (FLine, "</MODULE>"))
+            {
+              This->loaded = 0;
+              /* Create the index for the next module */
+              state = 1;
+            }
+          else
+            {
+              /* Add the symbols */
+              if (ThisSym == NULL)      /* First symbol of the current module */
+                {
+                  ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+                }
+              else
+                {
+                  ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+                  ThisSym = ThisSym->next;
+                }
+              ThisSym->next = NULL;
+              ThisSym->name = strdup (FLine);
+            }
+          break;
+
+        default:
+          return This;          /* State machine should never reach this point, but just in case... */
+          break;
+        }
+    }
+
+  return This;                  /* State machine should never reach this point, but just in case... */
+}
+
+#else
+
+/* Load an .adb file embedded in a sdcclib file. If there is
+something between <ADB> and </ADB> returns 1, otherwise returns 0.
+This way the aomf51 will not have useless empty modules. */
+
+static int
+LoadAdb (FILE * libfp)
+{
+  char str[MAXLINE];
+  int state = 0;
+  int ret = 0;
+
+  while (lk_readnl (str, sizeof (str), libfp) != NULL)
+    {
+      switch (state)
+        {
+        case 0:
+          if (EQ (str, "<ADB>"))
+            state = 1;
+          break;
+
+        case 1:
+          if (EQ (str, "</ADB>"))
+            return ret;
+          fprintf (yfp, "%s\n", str);
+          ret = 1;
+          break;
+        }
+    }
+  return ret;
+}
+
+/* Check for a symbol in a SDCC library. If found, add the embedded .rel and
+   .adb files from the library.  The library must be created with the SDCC
+   librarian 'sdcclib' since the linking process depends on the correct file offsets
+   embedded in the library file. */
+
+static int
+findsym_sdcclib (const char *name, struct lbname *lbnh, FILE * libfp, int type)
+{
+  struct lbfile *lbfh;
+  char ModName[NCPS] = "";
+  char FLine[MAXLINE];
+  int state = 0;
+  long IndexOffset = 0, FileOffset;
+
+  while (lk_readnl (FLine, sizeof (FLine), libfp))
+    {
+      char filspc[PATH_MAX];
+
+      if (lbnh->path != NULL)
+        {
+          strcpy (filspc, lbnh->path);
+#ifdef  OTHERSYSTEM
+          if (*filspc != '\0' && (filspc[strlen (filspc) - 1] != '/') && (filspc[strlen (filspc) - 1] != LKDIRSEP))
+            {
+              strcat (filspc, LKDIRSEPSTR);
+            }
+#endif
+        }
+
+      switch (state)
+        {
+        case 0:
+          if (EQ (FLine, "<INDEX>"))
+            {
+              /* The next line has the size of the index */
+              lk_readnl (FLine, sizeof (FLine), libfp);
+              IndexOffset = atol (FLine);
+              state = 1;
+            }
+          break;
+
+        case 1:
+          if (EQ (FLine, "<MODULE>"))
+            {
+              /* The next line has the name of the module and the offset
+                 of the corresponding embedded file in the library */
+              lk_readnl (FLine, sizeof (FLine), libfp);
+              sscanf (FLine, "%s %ld", ModName, &FileOffset);
+              state = 2;
+            }
+          else if (EQ (FLine, "</INDEX>"))
+            {
+              /* Reached the end of the index.  The symbol is not in this library. */
+              return 0;
+            }
+          break;
+
+        case 2:
+          if (EQ (FLine, "</MODULE>"))
+            {
+              /* The symbol is not in this module, try the next one */
+              state = 1;
+            }
+          else
+            {
+              /* Check if this is the symbol we are looking for. */
+              if (strncmp (name, FLine, NCPS) == 0)
+                {
+                  /* The symbol is in this module. */
+
+                  /* As in the original library format, it is assumed that the .rel
+                     files reside in the same directory as the lib files. */
+                  sprintf (&filspc[strlen (filspc)], "%s%c%s", ModName, FSEPX, LKOBJEXT);
+
+                  /* If this module has been loaded already don't load it again. */
+                  if (is_module_loaded (filspc))
+                    return 1;
+
+                  /* Add the embedded file to the list of files to be loaded in
+                     the second pass.  That is performed latter by the function
+                     library() below. */
+                  lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+                  if (lbfhead == NULL)
+                    {
+                      lbfhead = lbfh;
+                    }
+                  else
+                    {
+                      struct lbfile *lbf;
+
+                      for (lbf = lbfhead; lbf->next; lbf = lbf->next)
+                        ;
+
+                      lbf->next = lbfh;
+                    }
+
+                  lbfh->libspc = lbnh->libspc;
+                  lbfh->filspc = strdup (filspc);
+                  lbfh->relfil = strdup (ModName);
+                  lbfh->f_obj = lbnh->f_obj;
+                  /* Library embedded file, so lbfh->offset must be >=0 */
+                  lbfh->offset = IndexOffset + FileOffset;
+                  obj_flag = lbfh->f_obj;
+
+                  /* Jump to where the .rel begins and load it. */
+                  fseek (libfp, lbfh->offset, SEEK_SET);
+                  if (!LoadRel (lbnh->libspc, libfp, ModName))
+                    {
+                      fclose (libfp);
+                      fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, ModName);
+                      lkexit (1);
+                    }
+                  /* if cdb information required & .adb file present */
+                  if (yflag && yfp)
+                    {
+                      if (LoadAdb (libfp))
+                        SaveLinkedFilePath (filspc);
+                    }
+                  return 1;     /* Found the symbol, so success! */
+                }
+            }
+          break;
+
+        default:
+          return 0;             /* It should never reach this point, but just in case... */
+          break;
+        }
+    }
+
+  return 0;                     /* The symbol is not in this library */
+}
+
+#endif
+
+static void
+loadfile_sdcclib (struct lbfile *lbfh)
+{
+  FILE *fp;
+  int res;
+
+#ifdef __CYGWIN__
+  char posix_path[PATH_MAX];
+  void cygwin_conv_to_full_posix_path (char *win_path, char *posix_path);
+  cygwin_conv_to_full_posix_path (lbfh->libspc, posix_path);
+  fp = fopen (posix_path, "rb");
+#else
+  fp = fopen (lbfh->libspc, "rb");
+#endif
+
+  if (fp != NULL)
+    {
+      fseek (fp, lbfh->offset, SEEK_SET);
+      res = LoadRel (lbfh->libspc, fp, lbfh->relfil);
+      fclose (fp);
+
+      if (!res)
+        {
+          fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, lbfh->relfil);
+          lkexit (1);
+        }
+    }
+  else
+    {
+      fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->libspc);
+      lkexit (1);
+    }
+}
+
+struct aslib_target aslib_target_sdcclib = {
+  &is_sdcclib,
+#ifdef INDEXLIB
+  &buildlibraryindex_sdcclib,
+#else
+  &findsym_sdcclib,
+#endif
+  &loadfile_sdcclib,
+};
diff --git a/Kernel/tools/bankld/lksdcdb.c b/Kernel/tools/bankld/lksdcdb.c
new file mode 100644 (file)
index 0000000..b2f3b83
--- /dev/null
@@ -0,0 +1,179 @@
+/* lksdcdb.c */
+
+/*
+ *  Copyright (C) 2001-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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ */
+
+#include "aslink.h"
+
+#if SDCDB
+
+/*Module       lkcdb.c
+ *
+ *     The module lkcdb.c contains the functions
+ *     required to create a SDCDB debug file.
+ *
+ *     lksdcdb.c contains the following functions:
+ *             VOID    SDCDBfopen()
+ *             VOID    SDCDBcopy()
+ *             VOID    DefineSDCDB()
+ */
+
+/*)Function    VOID    SDCDBfopen()
+ * 
+ *     The function SDCDBfopen() opens the SDCDB output file
+ *     and sets the map flag, mflag, to create a map file.
+ *     SDCDB processing is performed during map generation.
+ *
+ *     local variables:
+ *             none
+ *
+ *     global variables:
+ *             int     yflag           SDCDB Debug flag
+ *             FILE *  yfp             SDCDB Debug File handle
+ *             struct lfile *linkp     Pointer to the Linker output file name
+ *             int     mflag           Map output flag
+ *
+ *     functions called:
+ *             FILE *  afile()         lkmain.c
+ *             VOID    lkexit()        lkmain.c
+ *
+ *     side effects:
+ *             The SDCDB output file is opened.
+ *             Failure to open the file will
+ *             terminate the linker.
+ */
+
+VOID SDCDBfopen(void)
+{
+       if (yflag) {
+               SaveLinkedFilePath(linkp->f_idp);       //Must be the first one...
+               yfp = afile(linkp->f_idp, "cdb", 1);
+               if (yfp == NULL) {
+                       lkexit(1);
+               }
+               mflag = 1;
+       }
+}
+
+
+/*)Function    VOID    SDCDBcopy()
+ * 
+ *             char *  str             pointer to the file spec
+ *
+ *     The function SDCDBcopy() copies an existing adb file
+ *     into the linker cdb file.
+ *
+ *     The function is called from lklex.c and lklibr.c
+ *
+ *     local variables:
+ *             FILE *  xfp             file handle
+ *             char    line[]          line from file
+ *
+ *     global variables:
+ *             int     yflag           SDCDB Debug flag
+ *             FILE *  yfp             SDCDB Debug File handle
+ *
+ *     functions called:
+ *             FILE *  afile()         lkmain.c
+ *             int     fgets()         c_library
+ *             int     fprintf()       c_library
+ *             int     fclose()        c_library
+ *
+ *     side effects:
+ *             SDCDB cdb file is copied into
+ *             the linker cdb output file.
+ */
+
+VOID SDCDBcopy(char * str)
+{
+       FILE * xfp;
+
+       /*
+        * Copy .adb file if present and requested.
+        */
+       if (yflag && yfp) {
+               xfp = afile(str, "adb", 0); //JCF: Nov 30, 2002
+               if (xfp) {
+                       copyfile(yfp, xfp);
+                       fclose(xfp);
+               }
+       }
+}
+
+
+/*)Function    VOID    DefineSDCDB()
+ * 
+ *             char *  name            pointer to the symbol string
+ *             a_uint  value           value of symbol
+ *
+ *     The function DefineSDCDB() processes the symbols into
+ *     SDCDB commands for inclusion in the SDCDB output file.
+ *
+ *     The function is called from lstarea in lklist.c
+ *     for each symbol.
+ *
+ *     local variables:
+ *             int     j               argument count
+ *             char *  p1              temporary string pointer
+ *
+ *     global variables:
+ *             FILE *  yfp             SDCDB Debug File handle
+ *
+ *     functions called:
+ *             int     fprintf()       c_library
+ *             int     strchr()        c_library
+ *
+ *     side effects:
+ *             SDCDB debug symbols are placed
+ *             into the output file.
+ */
+
+VOID DefineSDCDB(char *name, a_uint value)
+{
+       int  j;
+       char *p1;
+
+       /* no output if file is not open */
+       if (yfp == NULL) return;
+
+       /*
+        * SDCC symbols have 3 or more $ characters
+        */
+       j = 0;
+       p1 = name;
+       while ((p1 = strchr(p1, '$')) != NULL) {
+               p1++;
+               j += 1;
+       }
+
+       if (j > 2) {
+#ifdef LONGINT
+               fprintf(yfp, "L:%s:%lX\n", name ,value);
+#else
+               fprintf(yfp, "L:%s:%X\n", name ,value);
+#endif
+       }
+
+}
+
+#endif
+
diff --git a/Kernel/tools/bankld/lksym.c b/Kernel/tools/bankld/lksym.c
new file mode 100644 (file)
index 0000000..e389f4e
--- /dev/null
@@ -0,0 +1,757 @@
+/* lksym.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 <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio  44240
+ *
+ *   With enhancements from
+ *      John L. Hartman (JLH)
+ *      jhartman@compuserve.com
+ *
+ */
+
+#include "aslink.h"
+
+/*)Module       lksym.c
+ *
+ *      The module lksym.c contains the functions that operate
+ *      on the symbol structures.
+ *
+ *      lksym.c contains the following functions:
+ *              int     hash()
+ *              sym *   lkpsym()
+ *              char *  new()
+ *              sym *   newsym()
+ *              char *  strsto()
+ *              VOID    symdef()
+ *              int     symeq()
+ *              VOID    syminit()
+ *              VOID    symmod()
+ *              a_uint  symval()
+ *
+ *      lksym.c contains the static variables:
+ *              char *  pnext
+ *              int     bytes
+ *      used by the string store function.
+ */
+
+/*)Function     VOID    syminit()
+ *
+ *      The function syminit() is called to clear the hashtable.
+ *
+ *      local variables:
+ *              sym **  spp             pointer to an array of
+ *                                      sym structure pointers
+ *
+ *      global variables:
+ *              sym * symhash[]         array of pointers to NHASH
+ *                                      linked symbol lists
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              (1)     The symbol hash tables are cleared
+ */
+
+VOID
+syminit(void)
+{
+        struct sym **spp;
+
+        spp = &symhash[0];
+        while (spp < &symhash[NHASH])
+                *spp++ = NULL;
+}
+
+/*)Function     sym *   newsym()
+ *
+ *      The function newsym() is called to evaluate the symbol
+ *      definition/reference directive from the .rel file(s).
+ *      If the symbol is not found in the symbol table a new
+ *      symbol structure is created.  Evaluation of the
+ *      directive determines if this is a reference or a definition.
+ *      Multiple definitions of the same variable will be flagged
+ *      as an error if the values are not identical.  A symbol
+ *      definition places the symbol value and area extension
+ *      into the symbols data structure.  And finally, a pointer
+ *      to the symbol structure is placed into the head structure
+ *      symbol list.  Refer to the description of the header, symbol,
+ *      area, and areax structures in lkdata.c for structure and
+ *      linkage details.
+ *
+ *      local variables:
+ *              int     c               character from input text
+ *              int     i               evaluation value
+ *              char    id[]            symbol name
+ *              int     nglob           number of symbols in this header
+ *              sym *   tsp             pointer to symbol structure
+ *              sym **  s               list of pointers to symbol structures
+ *
+ *      global variables:
+ *              areax   *axp            Pointer to the current
+ *                                      areax structure
+ *              head    *headp          The pointer to the first
+ *                                      head structure of a linked list
+ *              int     lkerr           error flag
+ *
+ *      functions called:
+ *              a_uint  eval()          lkeval.c
+ *              VOID    exit()          c_library
+ *              int     fprintf()       c_library
+ *              char    getSid()        lklex.c
+ *              int     get()           lklex.c
+ *              int     getnb()         lklex.c
+ *              sym *   lkpsym()        lksym.c
+ *
+ *      side effects:
+ *              A symbol structure is created and/or modified.
+ *              If structure space allocation fails linker will abort.
+ *              Several severe errors (these are internal errors
+ *              indicating a corrupted .rel file or corrupted
+ *              assembler or linker) will terminated the linker.
+ */
+
+/*
+ * Find/Create a global symbol entry.
+ *
+ * S xxxxxx Defnnnn
+ *   |      |  |
+ *   |      |  `-- sp->s_addr
+ *   |      `----- sp->s_type
+ *   `------------ sp->s_id
+ *
+ */
+struct sym *
+newsym(void)
+{
+        a_uint ev;
+        int c, i, nsym;
+        struct sym *tsp;
+        struct sym **s;
+        char id[NCPS];
+
+        if (headp == NULL) {
+                fprintf(stderr, "No header defined\n");
+                lkexit(ER_FATAL);
+        }
+        /*
+         * Create symbol entry
+         */
+        getSid(id);
+        tsp = lkpsym(id, 1);
+        c = getnb();get();get();
+        if (c == 'R') {
+                tsp->s_type |= S_REF;
+                if (eval()) {
+                        fprintf(stderr, "Non zero S_REF\n");
+                        lkerr++;
+                }
+        } else
+        if (c == 'D') {
+                ev = eval();
+                if (tsp->s_type & S_DEF &&
+                    !(tsp->s_addr == ev && tsp->s_axp && tsp->s_axp->a_bap && ((tsp->s_axp->a_bap->a_flag & A3_ABS) == A3_ABS))) {
+                        fprintf(stderr,
+                                "Multiple definition of %s\n", id);
+                        lkerr++;
+                }
+                /*
+                 * Set value and area extension link.
+                 */
+                tsp->s_addr = ev;
+                tsp->s_axp = axp;
+                tsp->s_type |= S_DEF;
+                tsp->m_id = hp->m_id;
+        } else {
+                fprintf(stderr, "Invalid symbol type %c for %s\n", c, id);
+                lkexit(ER_FATAL);
+        }
+        /*
+         * Place pointer in header symbol list
+         */
+        nsym = hp->h_nsym;
+        s = hp->s_list;
+        for (i=0; i < nsym ;++i) {
+                if (s[i] == NULL) {
+                        s[i] = tsp;
+                        return(tsp);
+                }
+        }
+        fprintf(stderr, "Header symbol list overflow\n");
+        lkexit(ER_FATAL);
+        return(NULL);
+}
+
+/*)Function     sym *   lkpsym(id,f)
+ *
+ *              char *  id              symbol name string
+ *              int     f               f == 0, lookup only
+ *                                      f != 0, create if not found
+ *
+ *      The function lookup() searches the symbol hash tables for
+ *      a symbol name match returning a pointer to the sym structure.
+ *      If the symbol is not found then a sym structure is created,
+ *      initialized, and linked to the appropriate hash table if f != 0.
+ *      A pointer to this new sym structure is returned or a NULL
+ *      pointer is returned if f == 0.
+ *
+ *      local variables:
+ *              int     h               computed hash value
+ *              sym *   sp              pointer to a sym structure
+ *
+ *      global varaibles:
+ *              sym * symhash[]         array of pointers to NHASH
+ *                                      linked symbol lists
+ *              int     zflag           Disable symbol case sensitivity
+ *
+ *      functions called:
+ *              int     hash()          lksym.c
+ *              char *  new()           lksym.c
+ *              int     symeq()         lksym.c
+ *
+ *      side effects:
+ *              If the function new() fails to allocate space
+ *              for the new sym structure the linker terminates.
+ */
+
+struct sym *
+lkpsym(char *id, int f)
+{
+        struct sym *sp;
+        int h;
+
+        h = hash(id, zflag);
+        sp = symhash[h];
+        while (sp != NULL) {
+                if (symeq(id, sp->s_id, zflag))
+                        return (sp);
+                sp = sp->s_sp;
+        }
+        if (f == 0)
+                return (NULL);
+        sp = (struct sym *) new (sizeof(struct sym));
+        sp->s_sp = symhash[h];
+        symhash[h] = sp;
+        sp->s_id = strsto(id);   /* JLH */
+        return (sp);
+}
+
+/*)Function     a_uint  symval(tsp)
+ *
+ *              sym *   tsp             pointer to a symbol structure
+ *
+ *      The function symval() returns the value of the
+ *      relocated symbol by adding the variable definition
+ *      value to the areax base address.
+ *
+ *      local variables:
+ *              a_uint  val             relocated address value
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              none
+ */
+
+a_uint
+symval(struct sym *tsp)
+{
+        a_uint val;
+
+        val = tsp->s_addr;
+        if (tsp->s_axp) {
+                val += tsp->s_axp->a_addr;
+        }
+        return(val);
+}
+
+/*)Function     VOID    symdef(fp)
+ *
+ *              FILE *  fp              file handle for output
+ *
+ *      The function symdef() scans the hashed symbol table
+ *      searching for variables referenced but not defined.
+ *      Undefined variables are linked to the default
+ *      area "_CODE" and reported as referenced by the
+ *      appropriate module.
+ *
+ *      local variables:
+ *              int     i               hash table index loop variable
+ *              sym *   sp              pointer to linked symbol structure
+ *
+ *      global variables:
+ *              area    *areap          The pointer to the first
+ *                                      area structure of a linked list
+ *              sym *symhash[NHASH]     array of pointers to NHASH
+ *                                      linked symbol lists
+ *
+ *      functions called:
+ *              symmod()                lksym.c
+ *
+ *      side effects:
+ *              Undefined variables have their areas set to "_CODE".
+ */
+
+VOID
+symdef(FILE *fp)
+{
+        struct sym *sp;
+        int i;
+
+        for (i=0; i<NHASH; ++i) {
+                sp = symhash[i];
+                while (sp) {
+                        if (sp->s_axp == NULL)
+                                sp->s_axp = areap->a_axp;
+                        if ((sp->s_type & S_DEF) == 0)
+                                symmod(fp, sp);
+                        sp = sp->s_sp;
+                }
+        }
+}
+
+/*)Function     VOID    symmod(fp,tsp)
+ *
+ *              FILE *  fp              output file handle
+ *              sym *   tsp             pointer to a symbol structure
+ *
+ *      The function symmod() scans the header structures
+ *      searching for a reference to the symbol structure
+ *      pointed to by tsp.  The function then generates an error
+ *      message whichs names the module having referenced the
+ *      undefined variable.
+ *
+ *      local variables:
+ *              int     i               loop counter
+ *              sym **  p               pointer to a list of pointers
+ *                                      to symbol structures
+ *
+ *      global variables:
+ *              head    *headp          The pointer to the first
+ *                                      head structure of a linked list
+ *              head    *hp             Pointer to the current
+ *                                      head structure
+ *              int     lkerr           error flag
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *
+ *      side effects:
+ *              Error output generated.
+ */
+
+VOID
+symmod(FILE *fp, struct sym *tsp)
+{
+        int i;
+        struct sym **p;
+
+        if ((hp = headp) != NULL) {
+                while(hp) {
+                        p = hp->s_list;
+                        for (i=0; i<hp->h_nsym; ++i) {
+                                if (p[i] == tsp) {
+                                        fprintf(fp,
+                                                "\n?ASlink-Warning-Undefined Global '%s' ",
+                                                tsp->s_id);
+                                        fprintf(fp,
+                                                "referenced by module '%s'\n",
+                                                hp->m_id);
+                                        lkerr++;
+                                }
+                        }
+                        hp = hp->h_hp;
+                }
+        }
+}
+
+/*)Function     int     symeq(p1, p2, cflag)
+ *
+ *              int     cflag           case sensitive flag
+ *              char *  p1              name string
+ *              char *  p2              name string
+ *
+ *      The function symeq() compares the two name strings for a match.
+ *      The return value is 1 for a match and 0 for no match.
+ *
+ *              cflag == 0      case sensitive compare
+ *              cflag != 0      case insensitive compare
+ *
+ *      local variables:
+ *              int     n               loop counter
+ *
+ *      global variables:
+ *              char    ccase[]         an array of characters which
+ *                                      perform the case translation function
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              none
+ *
+ */
+
+int
+symeq(char *p1, char *p2, int cflag)
+{
+        int n;
+
+        n = strlen(p1) + 1;
+        if(cflag) {
+                /*
+                 * Case Insensitive Compare
+                 */
+                do {
+                        if (ccase[*p1++ & 0x007F] != ccase[*p2++ & 0x007F])
+                                return (0);
+                } while (--n);
+        } else {
+                /*
+                 * Case Sensitive Compare
+                 */
+                do {
+                        if (*p1++ != *p2++)
+                                return (0);
+                } while (--n);
+        }
+        return (1);
+}
+
+/*)Function     int     hash(p, cflag)
+ *
+ *              char *  p               pointer to string to hash
+ *              int     cflag           case sensitive flag
+ *
+ *      The function hash() computes a hash code using the sum
+ *      of all characters mod table size algorithm.
+ *
+ *              cflag == 0      case sensitive hash
+ *              cflag != 0      case insensitive hash
+ *
+ *      local variables:
+ *              int     h               accumulated character sum
+ *
+ *      global variables:
+ *              char    ccase[]         an array of characters which
+ *                                      perform the case translation function
+ *
+ *      functions called:
+ *              none
+ *
+ *      side effects:
+ *              none
+ */
+
+int
+hash(char *p, int cflag)
+{
+        int h;
+
+        h = 0;
+        while (*p) {
+                if(cflag) {
+                        /*
+                         * Case Insensitive Hash
+                         */
+                        h += ccase[*p++ & 0x007F];
+                } else {
+                        /*
+                         * Case Sensitive Hash
+                         */
+                        h += *p++;
+                }
+        }
+        return (h&HMASK);
+}
+
+#if     decus
+
+/*)Function     char *  strsto(str)
+ *
+ *              char *  str             pointer to string to save
+ *
+ *      Allocate space for "str", copy str into new space.
+ *      Return a pointer to the allocated string.
+ *
+ *      This function based on code by
+ *              John L. Hartman
+ *              jhartman@compuserve.com
+ *
+ *      local variables:
+ *              int     l               string length + 1
+ *              char *  p               string location
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              char *  new()           assym.c
+ *              char *  strncpy()       c_library
+ *
+ *      side effects:
+ *              Space allocated for string, string copied
+ *              to space.  Out of Space terminates linker.
+ */
+
+char *
+strsto(char *str)
+{
+        int  l;
+        char *p;
+
+        /*
+         * What we need, including a null.
+         */
+        l = strlen(str) + 1;
+        p = (char *) new (l);
+
+        /*
+         * Copy the name and terminating null.
+         */
+        strncpy(p, str, l);
+        return(p);
+}
+
+/*
+ * This code is optimized for the PDP-11 (decus)
+ * which has a limited program space of 56K Bytes !
+ * Short strings and small structures are allocated
+ * from a memory hunk in new() to reduce the overhead
+ * from allocations directly by malloc().  Longer
+ * allocations are made directly by malloc.
+ * PDP-11 addressing requires that variables
+ * are allocated on a word boundary, (strings donot
+ * have this restriction,) all allocations will have
+ * at most 1 extra byte to maintain the word boundary
+ * requirement.
+ */
+
+/*)Function     char *  new(n)
+ *
+ *              unsigned int    n       allocation size in bytes
+ *
+ *      The function new() allocates n bytes of space and returns
+ *      a pointer to this memory.  If no space is available the
+ *      linker is terminated.
+ *
+ *      Allocate space for "str", copy str into new space.
+ *      Return a pointer to the allocated string.
+ *
+ *      This function based on code by
+ *              John L. Hartman
+ *              jhartman@compuserve.com
+ *
+ *      local variables:
+ *              int     bytes           bytes remaining in buffer area
+ *              int     i               loop counter
+ *              char *  p               pointer to head of copied string
+ *              char *  pnext           next location in buffer area
+ *              char *  q               a general pointer
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID *  malloc()        c_library
+ *
+ *      side effects:
+ *              Memory is allocated, if allocation fails
+ *              the linker is terminated.
+ */
+
+/*
+ * To avoid wasting memory headers on small allocations, we
+ * allocate a big chunk and parcel it out as required.
+ * These static variables remember our hunk.
+ */
+
+#define STR_SPC 1024
+#define STR_MIN 16
+static  char *  pnext = NULL;
+static  int     bytes = 0;
+
+char *
+new(unsigned int n)
+{
+        char *p,*q;
+        unsigned int i;
+
+        /*
+         * Always an even byte count
+         */
+        n = (n+1) & 0xFFFE;
+
+        if (n > STR_MIN) {
+                /*
+                 * For allocations larger than
+                 * most structures and short strings
+                 * allocate the space directly.
+                 */
+                p = (char *) malloc(n);
+        } else {
+                /*
+                 * For smaller structures and
+                 * strings allocate from the hunk.
+                 */
+                if (n > bytes) {
+                        /*
+                         * No space.  Allocate a new hunk.
+                         * We lose the pointer to any old hunk.
+                         * We don't care, as the pieces are never deleted.
+                        */
+                        pnext = (char *) malloc (STR_SPC);
+                        bytes = STR_SPC;
+                }
+                p = pnext;
+                pnext += n;
+                bytes -= n;
+        }
+        if (p == NULL) {
+                fprintf(stderr, "Out of space!\n");
+                lkexit(ER_FATAL);
+        }
+        for (i=0,q=p; i<n; i++) {
+                *q++ = 0;
+        }
+        return (p);
+}
+
+#else
+
+/*)Function     char *  strsto(str)
+ *
+ *              char *  str             pointer to string to save
+ *
+ *      Allocate space for "str", copy str into new space.
+ *      Return a pointer to the allocated string.
+ *
+ *      This function based on code by
+ *              John L. Hartman
+ *              jhartman@compuserve.com
+ *
+ *      local variables:
+ *              int     l               string length + 1
+ *              int     bytes           bytes remaining in buffer area
+ *              char *  p               pointer to head of copied string
+ *              char *  pnext           next location in buffer area
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              char *  new()           assym.c
+ *              char *  strncpy()       c_library
+ *
+ *      side effects:
+ *              Space allocated for string, string copied
+ *              to space.  Out of Space terminates assembler.
+ */
+
+/*
+ * To avoid wasting memory headers on small allocations, we
+ * allocate a big chunk and parcel it out as required.
+ * These static variables remember our hunk
+ */
+
+#define STR_SPC 1024
+static  char *  pnext = NULL;
+static  int     bytes = 0;
+
+char *
+strsto(char *str)
+{
+        int  l;
+        char *p;
+
+        /*
+         * What we need, including a null.
+         */
+        l = strlen(str) + 1;
+
+        if (l > bytes) {
+                /*
+                 * No space.  Allocate a new hunk.
+                 * We lose the pointer to any old hunk.
+                 * We don't care, as the strings are never deleted.
+                */
+                pnext = (char *) new (STR_SPC);
+                bytes = STR_SPC;
+        }
+
+        /*
+         * Copy the name and terminating null.
+         */
+        p = pnext;
+        strncpy(p, str, l);
+
+        pnext += l;
+        bytes -= l;
+
+        return(p);
+}
+
+/*)Function     char *  new(n)
+ *
+ *              unsigned int    n       allocation size in bytes
+ *
+ *      The function new() allocates n bytes of space and returns
+ *      a pointer to this memory.  If no space is available the
+ *      linker is terminated.
+ *
+ *      local variables:
+ *              char *  p               a general pointer
+ *              char *  q               a general pointer
+ *
+ *      global variables:
+ *              none
+ *
+ *      functions called:
+ *              int     fprintf()       c_library
+ *              VOID *  malloc()        c_library
+ *
+ *      side effects:
+ *              Memory is allocated, if allocation fails
+ *              the linker is terminated.
+ */
+
+char *
+new(unsigned int n)
+{
+        char *p,*q;
+        unsigned int i;
+
+        if ((p = (char *) malloc(n)) == NULL) {
+                fprintf(stderr, "Out of space!\n");
+                lkexit(ER_FATAL);
+        }
+        for (i=0,q=p; i<n; i++) {
+                *q++ = 0;
+        }
+        return (p);
+}
+
+#endif
diff --git a/Kernel/tools/bankld/readme.390 b/Kernel/tools/bankld/readme.390
new file mode 100644 (file)
index 0000000..80170bd
--- /dev/null
@@ -0,0 +1,141 @@
+DS80C390 flat mode support
+
+2/4/2000 Kevin Vigor (e-mail: kevin at vigor.nu)
+
+I have hacked the 8051 assembler to support the 24 bit flat address mode of
+the DS80C390 processor. This mode allows the chip to directly address up to
+4 Meg of RAM. Details can be found at Dallas' web site: www.dalsemi.com.
+
+1: Assembler changes.
+
+24 bit mode is entered via a new assembler directive, .flat24. This directive
+takes a mandatory argument, which is either the string "on" or the string
+"off". ".flat24 on" enables 24-bit mode, and ".flat24 off" puts the assembler
+into standard 8051 mode.
+
+Note that any .included files within a ".flat24 on" segment of the code will
+be compiled in 24-bit mode.
+
+In 24-bit mode, 8 instructions have altered behavior. Of these, 5 modify
+the instruction encoding, while 3 differ only in behavior. These
+instructions are discussed in the DS80C390 User's Guide, but a summary is
+included here:
+
+ACALL and AJMP now take a 19 bit offset instead of the 8051's 11 bit offset. 
+An extra address byte is added to the encoded instruction.
+
+LCALL and LJMP now take a 24 bit target address instead of the 8051's 16 bit
+address. An extra address byte is added to the encoded instruction.
+
+MOV DPTR, #immed now takes a 24 bit immediate value instead of the 8051's 16
+bit address. An extra data byte is added to the encoded instruction.
+
+INC DPTR now increments the entire 24 bit DPTR. The encoding is not changed.
+
+RET and RETI restore the full 24 bit PC from the stack. The encoding is not
+changed.
+
+2: Linker changes.
+
+The linker supports (through a variety of evil hacks) 19 bit ACALL/AJMP
+relocations and 24 bit LCALL/LJMP/DPTR relocations. These changes should be
+invisible to the user.
+
+The linker can now also generated extended linear address records in the
+Intel hex output format. This is necessary for any areas located above the
+64K mark. This is enabled by the "-r" linker flag, and is disabled by
+default (but the linker will throw a warning if an extended address is
+encountered without the -r flag being enabled).
+
+Note that for various reasons, areas may still not be larger than 64K.
+However, they may be located anywhere in the 4 Meg address space via the
+assembler .org directive (for ABS areas) or the linker "-b" option.
+
+3: Examples
+
+Note that this example uses ABS areas to make the layout obvious. This code
+won't do anything useful at all, but demonstrates the instruction encoding
+in .flat24 mode vs 8051 mode.
+
+; test1.asm
+.area CODE (ABS)
+.org 0
+
+; SFRs not known to the assembler yet...
+$TA = 0x00C7
+$ACON = 0x009D
+
+; Set the chip to 24 bit flat mode via the DS "timed access" procedure.
+mov $TA, #0xAA
+mov $TA, #0x55
+mov $ACON, #0x06               ; 10 bit stack & 24 bit flat addressing.
+
+.flat24 on             ; Enable 24-bit mode. The AM1 bit had better be
+                       ; on...
+
+mov dptr, #myData      ; Valid on the '390: myData is in the FARDATA
+                       ; area at 0x300001.
+                       ; Generates: 90 30 00 01
+acall _junkNear                ; Within 11 bit range, but still must generate
+                       ; 19 bit address for '390 flat mode.
+                       ; Generates: 11 04 00                   
+ajmp _junkFar          ; Within 16 bit range.
+                       ; Generates 01 08 00
+acall _junkReallyFar   ; Within 19 bit range.
+                       ; Generates 91 00 00
+lcall _junkReallyReallyFar     ; Within 24 bit range.
+                       ; Generates 12 08 00 00
+
+; Set the chip to 8051 mode via the DS "timed access" procedure.
+mov $TA, #0x0AA
+mov $TA, #0x055
+mov $ACON, #0x00       ; 8 bit stack & 16 bit flat addressing.
+
+.flat24 off            ; Now we're an 8051 again. The AM1 bit had better be
+                       ; off...
+
+;mov dptr, #myData     ; Can't do that: myData is too far away.
+acall _junkNear                ; Within 11 bit range.
+                       ; Generates 91 00
+ljmp _junkFar          ; Within 16 bit range; can't AJMP, but can LJMP
+                       ; Generates 02 08 00
+ret
+
+.area CODE2 (ABS)
+.org 0x400
+; This is within the 11 bit ACALL/AJMP range of the 8051.
+_junkNear:
+ret
+
+.area CODE3 (ABS)
+.org 0x800
+; This is within the 390's 19 bit ACALL/AJMP range, and inside the stock
+; 8051's 16 bit LCALL range.
+_junkFar:
+ret
+
+.area CODE4 (ABS)
+; This is within the 390's 19 bit ACALL/AJMP range and outside the
+; 8051's LCALL range.
+; Note that to link an image with an area beyond 64K (like this one),
+; the '-r' flag must be provided to the linker, and Intel Hex output format
+; must be used.
+.org 0x40000
+_junkReallyFar:
+ret
+
+.area CODE5 (ABS)
+; This is outside anybody's ACALL/AJMP range.
+.org 0x80000
+_junkReallyReallyFar:
+ret
+
+.area FARDATA (ABS)
+.org 0x300000
+; This is way, way up there.
+.byte 0x01
+myData:
+.byte 0x02
+
+; test1.asm ends.
+
diff --git a/Kernel/tools/bankld/sdld.c b/Kernel/tools/bankld/sdld.c
new file mode 100644 (file)
index 0000000..76bce8b
--- /dev/null
@@ -0,0 +1,139 @@
+/* sdld.c
+
+   Copyright (C) 2009-2010 Borut Razem
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+#ifndef _WIN32
+#include <libgen.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sdld.h"
+
+#define NELEM(x)  (sizeof (x) / sizeof (x)[0])
+
+
+static int sdld = -1;
+static enum sdld_target_e target = TARGET_ID_UNKNOWN;
+
+
+static char
+*program_name (char *path)
+{
+#ifdef _WIN32
+  static char fname[_MAX_FNAME];
+  char *p;
+
+  _splitpath (path, NULL, NULL, fname, NULL);
+  /* convert it to lower case:
+     on DOS and Windows 9x the file name in argv[0] is uppercase */
+  for (p = fname; '\0' != *p; ++p)
+    *p = tolower (*p);
+  return fname;
+#else
+  return basename (path);
+#endif
+}
+
+
+static void
+check_init(void)
+{
+  if (sdld == -1)
+    {
+      fprintf(stderr, "sdld_init not called!\n");
+      exit (1);
+    }
+}
+
+
+void
+sdld_init (char *path)
+{
+  struct tgt_s {
+    char *str;
+    enum sdld_target_e target;
+  } tgt[] = {
+    { "gb",   TARGET_ID_GB,   },
+    { "z80",  TARGET_ID_Z80,  },
+    { "z180", TARGET_ID_Z180, },
+    { "8051", TARGET_ID_8051, },
+    { "6808", TARGET_ID_6808, },
+    { "stm8", TARGET_ID_STM8, },
+  };
+  int i = NELEM (tgt);
+
+  char *progname = program_name (path);
+  if ((sdld = (strncmp(progname, "sdld", 4) == 0)) != 0)
+    {
+      /* exception: sdld is 8051 linker */
+      if (progname[4] == '\0')
+        target = TARGET_ID_8051;
+      else
+        {
+          for (i = 0; i < NELEM (tgt); ++i)
+            {
+              if (strstr(progname, tgt[i].str))
+                {
+                  target = tgt[i].target;
+                  break;
+                }
+            }
+        }
+    }
+  /* diagnostic message */
+  if (getenv ("SDLD_DIAG"))
+    {
+      printf ("sdld path: %s\n", path);
+      printf ("is sdld: %d\n", sdld);
+      if (sdld)
+        printf ("sdld target: %s\n", (i >= NELEM (tgt)) ? "8051" : tgt[i].str);
+    }
+}
+
+
+int
+is_sdld(void)
+{
+  check_init();
+  return sdld;
+}
+
+
+enum sdld_target_e
+get_sdld_target(void)
+{
+  check_init();
+  return target;
+}
+
+
+int
+is_sdld_target_z80_like(void)
+{
+  check_init();
+  return target == TARGET_ID_Z80 || target == TARGET_ID_Z180 || target == TARGET_ID_GB;
+}
+
+
+int
+is_sdld_target_8051_like(void)
+{
+  check_init();
+  return target == TARGET_ID_8051;
+}
diff --git a/Kernel/tools/bankld/sdld.h b/Kernel/tools/bankld/sdld.h
new file mode 100644 (file)
index 0000000..9fdc6a6
--- /dev/null
@@ -0,0 +1,44 @@
+/* sdld.h
+
+   Copyright (C) 2009 Borut Razem
+
+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, 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 <http://www.gnu.org/licenses/>. */
+
+#ifndef __SDLD_H
+#define __SDLD_H
+
+enum sdld_target_e {
+  TARGET_ID_UNKNOWN,
+  TARGET_ID_GB,
+  TARGET_ID_Z80,
+  TARGET_ID_Z180,
+  TARGET_ID_8051,
+  TARGET_ID_6808,
+  TARGET_ID_STM8,
+};
+
+void sdld_init (char *path);
+int is_sdld(void);
+enum sdld_target_e get_sdld_target(void);
+int is_sdld_target_z80_like(void);
+int is_sdld_target_8051_like(void);
+
+#define TARGET_IS_GB   (get_sdld_target() == TARGET_ID_GB)
+#define TARGET_IS_Z80   (get_sdld_target() == TARGET_ID_Z80)
+#define TARGET_IS_Z180  (get_sdld_target() == TARGET_ID_Z180)
+#define TARGET_IS_8051  (get_sdld_target() == TARGET_ID_8051)
+#define TARGET_IS_6808  (get_sdld_target() == TARGET_ID_6808)
+#define TARGET_IS_STM8  (get_sdld_target() == TARGET_ID_STM8)
+
+#endif  /* __SDLD_H */