OpenCores
URL https://opencores.org/ocsvn/m16c5x/m16c5x/trunk

Subversion Repositories m16c5x

[/] [m16c5x/] [trunk/] [Utils/] [IH2MEM.C] - Rev 3

Compare with Previous | Blame | View Log

/*******************************************************************************
********************************************************************************
////////////////////////////////////////////////////////////////////////////////
//
//  Copyright 2013 by Michael A. Morris, dba M. A. Morris & Associates
//
//  All rights reserved. The source code contained herein is publicly released
//  under the terms and conditions of the GNU Lesser Public License. No part of
//  this source code may be reproduced or transmitted in any form or by any
//  means, electronic or mechanical, including photocopying, recording, or any
//  information storage and retrieval system in violation of the license under
//  which the source code is released.
//
//  The source code contained herein is free; it may be redistributed and/or
//  modified in accordance with the terms of the GNU Lesser General Public
//  License as published by the Free Software Foundation; either version 2.1 of
//  the GNU Lesser General Public License, or any later version.
//
//  The source code contained herein is freely released WITHOUT ANY WARRANTY;
//  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
//  PARTICULAR PURPOSE. (Refer to the GNU Lesser General Public License for
//  more details.)
//
//  A copy of the GNU Lesser General Public License should have been received
//  along with the source code contained herein; if not, a copy can be obtained
//  by writing to:
//
//  Free Software Foundation, Inc.
//  51 Franklin Street, Fifth Floor
//  Boston, MA  02110-1301 USA
//
//  Further, no use of this source code is permitted in any form or means
//  without inclusion of this banner prominently in any derived works.
//
//  Michael A. Morris
//  Huntsville, AL
//
////////////////////////////////////////////////////////////////////////////////
********************************************************************************
*******************************************************************************/

/*******************************************************************************
********************************************************************************

This utility is designed to function as a filter program to translate an Intel
Hex programming file into a MEM file compatible with Xilinx's Data2MEM utility
program.

It expects an Intel Hex file generated by the Microchip MPLAB toolsuite to be
piped in on stdin, and it outputs its MEM-compatible output on stdout.

The M16C5x soft-core microcomputer for which this utility is designed has a
12-bit instruction width. The MPLAB Intel Hex output is byte-oriented, so it
outputs two 8-bit ASCII Hex characters for each 12-bit instruction word. The
least significant 8 bits are output first, and then that is followed by a
second 8 bit byte. The second byte holds the most significant 4 bits of the
instruction word in bits 3:0. The upper 4 bits of this second byte are set to
0 by MPLAB. Considering the MPLAB Intel Hex output as a stream of instruction
word nibbles, each 12-bit M16C5x instruction can be represented as a Verilog
vector in the following manner:

    {I[7:4], I[3:0], 4'b0000, I[11:8]}

For the Xilinx Data2MEM utility, in the block RAM configuration of the M16C5x
program memory, the output order of these nibbles to stdout is least
significant nibble to most significant nibble. Thus, the output order of the
ASCII Hex characters representing the instruction word nibbles is: 1, 0, 3.

This utility program is not intended to be general purpose. For every four
characters read from a data record of the Intel Hex programming file, the
utility only emits three characters. Each instruction word (3 characters) is
output on a separate line, although it's possible to emit the record address
and the instruction word data on a single line separated by spaces.

Furthermore, MPLAB's Intel Hex file format adheres to the 32-bit segmented
address format. The upper 16 bits of a data records address is provided by a
record having a type of "04". Because the M16C5x only supports a 4096 x 12
instruction memory address space, these records are ignored by this utility
program. Similarly, the utility ignores records of type "01". Thus, the
utility only outputs emits a MEM-compatible address for records of type "00".

********************************************************************************
Revision History

    1.00    13G18   MAM     Initial File Creation

    1.01    13G19   MAM     Added description and license header to file.

    1.10    13G19   MAM     Made several corrections: (1) record length changed
                            to instructions instead of bytes; (2) address output
                            is 1.5 bytes per instruction. Also, added check to
                            ensure address falls on byte boundary. Thus, if
                            address after multiplying by 3 is even, then it is
                            divided by 2 and emitted on a line by itself. If it
                            is odd, then 2 is subtracted before dividing the
                            resultant by 2. After emitting this modified address
                            a three character (1.5 bytes) pad is emitted before
                            the data in the record. (This situation generally
                            occurs when emitting the reset vectors, but may
                            occur in other situations.)

********************************************************************************
*******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int ahtoi(char ch)
{
    int tmp;

    tmp = toupper(ch);

    tmp = (ch - '0');
    if(tmp > 9) tmp = (tmp - 7);

    return tmp;
}

void main(void)
{
    char ch;
    int  i = 0;
    int  j = 0;
    char state = 0;

    int  rlen = 0;
    int  radd = 0;
    int  rtyp = 0;
    char rdat[4];

    while(!feof(stdin)) {

        ch = fgetc(stdin);

        switch(state) {
           case 0 :                     // Find start of record

                if(ch == ':') {         // Read record length - 2 chars
                     i = 2;
                     j = 0;
                     rlen  = 0;
                     state = 1;
                }

                break;

           case 1 :                     // Read and convert record length field

                rlen = (rlen << 4) + ahtoi(ch);

                i -= 1;

                if(i == 0) {            // Capture record address field
                     i = 4;
                     j = 0;
                     rlen  = rlen / 2;
                     radd  = 0;
                     state = 2;
                }

                break;

           case 2 :                     // Read and convert record address field

                radd = (radd << 4) + ahtoi(ch);

                i -= 1;
                j += 1;

                if(i == 0) {            // Read record type
                     i = 2;             // read two (2) chars
                     j = 0;

                     radd = radd / 2;

                     rtyp  = 0;
                     state = 3;
                }

                break;

           case 3 :                     // Read and convert record type

                rtyp = (rtyp << 4) + ahtoi(ch); // Convert to integer

                i -= 1;

                if(i == 0) {            // ((rtype) ? 0 : 4)
                     i = 4;
                     j = 0;

                     if(rtyp == 0) {    // Read and print data records
                         radd = (radd * 3);
                         if(radd & 1) {
                            radd = (radd - 2) / 2; // emit address with padding
                            fprintf(stdout, "@%04X\n000\n", radd);
                         } else {
                            radd = radd / 2;     // 1.5 bytes per instruction
                            fprintf(stdout, "@%04X\n", radd);    // emit address
                         }
                         state = 4;
                     } else {           // Skip to next record or EOF
                         state = 0;
                     }
                }

                break;

           case 4 :                     // Read and output sorted data - 4 chars

                rdat[j] = ch;

                i -= 1;
                j += 1;

                if(i == 0) {
                     i = 4;
                     j = 0;

                     //fprintf(stdout, "%c%c%c\n", rdat[1], rdat[0], rdat[3]);
                     fprintf(stdout, "%c%c%c\n", rdat[3], rdat[0], rdat[1]);

                     rlen -= 1;      // Decrement record length

                     if(rlen == 0) {
                         state = 0;  // End of data, skip to next record/EOF
                     } else {
                         state = 4;  // Data available, read next data word
                     }
                }

                break;

           default : break;
        }
    }
}

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.