fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 399 lines 7.2 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/lib/ihex.c * 7 * Created: 2004-06-23 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2004-2013 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include <stdlib.h> 24#include <stdio.h> 25 26#include "ihex.h" 27 28 29typedef struct { 30 unsigned char type; 31 unsigned char cnt; 32 unsigned short addr; 33 unsigned char data[256]; 34 unsigned char cksum; 35} record_t; 36 37 38#define IHEX_REC_DATA 0x00 39#define IHEX_REC_EOFR 0x01 40#define IHEX_REC_ESAR 0x02 41#define IHEX_REC_SSAR 0x03 42#define IHEX_REC_ELAR 0x04 43#define IHEX_REC_SLAR 0x05 44 45 46static 47int ihex_skip_line (FILE *fp) 48{ 49 int c; 50 51 while (1) { 52 c = fgetc (fp); 53 54 if (c == EOF) { 55 return (1); 56 } 57 58 if ((c == 0x0a) || (c == 0x0d)) { 59 return (0); 60 } 61 } 62 63 return (0); 64} 65 66static 67int ihex_get_hex8 (FILE *fp, unsigned char *val) 68{ 69 unsigned i; 70 int c; 71 72 *val = 0; 73 74 for (i = 0; i < 2; i++) { 75 c = fgetc (fp); 76 77 if ((c >= '0') && (c <= '9')) { 78 *val = (*val << 4) | (c - '0'); 79 } 80 else if ((c >= 'A') && (c <= 'F')) { 81 *val = (*val << 4) | (c - 'A' + 10); 82 } 83 else if ((c >= 'a') && (c <= 'f')) { 84 *val = (*val << 4) | (c - 'a' + 10); 85 } 86 else { 87 return (1); 88 } 89 } 90 91 return (0); 92} 93 94static 95unsigned char ihex_get_cksum (record_t *rec) 96{ 97 unsigned i; 98 unsigned char ck; 99 100 ck = rec->cnt & 0xff; 101 ck += rec->addr & 0xff; 102 ck += (rec->addr >> 8) & 0xff; 103 ck += rec->type & 0xff; 104 105 for (i = 0; i < rec->cnt; i++) { 106 ck += rec->data[i]; 107 } 108 109 ck = (~ck + 1) & 0xff; 110 111 return (ck); 112} 113 114static 115int ihex_get_record (FILE *fp, record_t *rec) 116{ 117 unsigned i; 118 int c; 119 unsigned char a1, a2; 120 121 while (1) { 122 c = fgetc (fp); 123 124 if (c == EOF) { 125 return (1); 126 } 127 128 if (c == ':') { 129 break; 130 } 131 132 if ((c != 0x0a) && (c != 0x0d)) { 133 ihex_skip_line (fp); 134 } 135 } 136 137 if (ihex_get_hex8 (fp, &rec->cnt)) { 138 return (1); 139 } 140 141 if (ihex_get_hex8 (fp, &a1) || ihex_get_hex8 (fp, &a2)) { 142 return (1); 143 } 144 145 rec->addr = (a1 << 8) | a2; 146 147 if (ihex_get_hex8 (fp, &rec->type)) { 148 return (1); 149 } 150 151 for (i = 0; i < rec->cnt; i++) { 152 if (ihex_get_hex8 (fp, &rec->data[i])) { 153 return (1); 154 } 155 } 156 157 if (ihex_get_hex8 (fp, &rec->cksum)) { 158 return (1); 159 } 160 161 ihex_skip_line (fp); 162 163 return (0); 164} 165 166 167static 168void ihex_set_hex8 (FILE *fp, unsigned char c) 169{ 170 int tmp; 171 172 tmp = (c >> 4) & 0x0f; 173 tmp += (tmp <= 9) ? '0' : ('A' - 10); 174 fputc (tmp, fp); 175 176 tmp = c & 0x0f; 177 tmp += (tmp <= 9) ? '0' : ('A' - 10); 178 fputc (tmp, fp); 179} 180 181static 182void ihex_set_record (FILE *fp, record_t *rec) 183{ 184 unsigned i; 185 186 rec->cksum = ihex_get_cksum (rec); 187 188 fprintf (fp, ":%02X%04X%02X", 189 (unsigned) rec->cnt, (unsigned) rec->addr & 0xffffU, (unsigned) rec->type 190 ); 191 192 for (i = 0; i < rec->cnt; i++) { 193 ihex_set_hex8 (fp, rec->data[i]); 194 } 195 196 ihex_set_hex8 (fp, rec->cksum); 197 198 fputs ("\n", fp); 199} 200 201static 202void ihex_set_esar (FILE *fp, unsigned seg) 203{ 204 record_t rec; 205 206 rec.type = IHEX_REC_ESAR; 207 rec.cnt = 2; 208 rec.addr = 0; 209 rec.data[0] = (seg >> 8) & 0xff; 210 rec.data[1] = seg & 0xff; 211 212 ihex_set_record (fp, &rec); 213} 214 215static 216void ihex_set_ulba (FILE *fp, unsigned long addr) 217{ 218 record_t rec; 219 220 rec.type = 0x04; 221 rec.cnt = 2; 222 rec.addr = 0; 223 rec.data[0] = (addr >> 24) & 0xff; 224 rec.data[1] = (addr >> 16) & 0xff; 225 226 ihex_set_record (fp, &rec); 227} 228 229static 230void ihex_set_end (FILE *fp) 231{ 232 record_t rec; 233 234 rec.type = 0x01; 235 rec.cnt = 0; 236 rec.addr = 0; 237 238 ihex_set_record (fp, &rec); 239} 240 241int ihex_load_fp (FILE *fp, void *ext, ihex_set_f set) 242{ 243 unsigned i; 244 unsigned mode; 245 unsigned long addr, ulba; 246 record_t rec; 247 248 mode = 0; 249 ulba = 0; 250 251 while (1) { 252 if (ihex_get_record (fp, &rec)) { 253 break; 254 } 255 256 if (rec.cksum != ihex_get_cksum (&rec)) { 257 return (1); 258 } 259 260 if (rec.type == IHEX_REC_EOFR) { 261 return (0); 262 } 263 else if (rec.type == IHEX_REC_ELAR) { 264 if (rec.cnt == 2) { 265 mode = 0; 266 ulba = (rec.data[0] << 8) | rec.data[1]; 267 ulba = ulba << 16; 268 } 269 else { 270 return (1); 271 } 272 } 273 else if (rec.type == IHEX_REC_ESAR) { 274 if (rec.cnt == 2) { 275 mode = 1; 276 ulba = (rec.data[0] << 8) | rec.data[1]; 277 ulba = ulba << 4; 278 } 279 else { 280 return (1); 281 } 282 } 283 else if (rec.type == IHEX_REC_DATA) { 284 addr = ulba + (rec.addr & 0xffffU); 285 286 for (i = 0; i < rec.cnt; i++) { 287 if (mode == 0) { 288 addr = ulba + rec.addr + i; 289 } 290 else { 291 addr = ulba + ((rec.addr + i) & 0xffffU); 292 } 293 294 set (ext, addr, rec.data[i]); 295 } 296 } 297 } 298 299 return (0); 300} 301 302int ihex_load (const char *fname, void *ext, ihex_set_f set) 303{ 304 int r; 305 FILE *fp; 306 307 fp = fopen (fname, "rb"); 308 if (fp == NULL) { 309 return (1); 310 } 311 312 r = ihex_load_fp (fp, ext, set); 313 314 fclose (fp); 315 316 return (r); 317} 318 319 320int ihex_save (FILE *fp, unsigned seg, unsigned ofs, unsigned long size, void *ext, ihex_get_f get) 321{ 322 unsigned i; 323 unsigned cnt; 324 unsigned short oldseg; 325 record_t rec; 326 327 oldseg = 0; 328 329 while (size > 0) { 330 if (seg != oldseg) { 331 ihex_set_esar (fp, seg); 332 oldseg = seg; 333 } 334 335 cnt = (size < 16) ? size : 16; 336 337 if (((ofs + cnt) & 0xffff) < ofs) { 338 cnt = -ofs & 0xffff; 339 } 340 341 rec.type = 0x00; 342 rec.addr = ofs; 343 rec.cnt = cnt; 344 345 for (i = 0; i < rec.cnt; i++) { 346 rec.data[i] = get (ext, ((unsigned long) seg << 4) + ofs); 347 348 ofs = (ofs + 1) & 0xffff; 349 } 350 351 ihex_set_record (fp, &rec); 352 353 if (ofs == 0) { 354 seg += 0x1000; 355 } 356 357 size -= rec.cnt; 358 } 359 360 return (0); 361} 362 363int ihex_save_linear (FILE *fp, unsigned long base, unsigned long size, void *ext, ihex_get_f get) 364{ 365 unsigned i; 366 unsigned long ulba, addr; 367 record_t rec; 368 369 ulba = 0; 370 addr = base; 371 372 while (size > 0) { 373 rec.type = 0x00; 374 rec.addr = addr & 0xffffU; 375 rec.cnt = (size < 16) ? size : 16; 376 377 for (i = 0; i < rec.cnt; i++) { 378 rec.data[i] = get (ext, addr + i); 379 } 380 381 if ((ulba & 0xffff0000UL) != (addr & 0xffff0000UL)) { 382 ihex_set_ulba (fp, addr); 383 ulba = addr & 0xffff0000UL; 384 } 385 386 ihex_set_record (fp, &rec); 387 388 addr += rec.cnt; 389 size -= rec.cnt; 390 } 391 392 return (0); 393} 394 395int ihex_save_done (FILE *fp) 396{ 397 ihex_set_end (fp); 398 return (0); 399}