URL
https://opencores.org/ocsvn/m16c5x/m16c5x/trunk
Subversion Repositories m16c5x
[/] [m16c5x/] [trunk/] [Utils/] [IH2MEM.C] - Rev 2
Go to most recent revision | 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]);
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;
}
}
}
Go to most recent revision | Compare with Previous | Blame | View Log