/*******************************************************************************
|
/*******************************************************************************
|
********************************************************************************
|
********************************************************************************
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
//
|
//
|
// Copyright 2013 by Michael A. Morris, dba M. A. Morris & Associates
|
// Copyright 2013 by Michael A. Morris, dba M. A. Morris & Associates
|
//
|
//
|
// All rights reserved. The source code contained herein is publicly released
|
// 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
|
// 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
|
// this source code may be reproduced or transmitted in any form or by any
|
// means, electronic or mechanical, including photocopying, recording, or any
|
// means, electronic or mechanical, including photocopying, recording, or any
|
// information storage and retrieval system in violation of the license under
|
// information storage and retrieval system in violation of the license under
|
// which the source code is released.
|
// which the source code is released.
|
//
|
//
|
// The source code contained herein is free; it may be redistributed and/or
|
// 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
|
// 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
|
// License as published by the Free Software Foundation; either version 2.1 of
|
// the GNU Lesser General Public License, or any later version.
|
// the GNU Lesser General Public License, or any later version.
|
//
|
//
|
// The source code contained herein is freely released WITHOUT ANY WARRANTY;
|
// The source code contained herein is freely released WITHOUT ANY WARRANTY;
|
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
// PARTICULAR PURPOSE. (Refer to the GNU Lesser General Public License for
|
// PARTICULAR PURPOSE. (Refer to the GNU Lesser General Public License for
|
// more details.)
|
// more details.)
|
//
|
//
|
// A copy of the GNU Lesser General Public License should have been received
|
// 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
|
// along with the source code contained herein; if not, a copy can be obtained
|
// by writing to:
|
// by writing to:
|
//
|
//
|
// Free Software Foundation, Inc.
|
// Free Software Foundation, Inc.
|
// 51 Franklin Street, Fifth Floor
|
// 51 Franklin Street, Fifth Floor
|
// Boston, MA 02110-1301 USA
|
// Boston, MA 02110-1301 USA
|
//
|
//
|
// Further, no use of this source code is permitted in any form or means
|
// Further, no use of this source code is permitted in any form or means
|
// without inclusion of this banner prominently in any derived works.
|
// without inclusion of this banner prominently in any derived works.
|
//
|
//
|
// Michael A. Morris
|
// Michael A. Morris
|
// Huntsville, AL
|
// Huntsville, AL
|
//
|
//
|
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
********************************************************************************
|
********************************************************************************
|
*******************************************************************************/
|
*******************************************************************************/
|
|
|
/*******************************************************************************
|
/*******************************************************************************
|
********************************************************************************
|
********************************************************************************
|
|
|
This utility is designed to function as a filter program to translate an Intel
|
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
|
Hex programming file into a MEM file compatible with Xilinx's Data2MEM utility
|
program.
|
program.
|
|
|
It expects an Intel Hex file generated by the Microchip MPLAB toolsuite to be
|
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.
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
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
|
word nibbles, each 12-bit M16C5x instruction can be represented as a Verilog
|
vector in the following manner:
|
vector in the following manner:
|
|
|
{I[7:4], I[3:0], 4'b0000, I[11:8]}
|
{I[7:4], I[3:0], 4'b0000, I[11:8]}
|
|
|
For the Xilinx Data2MEM utility, in the block RAM configuration of the M16C5x
|
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
|
program memory, the output order of these nibbles to stdout is least
|
significant nibble to most significant nibble. Thus, the output order of the
|
significant nibble to most significant nibble. Thus, the output order of the
|
ASCII Hex characters representing the instruction word nibbles is: 1, 0, 3.
|
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
|
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
|
characters read from a data record of the Intel Hex programming file, the
|
utility only emits three characters. Each instruction word (3 characters) is
|
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
|
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.
|
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
|
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
|
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
|
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
|
instruction memory address space, these records are ignored by this utility
|
program. Similarly, the utility ignores records of type "01". Thus, the
|
program. Similarly, the utility ignores records of type "01". Thus, the
|
utility only outputs emits a MEM-compatible address for records of type "00".
|
utility only outputs emits a MEM-compatible address for records of type "00".
|
|
|
********************************************************************************
|
********************************************************************************
|
Revision History
|
Revision History
|
|
|
1.00 13G18 MAM Initial File Creation
|
1.00 13G18 MAM Initial File Creation
|
|
|
1.01 13G19 MAM Added description and license header to file.
|
1.01 13G19 MAM Added description and license header to file.
|
|
|
1.10 13G19 MAM Made several corrections: (1) record length changed
|
1.10 13G19 MAM Made several corrections: (1) record length changed
|
to instructions instead of bytes; (2) address output
|
to instructions instead of bytes; (2) address output
|
is 1.5 bytes per instruction. Also, added check to
|
is 1.5 bytes per instruction. Also, added check to
|
ensure address falls on byte boundary. Thus, if
|
ensure address falls on byte boundary. Thus, if
|
address after multiplying by 3 is even, then it is
|
address after multiplying by 3 is even, then it is
|
divided by 2 and emitted on a line by itself. If it
|
divided by 2 and emitted on a line by itself. If it
|
is odd, then 2 is subtracted before dividing the
|
is odd, then 2 is subtracted before dividing the
|
resultant by 2. After emitting this modified address
|
resultant by 2. After emitting this modified address
|
a three character (1.5 bytes) pad is emitted before
|
a three character (1.5 bytes) pad is emitted before
|
the data in the record. (This situation generally
|
the data in the record. (This situation generally
|
occurs when emitting the reset vectors, but may
|
occurs when emitting the reset vectors, but may
|
occur in other situations.)
|
occur in other situations.)
|
|
|
********************************************************************************
|
********************************************************************************
|
*******************************************************************************/
|
*******************************************************************************/
|
|
|
#include
|
#include
|
#include
|
#include
|
#include
|
#include
|
|
|
int ahtoi(char ch)
|
int ahtoi(char ch)
|
{
|
{
|
int tmp;
|
int tmp;
|
|
|
tmp = toupper(ch);
|
tmp = toupper(ch);
|
|
|
tmp = (ch - '0');
|
tmp = (ch - '0');
|
if(tmp > 9) tmp = (tmp - 7);
|
if(tmp > 9) tmp = (tmp - 7);
|
|
|
return tmp;
|
return tmp;
|
}
|
}
|
|
|
void main(void)
|
void main(void)
|
{
|
{
|
char ch;
|
char ch;
|
int i = 0;
|
int i = 0;
|
int j = 0;
|
int j = 0;
|
char state = 0;
|
char state = 0;
|
|
|
int rlen = 0;
|
int rlen = 0;
|
int radd = 0;
|
int radd = 0;
|
int rtyp = 0;
|
int rtyp = 0;
|
char rdat[4];
|
char rdat[4];
|
|
|
while(!feof(stdin)) {
|
while(!feof(stdin)) {
|
|
|
ch = fgetc(stdin);
|
ch = fgetc(stdin);
|
|
|
switch(state) {
|
switch(state) {
|
case 0 : // Find start of record
|
case 0 : // Find start of record
|
|
|
if(ch == ':') { // Read record length - 2 chars
|
if(ch == ':') { // Read record length - 2 chars
|
i = 2;
|
i = 2;
|
j = 0;
|
j = 0;
|
rlen = 0;
|
rlen = 0;
|
state = 1;
|
state = 1;
|
}
|
}
|
|
|
break;
|
break;
|
|
|
case 1 : // Read and convert record length field
|
case 1 : // Read and convert record length field
|
|
|
rlen = (rlen << 4) + ahtoi(ch);
|
rlen = (rlen << 4) + ahtoi(ch);
|
|
|
i -= 1;
|
i -= 1;
|
|
|
if(i == 0) { // Capture record address field
|
if(i == 0) { // Capture record address field
|
i = 4;
|
i = 4;
|
j = 0;
|
j = 0;
|
rlen = rlen / 2;
|
rlen = rlen / 2;
|
radd = 0;
|
radd = 0;
|
state = 2;
|
state = 2;
|
}
|
}
|
|
|
break;
|
break;
|
|
|
case 2 : // Read and convert record address field
|
case 2 : // Read and convert record address field
|
|
|
radd = (radd << 4) + ahtoi(ch);
|
radd = (radd << 4) + ahtoi(ch);
|
|
|
i -= 1;
|
i -= 1;
|
j += 1;
|
j += 1;
|
|
|
if(i == 0) { // Read record type
|
if(i == 0) { // Read record type
|
i = 2; // read two (2) chars
|
i = 2; // read two (2) chars
|
j = 0;
|
j = 0;
|
|
|
radd = radd / 2;
|
radd = radd / 2;
|
|
|
rtyp = 0;
|
rtyp = 0;
|
state = 3;
|
state = 3;
|
}
|
}
|
|
|
break;
|
break;
|
|
|
case 3 : // Read and convert record type
|
case 3 : // Read and convert record type
|
|
|
rtyp = (rtyp << 4) + ahtoi(ch); // Convert to integer
|
rtyp = (rtyp << 4) + ahtoi(ch); // Convert to integer
|
|
|
i -= 1;
|
i -= 1;
|
|
|
if(i == 0) { // ((rtype) ? 0 : 4)
|
if(i == 0) { // ((rtype) ? 0 : 4)
|
i = 4;
|
i = 4;
|
j = 0;
|
j = 0;
|
|
|
if(rtyp == 0) { // Read and print data records
|
if(rtyp == 0) { // Read and print data records
|
radd = (radd * 3);
|
radd = (radd * 3);
|
if(radd & 1) {
|
if(radd & 1) {
|
radd = (radd - 2) / 2; // emit address with padding
|
radd = (radd - 2) / 2; // emit address with padding
|
fprintf(stdout, "@%04X\n000\n", radd);
|
fprintf(stdout, "@%04X\n000\n", radd);
|
} else {
|
} else {
|
radd = radd / 2; // 1.5 bytes per instruction
|
radd = radd / 2; // 1.5 bytes per instruction
|
fprintf(stdout, "@%04X\n", radd); // emit address
|
fprintf(stdout, "@%04X\n", radd); // emit address
|
}
|
}
|
state = 4;
|
state = 4;
|
} else { // Skip to next record or EOF
|
} else { // Skip to next record or EOF
|
state = 0;
|
state = 0;
|
}
|
}
|
}
|
}
|
|
|
break;
|
break;
|
|
|
case 4 : // Read and output sorted data - 4 chars
|
case 4 : // Read and output sorted data - 4 chars
|
|
|
rdat[j] = ch;
|
rdat[j] = ch;
|
|
|
i -= 1;
|
i -= 1;
|
j += 1;
|
j += 1;
|
|
|
if(i == 0) {
|
if(i == 0) {
|
i = 4;
|
i = 4;
|
j = 0;
|
j = 0;
|
|
|
fprintf(stdout, "%c%c%c\n", rdat[1], rdat[0], rdat[3]);
|
//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
|
rlen -= 1; // Decrement record length
|
|
|
if(rlen == 0) {
|
if(rlen == 0) {
|
state = 0; // End of data, skip to next record/EOF
|
state = 0; // End of data, skip to next record/EOF
|
} else {
|
} else {
|
state = 4; // Data available, read next data word
|
state = 4; // Data available, read next data word
|
}
|
}
|
}
|
}
|
|
|
break;
|
break;
|
|
|
default : break;
|
default : break;
|
}
|
}
|
}
|
}
|
|
|