1 |
2 |
MichaelA |
/*******************************************************************************
|
2 |
|
|
********************************************************************************
|
3 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
4 |
|
|
//
|
5 |
|
|
// Copyright 2013 by Michael A. Morris, dba M. A. Morris & Associates
|
6 |
|
|
//
|
7 |
|
|
// All rights reserved. The source code contained herein is publicly released
|
8 |
|
|
// under the terms and conditions of the GNU Lesser Public License. No part of
|
9 |
|
|
// this source code may be reproduced or transmitted in any form or by any
|
10 |
|
|
// means, electronic or mechanical, including photocopying, recording, or any
|
11 |
|
|
// information storage and retrieval system in violation of the license under
|
12 |
|
|
// which the source code is released.
|
13 |
|
|
//
|
14 |
|
|
// The source code contained herein is free; it may be redistributed and/or
|
15 |
|
|
// modified in accordance with the terms of the GNU Lesser General Public
|
16 |
|
|
// License as published by the Free Software Foundation; either version 2.1 of
|
17 |
|
|
// the GNU Lesser General Public License, or any later version.
|
18 |
|
|
//
|
19 |
|
|
// The source code contained herein is freely released WITHOUT ANY WARRANTY;
|
20 |
|
|
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
21 |
|
|
// PARTICULAR PURPOSE. (Refer to the GNU Lesser General Public License for
|
22 |
|
|
// more details.)
|
23 |
|
|
//
|
24 |
|
|
// A copy of the GNU Lesser General Public License should have been received
|
25 |
|
|
// along with the source code contained herein; if not, a copy can be obtained
|
26 |
|
|
// by writing to:
|
27 |
|
|
//
|
28 |
|
|
// Free Software Foundation, Inc.
|
29 |
|
|
// 51 Franklin Street, Fifth Floor
|
30 |
|
|
// Boston, MA 02110-1301 USA
|
31 |
|
|
//
|
32 |
|
|
// Further, no use of this source code is permitted in any form or means
|
33 |
|
|
// without inclusion of this banner prominently in any derived works.
|
34 |
|
|
//
|
35 |
|
|
// Michael A. Morris
|
36 |
|
|
// Huntsville, AL
|
37 |
|
|
//
|
38 |
|
|
////////////////////////////////////////////////////////////////////////////////
|
39 |
|
|
********************************************************************************
|
40 |
|
|
*******************************************************************************/
|
41 |
|
|
|
42 |
|
|
/*******************************************************************************
|
43 |
|
|
********************************************************************************
|
44 |
|
|
|
45 |
|
|
This utility is designed to function as a filter program to translate an Intel
|
46 |
|
|
Hex programming file into a MEM file compatible with Xilinx's Data2MEM utility
|
47 |
|
|
program.
|
48 |
|
|
|
49 |
|
|
It expects an Intel Hex file generated by the Microchip MPLAB toolsuite to be
|
50 |
|
|
piped in on stdin, and it outputs its MEM-compatible output on stdout.
|
51 |
|
|
|
52 |
|
|
The M16C5x soft-core microcomputer for which this utility is designed has a
|
53 |
|
|
12-bit instruction width. The MPLAB Intel Hex output is byte-oriented, so it
|
54 |
|
|
outputs two 8-bit ASCII Hex characters for each 12-bit instruction word. The
|
55 |
|
|
least significant 8 bits are output first, and then that is followed by a
|
56 |
|
|
second 8 bit byte. The second byte holds the most significant 4 bits of the
|
57 |
|
|
instruction word in bits 3:0. The upper 4 bits of this second byte are set to
|
58 |
|
|
|
59 |
|
|
word nibbles, each 12-bit M16C5x instruction can be represented as a Verilog
|
60 |
|
|
vector in the following manner:
|
61 |
|
|
|
62 |
|
|
{I[7:4], I[3:0], 4'b0000, I[11:8]}
|
63 |
|
|
|
64 |
|
|
For the Xilinx Data2MEM utility, in the block RAM configuration of the M16C5x
|
65 |
|
|
program memory, the output order of these nibbles to stdout is least
|
66 |
|
|
significant nibble to most significant nibble. Thus, the output order of the
|
67 |
|
|
ASCII Hex characters representing the instruction word nibbles is: 1, 0, 3.
|
68 |
|
|
|
69 |
|
|
This utility program is not intended to be general purpose. For every four
|
70 |
|
|
characters read from a data record of the Intel Hex programming file, the
|
71 |
|
|
utility only emits three characters. Each instruction word (3 characters) is
|
72 |
|
|
output on a separate line, although it's possible to emit the record address
|
73 |
|
|
and the instruction word data on a single line separated by spaces.
|
74 |
|
|
|
75 |
|
|
Furthermore, MPLAB's Intel Hex file format adheres to the 32-bit segmented
|
76 |
|
|
address format. The upper 16 bits of a data records address is provided by a
|
77 |
|
|
record having a type of "04". Because the M16C5x only supports a 4096 x 12
|
78 |
|
|
instruction memory address space, these records are ignored by this utility
|
79 |
|
|
program. Similarly, the utility ignores records of type "01". Thus, the
|
80 |
|
|
utility only outputs emits a MEM-compatible address for records of type "00".
|
81 |
|
|
|
82 |
|
|
********************************************************************************
|
83 |
|
|
Revision History
|
84 |
|
|
|
85 |
|
|
1.00 13G18 MAM Initial File Creation
|
86 |
|
|
|
87 |
|
|
1.01 13G19 MAM Added description and license header to file.
|
88 |
|
|
|
89 |
|
|
1.10 13G19 MAM Made several corrections: (1) record length changed
|
90 |
|
|
to instructions instead of bytes; (2) address output
|
91 |
|
|
is 1.5 bytes per instruction. Also, added check to
|
92 |
|
|
ensure address falls on byte boundary. Thus, if
|
93 |
|
|
address after multiplying by 3 is even, then it is
|
94 |
|
|
divided by 2 and emitted on a line by itself. If it
|
95 |
|
|
is odd, then 2 is subtracted before dividing the
|
96 |
|
|
resultant by 2. After emitting this modified address
|
97 |
|
|
a three character (1.5 bytes) pad is emitted before
|
98 |
|
|
the data in the record. (This situation generally
|
99 |
|
|
occurs when emitting the reset vectors, but may
|
100 |
|
|
occur in other situations.)
|
101 |
|
|
|
102 |
|
|
********************************************************************************
|
103 |
|
|
*******************************************************************************/
|
104 |
|
|
|
105 |
|
|
#include
|
106 |
|
|
#include
|
107 |
|
|
#include
|
108 |
|
|
|
109 |
|
|
int ahtoi(char ch)
|
110 |
|
|
{
|
111 |
|
|
int tmp;
|
112 |
|
|
|
113 |
|
|
tmp = toupper(ch);
|
114 |
|
|
|
115 |
|
|
tmp = (ch - '0');
|
116 |
|
|
if(tmp > 9) tmp = (tmp - 7);
|
117 |
|
|
|
118 |
|
|
return tmp;
|
119 |
|
|
}
|
120 |
|
|
|
121 |
|
|
void main(void)
|
122 |
|
|
{
|
123 |
|
|
char ch;
|
124 |
|
|
int i = 0;
|
125 |
|
|
int j = 0;
|
126 |
|
|
char state = 0;
|
127 |
|
|
|
128 |
|
|
int rlen = 0;
|
129 |
|
|
int radd = 0;
|
130 |
|
|
int rtyp = 0;
|
131 |
|
|
char rdat[4];
|
132 |
|
|
|
133 |
|
|
while(!feof(stdin)) {
|
134 |
|
|
|
135 |
|
|
ch = fgetc(stdin);
|
136 |
|
|
|
137 |
|
|
switch(state) {
|
138 |
|
|
case 0 : // Find start of record
|
139 |
|
|
|
140 |
|
|
if(ch == ':') { // Read record length - 2 chars
|
141 |
|
|
i = 2;
|
142 |
|
|
j = 0;
|
143 |
|
|
rlen = 0;
|
144 |
|
|
state = 1;
|
145 |
|
|
}
|
146 |
|
|
|
147 |
|
|
break;
|
148 |
|
|
|
149 |
|
|
case 1 : // Read and convert record length field
|
150 |
|
|
|
151 |
|
|
rlen = (rlen << 4) + ahtoi(ch);
|
152 |
|
|
|
153 |
|
|
i -= 1;
|
154 |
|
|
|
155 |
|
|
if(i == 0) { // Capture record address field
|
156 |
|
|
i = 4;
|
157 |
|
|
j = 0;
|
158 |
|
|
rlen = rlen / 2;
|
159 |
|
|
radd = 0;
|
160 |
|
|
state = 2;
|
161 |
|
|
}
|
162 |
|
|
|
163 |
|
|
break;
|
164 |
|
|
|
165 |
|
|
case 2 : // Read and convert record address field
|
166 |
|
|
|
167 |
|
|
radd = (radd << 4) + ahtoi(ch);
|
168 |
|
|
|
169 |
|
|
i -= 1;
|
170 |
|
|
j += 1;
|
171 |
|
|
|
172 |
|
|
if(i == 0) { // Read record type
|
173 |
|
|
i = 2; // read two (2) chars
|
174 |
|
|
j = 0;
|
175 |
|
|
|
176 |
|
|
radd = radd / 2;
|
177 |
|
|
|
178 |
|
|
rtyp = 0;
|
179 |
|
|
state = 3;
|
180 |
|
|
}
|
181 |
|
|
|
182 |
|
|
break;
|
183 |
|
|
|
184 |
|
|
case 3 : // Read and convert record type
|
185 |
|
|
|
186 |
|
|
rtyp = (rtyp << 4) + ahtoi(ch); // Convert to integer
|
187 |
|
|
|
188 |
|
|
i -= 1;
|
189 |
|
|
|
190 |
|
|
if(i == 0) { // ((rtype) ? 0 : 4)
|
191 |
|
|
i = 4;
|
192 |
|
|
j = 0;
|
193 |
|
|
|
194 |
|
|
if(rtyp == 0) { // Read and print data records
|
195 |
|
|
radd = (radd * 3);
|
196 |
|
|
if(radd & 1) {
|
197 |
|
|
radd = (radd - 2) / 2; // emit address with padding
|
198 |
|
|
fprintf(stdout, "@%04X\n000\n", radd);
|
199 |
|
|
} else {
|
200 |
|
|
radd = radd / 2; // 1.5 bytes per instruction
|
201 |
|
|
fprintf(stdout, "@%04X\n", radd); // emit address
|
202 |
|
|
}
|
203 |
|
|
state = 4;
|
204 |
|
|
} else { // Skip to next record or EOF
|
205 |
|
|
state = 0;
|
206 |
|
|
}
|
207 |
|
|
}
|
208 |
|
|
|
209 |
|
|
break;
|
210 |
|
|
|
211 |
|
|
case 4 : // Read and output sorted data - 4 chars
|
212 |
|
|
|
213 |
|
|
rdat[j] = ch;
|
214 |
|
|
|
215 |
|
|
i -= 1;
|
216 |
|
|
j += 1;
|
217 |
|
|
|
218 |
|
|
if(i == 0) {
|
219 |
|
|
i = 4;
|
220 |
|
|
j = 0;
|
221 |
|
|
|
222 |
3 |
MichaelA |
//fprintf(stdout, "%c%c%c\n", rdat[1], rdat[0], rdat[3]);
|
223 |
|
|
fprintf(stdout, "%c%c%c\n", rdat[3], rdat[0], rdat[1]);
|
224 |
2 |
MichaelA |
|
225 |
|
|
rlen -= 1; // Decrement record length
|
226 |
|
|
|
227 |
|
|
if(rlen == 0) {
|
228 |
|
|
state = 0; // End of data, skip to next record/EOF
|
229 |
|
|
} else {
|
230 |
|
|
state = 4; // Data available, read next data word
|
231 |
|
|
}
|
232 |
|
|
}
|
233 |
|
|
|
234 |
|
|
break;
|
235 |
|
|
|
236 |
|
|
default : break;
|
237 |
|
|
}
|
238 |
|
|
}
|
239 |
|
|
}
|