scc 2025.09
SystemC components library
ihex_parser.cpp
1
2#include "ihex_parser.h"
3#include <array>
4#include <cstring>
5#include <stdbool.h>
6#include <stdint.h>
7
8// IHEX file parser state machine
9enum {
10 START_CODE_STATE = 0,
11 BYTE_COUNT_0_STATE = 1,
12 BYTE_COUNT_1_STATE = 2,
13 ADDR_0_STATE = 3,
14 ADDR_1_STATE = 4,
15 ADDR_2_STATE = 5,
16 ADDR_3_STATE = 6,
17 RECORD_TYPE_0_STATE = 7,
18 RECORD_TYPE_1_STATE = 8,
19 DATA_STATE = 9,
20 CHECKSUM_0_STATE = 10,
21 CHECKSUM_1_STATE = 11
22};
23enum record_type_e { DATA, END_OF_FILE, EXTENDED_SEGMENT_ADDRESS, START_SEGMENT_ADDRESS, EXTENDED_LINEAR_ADDRESS, START_LINEAR_ADDRESS };
24
25#define INVALID_HEX_CHAR 'x'
26
27namespace util {
28namespace {
29uint8_t hex2dec(uint8_t h) {
30 if(h >= '0' && h <= '9')
31 return h - '0';
32 else if(h >= 'A' && h <= 'F')
33 return h - 'A' + 0xA;
34 else if(h >= 'a' && h <= 'z')
35 return h - 'a' + 0xA;
36 else
37 return INVALID_HEX_CHAR;
38}
39} // namespace
40
41bool ihex_parser::parse(std::istream& is, std::function<bool(uint64_t, uint64_t, const uint8_t*)> cb) {
42 char c;
43 uint8_t i;
44 unsigned state{0};
45 uint16_t address_lo{0};
46 uint16_t address_hi{0};
47 std::array<uint8_t, IHEX_DATA_SIZE> data;
48 unsigned data_size_in_nibble{0};
49 uint8_t byte_count{0};
50 uint8_t record_type{DATA};
51 uint8_t calculated_cs{0}; // calculate checksum
52 uint8_t saved_high_nibble{0};
53 bool save_high_nibble{true};
54 bool ex_segment_addr_mode{false};
55 while(!is.eof()) {
56 is.get(c);
57 if(c == '\0')
58 return true;
59 if(state) {
60 if((i = hex2dec(c)) == INVALID_HEX_CHAR)
61 return false;
62 if(state <= CHECKSUM_1_STATE) {
63 if(save_high_nibble)
64 saved_high_nibble = i;
65 else
66 calculated_cs += (saved_high_nibble << 4) | i;
67 save_high_nibble = !save_high_nibble;
68 }
69 }
70 switch(state) {
71 case START_CODE_STATE:
72 calculated_cs = 0x00;
73 save_high_nibble = true;
74 if(c == '\r' || c == '\n') {
75 continue;
76 } else if(c == ':') {
77 byte_count = 0;
78 record_type = DATA;
79 address_lo = 0x0000;
80 memset(data.data(), 0, data.size());
81 data_size_in_nibble = 0;
82 calculated_cs = 0;
83 ++state;
84 } else
85 return false;
86 break;
87 case BYTE_COUNT_0_STATE:
88 case BYTE_COUNT_1_STATE:
89 byte_count = (byte_count << 4) | i;
90 ++state;
91 break;
92 case ADDR_0_STATE:
93 case ADDR_1_STATE:
94 case ADDR_2_STATE:
95 case ADDR_3_STATE:
96 address_lo = ((address_lo << 4) | i); // only alter lower 16-bit address
97 ++state;
98 break;
99 case RECORD_TYPE_0_STATE:
100 if(i != 0)
101 return false;
102 ++state;
103 break;
104 case RECORD_TYPE_1_STATE:
105 if(i > START_LINEAR_ADDRESS)
106 return false;
107 record_type = i;
108 if(byte_count == 0) {
109 state = CHECKSUM_0_STATE;
110 } else if(byte_count > sizeof(data))
111 return false;
112 else
113 ++state;
114 break;
115 case DATA_STATE: {
116 uint8_t b_index = data_size_in_nibble / 2;
117 data[b_index] = (data[b_index] << 4) | i;
118
119 ++data_size_in_nibble;
120 if((data_size_in_nibble / 2) >= byte_count)
121 ++state;
122 break;
123 }
124 case CHECKSUM_0_STATE:
125 ++state;
126 break;
127 case CHECKSUM_1_STATE:
128 if((byte_count << 1) != data_size_in_nibble) // Check whether byte count field match the data size
129 return false;
130 if(calculated_cs != 0x00)
131 return false;
132 if(record_type == EXTENDED_SEGMENT_ADDRESS) { // Set extended segment addresss
133 address_hi = ((uint16_t)data[0] << 8) | (data[1]);
134 ex_segment_addr_mode = true;
135 } else if(record_type == EXTENDED_LINEAR_ADDRESS) { // Set linear addresss
136 address_hi = ((uint16_t)data[0] << 8) | (data[1]);
137 ex_segment_addr_mode = false;
138 } else if(record_type == DATA && cb) {
139 uint64_t address = ex_segment_addr_mode ? (static_cast<uint32_t>(address_hi) << 4) + static_cast<uint32_t>(address_lo)
140 : (static_cast<uint32_t>(address_hi) << 16) | static_cast<uint32_t>(address_lo);
141 if(!cb(address, data_size_in_nibble >> 1, data.data()))
142 return false;
143 }
144 state = START_CODE_STATE;
145 break;
146 default:
147 return false;
148 }
149 }
150 return true;
151}
152} // namespace util
SCC common utilities.
Definition bit_field.h:30
static bool parse(std::istream &, std::function< bool(uint64_t, uint64_t, const uint8_t *)>)
Parses an IHEX file from the given input stream and invokes a callback function for each data record ...