/* 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 .
*
*
* 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 j;
if (i && obj_flag) { return; }
if (ofp == NULL) { return; }
/*
* Create the Byte Output Address
*/
for (j=1; ja_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; is_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()
{
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, ":02000004%04lX%02lX\n", hi_addr, (~chksum + 1) & 0x00ff);
#else
fprintf(ofp, ":02000004%04X%02X\n", 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%04lX00", reclen, lo_addr);
#else
fprintf(ofp, ":%02X%04X00", reclen, lo_addr);
#endif
for (i=0; is_axp->a_bap->a_ofp == ofp)) {
symadr = symval(sp);
for (i=0,addr=symadr; i>=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>=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; is_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;
}