-
Notifications
You must be signed in to change notification settings - Fork 6
/
parse_ihex.c
166 lines (161 loc) · 4.5 KB
/
parse_ihex.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "memsim2.h"
static const char* errmsg = "Error in Intel hex file: ";
int
parse_ihex(FILE *file, uint8_t *buffer, int *min, int *max, long offset)
{
int ch;
*max = 0;
*min = INT_MAX;
int actual_size = 0;
int bytes_ignored = 0;
long long upper16 = 0;
long long segment = 0;
while (1)
{
int check;
int b;
int length;
int addr;
int type;
skip_white(file);
if (feof(file)) break;
ch = getc(file);
if (ch != ':')
{
fprintf(stderr, "%s':' expected\n", errmsg);
return -1;
}
check = 0;
length = get_hex2(file, &check);
if (length < 0)
{
fprintf(stderr, "%sillegal character in length field\n", errmsg);
return length;
}
addr = get_hex4(file, &check);
if (addr < 0)
{
fprintf(stderr, "%sillegal character in address field\n", errmsg);
return addr;
}
addr += segment;
addr += upper16;
type = get_hex2(file, &check);
if (type < 0)
{
fprintf(stderr, "%sillegal character in type field\n", errmsg);
return type;
}
if (type == 0)
{
for (b = 0; b < length; b++)
{
int v = get_hex2(file, &check);
if (v < 0)
{
fprintf(stderr, "%sillegal character in data field\n", errmsg);
return v;
}
if ((addr - offset) >= 0)
buffer[addr - offset] = v;
else
bytes_ignored++;
if (addr > *max) *max = addr;
if (addr < *min) *min = addr;
actual_size = *max - *min + 1;
addr++;
}
}
else if (type == 2)
{
// Type 2 Extended Segment address
if (length != 2)
{
fprintf(stderr, "Error: byte count 0x02 expected for Extended Segment Address field\n");
return -1;
}
segment = get_hex4(file, &check);
if (segment < 0)
{
fprintf(stderr, "%sillegal character in Extended Segment Address field\n", errmsg);
return segment;
}
segment = segment * 16;
upper16 = 0;
}
else if (type == 4)
{
// Type 4 Extended linear address
if (length != 2)
{
fprintf(stderr, "Error: byte count 0x02 expected for Extended Linear Address field\n");
return -1;
}
upper16 = get_hex4(file, &check);
if (upper16 < 0)
{
fprintf(stderr, "%sillegal character in Extended Linear Address field\n", errmsg);
return upper16;
}
upper16 = upper16 << 16;
segment = 0;
}
else if (type == 3)
{
// Type 3 Start Segment Address
if (length != 4)
{
fprintf(stderr, "Error: byte count 0x04 expected for Start Segment Address\n");
return -1;
}
long long int start = get_hex8(file, &check);
printf("Info: ignoring Start Segment address (CS:IP) %04llX\n", start);
}
else if (type == 5)
{
// Type 5 Start Linear Address
if (length != 4)
{
fprintf(stderr, "Error: byte count 0x04 expected for Start Linear Address\n");
return -1;
}
long long int start = get_hex8(file, &check);
printf("Info: ignoring Start Linear address (EIP) %04llX\n", start);
}
else if (type == 1)
{
break;
}
else
{
fprintf(stderr, "Error: Intel hex file with unsupported type %d entry\n", type);
return -4;
}
ch = get_hex2(file, &check);
if (ch < 0)
{
fprintf(stderr, "%sillegal character in checksum field\n", errmsg);
return ch;
}
if ((check & 0xFF) != 0)
{
fprintf(stderr, "%sWrong checksum\n", errmsg);
return -3;
}
}
printf("Info: Intel hex data from %04Xh - %04Xh = %d bytes\n", *min, *max, actual_size);
if (bytes_ignored) printf("Info: %d bytes outside storage area ignored\n", bytes_ignored);
if (!offset_given)
{
printf("Info: no offset specified, simulated data starts at %Xh\n", *min);
memmove(buffer, buffer + *min, actual_size);
memset(buffer + actual_size, 0, SIMMEMSIZE - actual_size);
}
return actual_size;
}