The Relogix translation

Note: This is a 100% automatic translation, with no human intervention or cleaning-up of the code. Relogix has automatically chosen the function prototypes, has chosen the variable types itself, and has placed the assembler comments in the translated source allowing for the re-arrangement of the code flow. It has also recovered complex control statements like 'for' loops and 'switch' statements.

The code is not quite ready to use. It needs a little tidying up of some of the variable declarations, and some minor changes to handle pointers correctly. However, it should be easy to see that the final code will be high quality C which is easy to read and maintain.




/************************************************************************
*                                                                       *
*       "xmodem.c" - Translated from file "xmodem.asm"                  *
*                                                                       *
*-----------------------------------------------------------------------*
*                                                                       *
*       Relogix Code Translator Copyright (c) MicroAPL 1990-2017        *
*                   All Rights Reserved Worldwide                       *
*                                                                       *
*************************************************************************
*/

/*
* Originally downloaded from: http://www.6502.org/source/io/xmodem/xmodem.txt
*
* XMODEM/CRC Sender/Receiver for the 65C02
*
* By Daryl Rictor Aug 2002
*
* A simple file transfer program to allow transfers between the SBC and a 
* console device utilizing the x-modem/CRC transfer protocol.  Requires 
* ~1200 bytes of either RAM or ROM, 132 bytes of RAM for the receive buffer,
* and 12 bytes of zero page RAM for variable storage.
*
***************************************************************************
* This implementation of XMODEM/CRC does NOT conform strictly to the 
* XMODEM protocol standard in that it (1) does not accurately time character
* reception or (2) fall back to the Checksum mode.
* (1) For timing, it uses a crude timing loop to provide approximate
* delays.  These have been calibrated against a 1MHz CPU clock.  I have
* found that CPU clock speed of up to 5MHz also work but may not in
* every case.  Windows HyperTerminal worked quite well at both speeds!
*
* (2) Most modern terminal programs support XMODEM/CRC which can detect a
* wider range of transmission errors so the fallback to the simple checksum
* calculation was not implemented to save space.
***************************************************************************
*
* Files transferred via XMODEM-CRC will have the load address contained in
* the first two bytes in little-endian format:  
*  FIRST BLOCK
*     offset(0) = lo(load start address),
*     offset(1) = hi(load start address)
*     offset(2) = data byte (0)
*     offset(n) = data byte (n-2)
*
* Subsequent blocks
*     offset(n) = data byte (n)
*
* One note, XMODEM send 128 byte blocks.  If the block of memory that
* you wish to save is smaller than the 128 byte block boundary, then
* the last block will be padded with zeros.  Upon reloading, the
* data will be written back to the original location.  In addition, the
* padded zeros WILL also be written into RAM, which could overwrite other
* data.   
*
*-------------------------- The Code ----------------------------
*
* zero page variables (adjust these to suit your needs)
*
*
*
*
* non-zero page variables and buffers
*
*
*(place anywhere, page aligned)
*
*
*  tables and constants
*
*
* The crclo & crchi labels are used to point to a lookup table to calculate
* the CRC for the 128 byte data blocks.  There are two implementations of these
* tables.  One is to use the tables included (defined towards the end of this
* file) and the other is to build them at run-time.  If building at run-time,
* then these two labels will need to be un-commented and declared in RAM.
*
*crclo          =       $7D00           ; Two 256-byte tables for quick lookup
*crchi          =       $7E00           ; (should be page-aligned for speed)
*
*
*
* XMODEM Control Character Constants
*
*^^^^^^^^^^^^^^^^^^^^^^ Start of Program ^^^^^^^^^^^^^^^^^^^^^^
*
* Xmodem/CRC transfer routines
* By Daryl Rictor, August 8, 2002
*
* v1.0  released on Aug 8, 2002.
*
*
**=      $FA00           ; Start of program (adjust to your needs)
*
* Enter this routine with the beginning address stored in the zero page address
* pointed to by ptr & ptrh and the ending address stored in the zero page address
* pointed to by eofp & eofph.
*
*
*/


#include "rlx6502.h"
#include "xmodem_hdr.h"
#include "xmodem.h"

#define lastblk              (*(char *) 0x00000035)
#define blkno                (*(unsigned char *) 0x00000036)
#define errcnt               (*(char *) 0x00000037)
#define bflag                (*(unsigned char *) 0x00000037)
#define crc                  (*(unsigned char *) 0x00000038)
#define crch                 (*(unsigned char *) 0x00000039)
#define ptr                  (*(unsigned char *) 0x0000003a)
#define ptrh                 (*(unsigned char *) 0x0000003b)
#define eofp                 (*(unsigned char *) 0x0000003c)
#define eofph                (*(unsigned char *) 0x0000003d)
#define retry                (*(char *) 0x0000003e)
#define retry2               (*(unsigned char *) 0x0000003f)
#define Rbuff                ((unsigned char *) 0x00000300)
#define SOH                  0x01                /* start block */
#define EOT                  0x04                /* end of text marker */
#define ACK                  0x06                /* good block acknowledged */
#define NAK                  0x15                /* bad block acknowledged */
#define CR                   0x0d                /* carriage return */
#define LF                   0x0a                /* line feed */
#define ESC                  0x1b                /* ESC to exit */
#define ACIA_Data            (*(unsigned char *) 0x00007f70)
#define ACIA_Status          (*(unsigned char *) 0x00007f71)
#define ACIA_Command         (*(char *) 0x00007f72)
#define ACIA_Control         (*(char *) 0x00007f73)

/* Prototypes for private routines translated to C */
static void Put_Chr (unsigned char a);
static void Flush (void);
static void PrintMsg (void);
static void Print_Err (void);
static void Print_Good (void);
static void CalcCRC (void);



/* Private file-scope variables */
static unsigned char Msg [] = {
        'B', 'e', 'g', 'i', 'n', ' ', 'X', 'M', 'O', 'D', 'E', 'M', '/', 'C', 'R', 'C', ' ', 
        't', 'r', 'a', 'n', 's', 'f', 'e', 'r', '.', ' ', ' ', 'P', 'r', 'e', 's', 's', ' ', 
        '<', 'E', 's', 'c', '>', ' ', 't', 'o', ' ', 'a', 'b', 'o', 'r', 't', '.', '.', '.', 
        CR, LF, 
        0
};
static unsigned char ErrMsg [] = {
        'T', 'r', 'a', 'n', 's', 'f', 'e', 'r', ' ', 'E', 'r', 'r', 'o', 'r', '!', 
        CR, LF, 
        0
};
static unsigned char GoodMsg [] = {
        EOT, CR, LF, EOT, CR, LF, EOT, CR, LF, CR, LF, 
        'T', 'r', 'a', 'n', 's', 'f', 'e', 'r', ' ', 'S', 'u', 'c', 'c', 'e', 's', 's', 'f', 'u', 'l', '!', 
        CR, LF, 
        0
};

/*  Alternate solution is to build the two lookup tables at run-time.  This might
    be desirable if the program is running from ram to reduce binary upload time.
    The following code generates the data for the lookup tables.  You would need to
    un-comment the variable declarations for crclo & crchi in the Tables and Constants
    section above and call this routine to build the tables before calling the
    "xmodem" routine.
   MAKECRCTABLE
                  ldx     #$00
                  LDA     #$00
   zeroloop       sta     crclo,x
                  sta     crchi,x
                  inx
                  bne     zeroloop
                  ldx     #$00
   fetch          txa
                  eor     crchi,x
                  sta     crchi,x
                  ldy     #$08
   fetch1         asl     crclo,x
                  rol     crchi,x
                  bcc     fetch2
                  lda     crchi,x
                  eor     #$10
                  sta     crchi,x
                  lda     crclo,x
                  eor     #$21
                  sta     crclo,x
   fetch2         dey
                  bne     fetch1
                  inx
                  bne     fetch
                  rts
    The following tables are used to calculate the CRC for the 128 bytes
    in the xmodem data blocks.  You can use these tables if you plan to 
    store this program in ROM.  If you choose to build them at run-time, 
    then just delete them and define the two labels: crclo & crchi.
    low byte CRC lookup table (should be page aligned)
   *= $FD00 */
static unsigned char crclo [] = {
        0x00, 0x21, 0x42, 0x63, 0x84, 0xa5, 0xc6, 0xe7, 0x08, 0x29, 0x4a, 0x6b, 0x8c, 0xad, 0xce, 0xef, 
        0x31, 0x10, 0x73, 0x52, 0xb5, 0x94, 0xf7, 0xd6, 0x39, 0x18, 0x7b, 0x5a, 0xbd, 0x9c, 0xff, 0xde, 
        0x62, 0x43, 0x20, 0x01, 0xe6, 0xc7, 0xa4, 0x85, 0x6a, 0x4b, 0x28, 0x09, 0xee, 0xcf, 0xac, 0x8d, 
        0x53, 0x72, 0x11, 0x30, 0xd7, 0xf6, 0x95, 0xb4, 0x5b, 0x7a, 0x19, 0x38, 0xdf, 0xfe, 0x9d, 0xbc, 
        0xc4, 0xe5, 0x86, 0xa7, 0x40, 0x61, 0x02, 0x23, 0xcc, 0xed, 0x8e, 0xaf, 0x48, 0x69, 0x0a, 0x2b, 
        0xf5, 0xd4, 0xb7, 0x96, 0x71, 0x50, 0x33, 0x12, 0xfd, 0xdc, 0xbf, 0x9e, 0x79, 0x58, 0x3b, 0x1a, 
        0xa6, 0x87, 0xe4, 0xc5, 0x22, 0x03, 0x60, 0x41, 0xae, 0x8f, 0xec, 0xcd, 0x2a, 0x0b, 0x68, 0x49, 
        0x97, 0xb6, 0xd5, 0xf4, 0x13, 0x32, 0x51, 0x70, 0x9f, 0xbe, 0xdd, 0xfc, 0x1b, 0x3a, 0x59, 0x78, 
        0x88, 0xa9, 0xca, 0xeb, 0x0c, 0x2d, 0x4e, 0x6f, 0x80, 0xa1, 0xc2, 0xe3, 0x04, 0x25, 0x46, 0x67, 
        0xb9, 0x98, 0xfb, 0xda, 0x3d, 0x1c, 0x7f, 0x5e, 0xb1, 0x90, 0xf3, 0xd2, 0x35, 0x14, 0x77, 0x56, 
        0xea, 0xcb, 0xa8, 0x89, 0x6e, 0x4f, 0x2c, 0x0d, 0xe2, 0xc3, 0xa0, 0x81, 0x66, 0x47, 0x24, 0x05, 
        0xdb, 0xfa, 0x99, 0xb8, 0x5f, 0x7e, 0x1d, 0x3c, 0xd3, 0xf2, 0x91, 0xb0, 0x57, 0x76, 0x15, 0x34, 
        0x4c, 0x6d, 0x0e, 0x2f, 0xc8, 0xe9, 0x8a, 0xab, 0x44, 0x65, 0x06, 0x27, 0xc0, 0xe1, 0x82, 0xa3, 
        0x7d, 0x5c, 0x3f, 0x1e, 0xf9, 0xd8, 0xbb, 0x9a, 0x75, 0x54, 0x37, 0x16, 0xf1, 0xd0, 0xb3, 0x92, 
        0x2e, 0x0f, 0x6c, 0x4d, 0xaa, 0x8b, 0xe8, 0xc9, 0x26, 0x07, 0x64, 0x45, 0xa2, 0x83, 0xe0, 0xc1, 
        0x1f, 0x3e, 0x5d, 0x7c, 0x9b, 0xba, 0xd9, 0xf8, 0x17, 0x36, 0x55, 0x74, 0x93, 0xb2, 0xd1, 0xf0
};

/*  hi byte CRC lookup table (should be page aligned)
   *= $FE00 */
static unsigned char crchi [] = {
        0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1, 
        0x12, 0x02, 0x32, 0x22, 0x52, 0x42, 0x72, 0x62, 0x93, 0x83, 0xb3, 0xa3, 0xd3, 0xc3, 0xf3, 0xe3, 
        0x24, 0x34, 0x04, 0x14, 0x64, 0x74, 0x44, 0x54, 0xa5, 0xb5, 0x85, 0x95, 0xe5, 0xf5, 0xc5, 0xd5, 
        0x36, 0x26, 0x16, 0x06, 0x76, 0x66, 0x56, 0x46, 0xb7, 0xa7, 0x97, 0x87, 0xf7, 0xe7, 0xd7, 0xc7, 
        0x48, 0x58, 0x68, 0x78, 0x08, 0x18, 0x28, 0x38, 0xc9, 0xd9, 0xe9, 0xf9, 0x89, 0x99, 0xa9, 0xb9, 
        0x5a, 0x4a, 0x7a, 0x6a, 0x1a, 0x0a, 0x3a, 0x2a, 0xdb, 0xcb, 0xfb, 0xeb, 0x9b, 0x8b, 0xbb, 0xab, 
        0x6c, 0x7c, 0x4c, 0x5c, 0x2c, 0x3c, 0x0c, 0x1c, 0xed, 0xfd, 0xcd, 0xdd, 0xad, 0xbd, 0x8d, 0x9d, 
        0x7e, 0x6e, 0x5e, 0x4e, 0x3e, 0x2e, 0x1e, 0x0e, 0xff, 0xef, 0xdf, 0xcf, 0xbf, 0xaf, 0x9f, 0x8f, 
        0x91, 0x81, 0xb1, 0xa1, 0xd1, 0xc1, 0xf1, 0xe1, 0x10, 0x00, 0x30, 0x20, 0x50, 0x40, 0x70, 0x60, 
        0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3, 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72, 
        0xb5, 0xa5, 0x95, 0x85, 0xf5, 0xe5, 0xd5, 0xc5, 0x34, 0x24, 0x14, 0x04, 0x74, 0x64, 0x54, 0x44, 
        0xa7, 0xb7, 0x87, 0x97, 0xe7, 0xf7, 0xc7, 0xd7, 0x26, 0x36, 0x06, 0x16, 0x66, 0x76, 0x46, 0x56, 
        0xd9, 0xc9, 0xf9, 0xe9, 0x99, 0x89, 0xb9, 0xa9, 0x58, 0x48, 0x78, 0x68, 0x18, 0x08, 0x38, 0x28, 
        0xcb, 0xdb, 0xeb, 0xfb, 0x8b, 0x9b, 0xab, 0xbb, 0x4a, 0x5a, 0x6a, 0x7a, 0x0a, 0x1a, 0x2a, 0x3a, 
        0xfd, 0xed, 0xdd, 0xcd, 0xbd, 0xad, 0x9d, 0x8d, 0x7c, 0x6c, 0x5c, 0x4c, 0x3c, 0x2c, 0x1c, 0x0c, 
        0xef, 0xff, 0xcf, 0xdf, 0xaf, 0xbf, 0x8f, 0x9f, 0x6e, 0x7e, 0x4e, 0x5e, 0x2e, 0x3e, 0x0e, 0x1e
};


/*
*************************************************************************
* XModemSend                                                            *
*************************************************************************
*/
void XModemSend (void)
{
    unsigned char comp_blkno_next;               /* [Originally in A] */
    unsigned char i;                             /* [Originally in Y] */
    unsigned char j;                             /* [Originally in X] */
    unsigned char rx_char;                       /* [Originally in A] */

    PrintMsg ();                                 /* send prompt and info  */
    errcnt = 0x00;                               /* error counter set to 0  */
    lastblk = 0x00;                              /* set flag to false  */
    blkno = 0x01;                                /* set block # to 1  */

    while (True) {
        retry2 = 0xff;                           /* 3 seconds  */
        if (GetByte (&rx_char)) {
            /* is it the "C" to start a CRC xfer? */
            if (rx_char == 'C')
                break;

            /* is it a cancel? <Esc> Key */
            if (rx_char == ESC) {
                Flush ();                        /* yes, too many errors, flush buffer,  */
                Print_Err ();
                return;
            }
        }
    }

    i = 0x00;                                    /* init data block offset to 0  */
    j = 0x04;                                    /* preload X to Receive buffer  */
    Rbuff [0] = 0x01;                            /* manually load blk number 
                                                     into 1st byte */
    Rbuff [1] = 0xfe;                            /* load 1's comp of block # 
                                                     into 2nd byte */
    Rbuff [2] = ptr;                             /* load low byte of start address 
                                                     into 3rd byte */
    Rbuff [3] = ptrh;                            /* load hi byte of start address 
                                                     into 4th byte */

    while (True) {
        Rbuff [j] = **(unsigned char **) (&ptr + i);
                                                 /* save 128 bytes of data  */

        /* Are we at the last address? */
        if (eofp == ptr && eofph == ptrh) {
            lastblk++;                           /* Yes, Set last byte flag  */
            while (++j != 0x82)
                Rbuff [j] = 0x00;                /* Fill rest of 128 bytes with $00  */
        } else {
            if (++ptr == 0)
                ptrh++;

            /* last byte in block? */
            if (++j != 0x82)
                continue;
        }

        CalcCRC ();
        Rbuff [0x82] = crch;                     /* save Hi byte of CRC to buffer  */
        Rbuff [0x83] = crc;                      /* save lo byte of CRC to buffer  */

        while (True) {
            Put_Chr (SOH);                       /* send SOH  */
            for (j = 0x00; j < 0x84; j++)
                Put_Chr (Rbuff [j]);             /* Send 132 bytes in buffer to the console  */
            retry2 = 0xff;                       /* yes, set 3 second delay 
                                                     and */

            /* Wait for Ack/Nack */
            if (GetByte (&rx_char)) {
                /* Chr received... is it: */
                if (rx_char == ACK)
                    break;
                if (rx_char == ESC && ESC != NAK) {
                    Flush ();                    /* yes, too many errors, flush buffer,  */
                    Print_Err ();
                    return;
                }
            }

            /* are there 10 errors? (Xmodem spec for failure) */
            if (++errcnt == 0x0a) {
                Flush ();                        /* yes, too many errors, flush buffer,  */
                Print_Err ();
                return;
            }
        }

        /* Was the last block sent? */
        if (lastblk != 0)
            break;
        j = 0x02;                                /* init pointers  */
        i = 0x00;
        comp_blkno_next = ++blkno;
        Rbuff [0] = comp_blkno_next;             /* save in 1st byte of buffer  */
        Rbuff [1] = comp_blkno_next ^ 0xff;      /* save 1's comp of blkno next  */
    }

    Print_Good ();
}


/*
*************************************************************************
* XModemRcv                                                             *
*************************************************************************
*/
void XModemRcv (void)
{
    Boolean break_to_badcrc;
    unsigned char i;                             /* [Originally in X] */
    unsigned char rx_char;                       /* [Originally in A] */

    PrintMsg ();                                 /* send prompt and info  */
    blkno = 0x01;                                /* set block # to 1  */
    bflag = 0x01;                                /* set flag to get address from block 1  */
    do {
        Put_Chr ('C');                           /* "C" start with CRC mode 
                                                     send it */
        retry2 = 0xff;                           /* set loop counter for ~3 sec delay  */
        crc = 0x00;
        crch = 0x00;                             /* init CRC value  */
    } while (!GetByte (&rx_char));

    while (True) {
        /* quitting? */
        switch (rx_char) {
        case SOH:
            break_to_badcrc = False;

            for (i = 0x00; i < 0x84; i++) {
                retry2 = 0xff;                   /* 3 sec window to receive characters  */

                /* get next character */
                if (!GetByte (&rx_char)) {
                    break_to_badcrc = True;
                    break;
                }
                Rbuff [i] = rx_char;             /* good char, save it in the rcv buffer  */
            }

            if (break_to_badcrc) {
                Flush ();                        /* flush the input port  */
                Put_Chr (NAK);                   /* send NAK to resend block  */
            } else if (Rbuff [0] == blkno) {
                /* 1's comp of block #
                   compare with expected 1's comp of block # */
                if ((Rbuff [0] ^ 0xff) != Rbuff [0x1]) {
                    Print_Err ();                /* Unexpected block number - abort  */
                    Flush ();                    /* mismatched - flush buffer and then do rts  */
                    return;
                }
                CalcCRC ();                      /* calc CRC  */

                /* get hi CRC from buffer
                   compare to calculated hi CRC
                   get lo CRC from buffer
                   compare to calculated lo CRC */
                if (Rbuff [0x82] == crch && Rbuff [0x83] == crc) {
                    i = 0x02;

                    /* get the block number
                       1st block?
                       is it really block 1, not block 257, 513 etc. */
                    if (blkno == 0x01 && bflag != 0) {
                        ptr = Rbuff [0x02];      /* get target address from 1st 2 bytes of blk 1 
                                                     save lo address */
                        ptrh = Rbuff [0x3];      /* get hi address 
                                                     save it */
                        i = 0x4;                 /* point to first byte of data  */
                        bflag--;                 /* set the flag so we won't get another address  */
                    }

                    do {
                        **(unsigned char **) ((char *) 0x00 + (long) &ptr) = Rbuff [i];
                                                 /* get data byte from buffer 
                                                     save to target */
                        if (++ptr == 0)
                            ptrh++;              /* adjust high address for page crossing  */
                    } while (++i != 0x82);

                    blkno++;                     /* done.  Inc the block #  */
                    Put_Chr (ACK);               /* send ACK  */

                } else {
                    Flush ();                    /* flush the input port  */
                    Put_Chr (NAK);               /* send NAK to resend block  */
                }
            } else {
                Print_Err ();                    /* Unexpected block number - abort  */
                Flush ();                        /* mismatched - flush buffer and then do rts  */
                return;
            }

            break;

        case EOT:
            Put_Chr (ACK);                       /* last block, send ACK and exit.  */
            Flush ();                            /* get leftover characters, if any  */
            Print_Good ();
            return;

        case ESC:
            return;

        default:
            Flush ();                            /* flush the input port  */
            Put_Chr (NAK);                       /* send NAK to resend block  */
            break;
        }

        do {
            retry2 = 0xff;                       /* set loop counter for ~3 sec delay  */
        } while (!GetByte (&rx_char));
    }

    Put_Chr (ACK);                               /* last block, send ACK and exit.  */
    Flush ();                                    /* get leftover characters, if any  */
    Print_Good ();
}


/*
*************************************************************************
* Get_Chr                                                               *
*************************************************************************
*
* input chr from ACIA (no waiting)
*
* Parameters:
*
*    unsigned char *rx_char                         [Originally in A; Out]
*
* Result:
*
*    Boolean                                        [Originally condition CS]
*/
Boolean Get_Chr (unsigned char *rx_char)
{
    Boolean result;                              /* [Originally condition CC] */

    result = True;                               /* no chr present  */
    *rx_char = ACIA_Status & 0x08;               /* get Serial port status 
                                                     mask rcvr full bit */
    if (*rx_char != 0) {
        *rx_char = ACIA_Data;                    /* else get chr  */
        result = False;                          /* and set the Carry Flag  */
    }
    return !result;
}


/*
*************************************************************************
* Put_Chr                                                               *
*************************************************************************
*
* output to OutPut Port
*
* Parameters:
*
*    unsigned char a                                [Originally in A; In]
*/
static void Put_Chr (unsigned char a)
{
    while ((ACIA_Status & 0x10) == 0)
        ;
    ACIA_Data = a;                               /* put character to Port  */
}


/*
*************************************************************************
* GetByte                                                               *
*************************************************************************
*
*
* subroutines
*
* Parameters:
*
*    unsigned char *rx_char                         [Originally in A; Out]
*
* Result:
*
*    Boolean                                        [Originally condition CS]
*/
Boolean GetByte (unsigned char *rx_char)
{
    retry = 0x00;                                /* wait for chr input and cycle timing loop 
                                                     set low value of timing loop */
    do {
        /* get chr from serial port, don't wait */
        if (Get_Chr (rx_char))
            return True;
    } while (--retry != 0 || --retry2 != 0);

    return False;
}


/*
*************************************************************************
* Flush                                                                 *
*************************************************************************
*/
static void Flush (void)
{
    unsigned char rx_char;                       /* [Originally in A] */

    do {
        retry2 = 0x70;                           /* flush receive buffer 
                                                     flush until empty for ~1 sec. */
    } while (GetByte (&rx_char));

}


/*
*************************************************************************
* PrintMsg                                                              *
*************************************************************************
*/
static void PrintMsg (void)
{
    unsigned char i;                             /* [Originally in X] */

    i = 0x00;                                    /* PRINT starting message  */
    do {
        if (Msg [i] == 0)
            break;
        Put_Chr (Msg [i]);
    } while (++i != 0);

}


/*
*************************************************************************
* Print_Err                                                             *
*************************************************************************
*/
static void Print_Err (void)
{
    unsigned char i;                             /* [Originally in X] */

    i = 0x00;                                    /* PRINT Error message  */
    do {
        if (ErrMsg [i] == 0)
            break;
        Put_Chr (ErrMsg [i]);
    } while (++i != 0);

}


/*
*************************************************************************
* Print_Good                                                            *
*************************************************************************
*/
static void Print_Good (void)
{
    unsigned char i;                             /* [Originally in X] */

    i = 0x00;                                    /* PRINT Good Transfer message  */
    do {
        if (GoodMsg [i] == 0)
            break;
        Put_Chr (GoodMsg [i]);
    } while (++i != 0);

}


/*
*************************************************************************
* CalcCRC                                                               *
*************************************************************************
*
*
*  CRC subroutines
*/
static void CalcCRC (void)
{
    unsigned char i;                             /* [Originally in Y] */
    unsigned char x;                             /* [Originally in X] */

    crc = 0x00;                                  /* yes, calculate the CRC for the 128 bytes  */
    crch = 0x00;
    i = 0x02;
    while (i != 0x82) {
        x = Rbuff [i++] ^ crch;                  /* Quick CRC computation with lookup tables 
                                                     updates the two bytes at crc & crc+1 */
        crch = crc ^ crchi [x];                  /* with the byte send in the "A" register  */
        crc = crclo [x];
    }
}