/* 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; }