1 /* Read ".HEX" files and store it in memory
2 Copyright (C) 2001, 2002, 2003, 2004, 2005
3 Craig Franklin
4
5 This file is part of gputils.
6
7 gputils is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 gputils is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with gputils; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 #include "stdhdr.h"
23 #include "libgputils.h"
24
25 #define LINESIZ 520
26
27 static char linebuf[LINESIZ];
28 static char *linept;
29 static uint8_t checksum;
30 static FILE *infile;
31
32 /*------------------------------------------------------------------------------------------------*/
33
34 /* Converts a single ASCII character into a number. */
35
36 static uint8_t
_a2n(uint8_t Character)37 _a2n(uint8_t Character)
38 {
39 uint8_t number;
40
41 if (Character <= '9') {
42 number = Character - '0';
43 }
44 else {
45 /* Convert lower case to upper. */
46 Character &= ~('a' - 'A');
47 number = Character - ('A' - 10);
48 }
49 return number;
50 }
51
52 /*------------------------------------------------------------------------------------------------*/
53
54 static uint8_t
_readbyte(void)55 _readbyte(void)
56 {
57 uint8_t number;
58
59 linept++;
60 number = _a2n(*linept) << 4;
61 linept++;
62 number |= _a2n(*linept);
63
64 checksum += number;
65 return number;
66 }
67
68 /*------------------------------------------------------------------------------------------------*/
69
70 static uint16_t
_readword(void)71 _readword(void)
72 {
73 uint16_t number;
74
75 number = (uint16_t)_readbyte();
76 number |= (uint16_t)_readbyte() << 8;
77 return number;
78 }
79
80 /*------------------------------------------------------------------------------------------------*/
81
82 static uint16_t
_swapword(uint16_t Input)83 _swapword(uint16_t Input)
84 {
85 uint16_t number;
86
87 number = ((Input & 0xFF) << 8) | ((Input & 0xFF00) >> 8);
88 return number;
89 }
90
91 /*------------------------------------------------------------------------------------------------*/
92
93 hex_data_t *
gp_readhex(const char * File_name,MemBlock_t * M)94 gp_readhex(const char *File_name, MemBlock_t *M)
95 {
96 hex_data_t *info;
97 unsigned int length;
98 unsigned int address;
99 unsigned int type;
100 uint8_t byte;
101 unsigned int i;
102 unsigned int page;
103
104 info = GP_Malloc(sizeof(*info));
105 info->hex_format = INHX8M;
106 info->size = 0;
107 info->error = false;
108
109 /* Open the input file. */
110 if ((infile = fopen(File_name, "rt")) == NULL) {
111 perror(File_name);
112 exit(1);
113 }
114
115 /* Go to the beginning of the file. */
116 fseek(infile, 0L, SEEK_SET);
117
118 /* Set the line pointer to the beginning of the line buffer. */
119 linept = linebuf;
120
121 /* Read a line of data from the file, if NULL stop. */
122 while (fgets(linept, LINESIZ, infile) != NULL)
123 {
124 /* Set the line pointer to the beginning of the line buffer. */
125 linept = linebuf;
126
127 checksum = 0;
128
129 /* Fetch the number of bytes. */
130 length = _readbyte();
131 if (length == 0) {
132 fclose(infile);
133 return info;
134 }
135
136 /* Fetch the address. */
137 address = _swapword(_readword());
138
139 if (info->hex_format == INHX16) {
140 address *= 2;
141 length *= 2;
142 }
143
144 /* Read the type of record. */
145 type = _readbyte();
146
147 if (type == IHEX_RECTYPE_EXT_LIN_ADDR) {
148 if (info->hex_format == INHX16) {
149 printf("\nHex Format Error\n");
150 fclose(infile);
151 info->error = true;
152 return info;
153 }
154
155 /* INHX32 segment line. */
156 page = ((_readbyte() << 8) + _readbyte()) << 16;
157 info->hex_format = INHX32;
158 }
159 else {
160 /* Read the data (skipping last byte if at odd address). */
161 for (i = 0; i < length; ++i) {
162 byte = _readbyte();
163
164 if (info->hex_format == INHX16) {
165 gp_mem_b_put(M, page | ((address + i) ^ 1), byte, File_name, NULL);
166 }
167 else {
168 gp_mem_b_put(M, page | (address + i), byte, File_name, NULL);
169 }
170 }
171
172 info->size += length;
173 }
174
175 /* Read the checksum, data is thrown away. */
176 _readbyte();
177
178 if (checksum != 0) {
179 if (info->hex_format == INHX8M) {
180 /* First attempt at INHX8M failed, try INHX16. */
181 fseek(infile, 0L, SEEK_SET);
182 info->hex_format = INHX16;
183 info->size = 0;
184 /* Data in i_memory is trash. */
185 gp_mem_i_free(M);
186 M = gp_mem_i_create();
187 }
188 else {
189 printf("\nChecksum Error\n");
190 fclose(infile);
191 info->error = true;
192 return info;
193 }
194 }
195
196 /* Set the line pointer to the beginning of the line buffer. */
197 linept = linebuf;
198 }
199
200 fclose(infile);
201
202 return info;
203 }
204