/* * (C) Copyright 2015 Leo C. * * SPDX-License-Identifier: GPL-2.0+ */ #include "common.h" #include #include #include #include "command.h" #include "con-utils.h" #include "z80-if.h" //#include "debug.h" typedef enum { IHX_OK, IHX_BROKEN, IHX_CHKSUMERR } ihx_rstat_t; typedef struct { ihx_rstat_t status; int8_t type; uint8_t len; uint16_t address; uint8_t *data; } ihex_t; static int get_hexdigit(void) { int c; c = toupper(my_getchar(1)); if (isxdigit(c)) { c -= '0'; if (c > 9) c -= ('A' - '0' - 10); return c; } else return -1; } static int get_hexbyte(void) { uint8_t i,j; if ((i = (uint8_t) get_hexdigit()) < 0x10) if ((j = (uint8_t) get_hexdigit()) < 0x10) { return (i<<4) + j; } return -1; } static ihex_t ihex_get_record() { int i; uint8_t sum, c; ihex_t rec = { IHX_BROKEN, 0, 0, 0, 0 }; while ((c = my_getchar(0)) != ':') if (c == 0x03) return rec; if ((i = get_hexbyte()) < 0) /* Start code */ return rec; sum = i; rec.len = i; if ((i = get_hexbyte()) < 0) /* Byte Count */ return rec; sum += i; rec.address = i * 256; if ((i = get_hexbyte()) < 0) /* Address */ return rec; sum += i; rec.address += i; if ((i = get_hexbyte()) < 0) /* Record type */ return rec; sum += i; rec.type = i; if (rec.len) { /* Record Data */ uint8_t *p; int k; if ((rec.data = malloc(rec.len)) == 0) return rec; for (p=rec.data, k=rec.len; k; k--) { if ((i = get_hexbyte()) < 0) break; sum += i; *p++ = i; } if (k) { free(rec.data); rec.data = 0; return rec; } } if ((i = get_hexbyte()) < 0) /* Check sum */ return rec; sum += i; if (sum) { free(rec.data); rec.data = 0; rec.status = IHX_CHKSUMERR; } else rec.status = IHX_OK; return rec; } command_ret_t do_loadihex(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { long offset = 0; uint32_t base_address = 0; uint32_t address_low = 0xffffffff; uint32_t address_high = 0; bool done = false; command_ret_t rcode = CMD_RET_FAILURE; ihex_t rec; (void) cmdtp; (void) flag; if (argc > 1) offset = strtol(argv[1], NULL, 16); while (!done) { rec = ihex_get_record(); if (rec.status == IHX_OK) { switch (rec.type) { case 0: /* Data record */ if (rec.len) { uint32_t addr = base_address + rec.address + offset; if (addr < address_low) address_low = addr; if (addr+rec.len > address_high) address_high = addr + rec.len; z80_bus_cmd(Request); z80_write_block(rec.data, /* src */ addr, /* dest */ rec.len); /* len */ z80_bus_cmd(Release); } continue; break; case 1: /* EOF record */ done = true; break; case 2: /* Extended Segment Address Record */ base_address = ((rec.data[0] << 8) + rec.data[1]) << 4; continue; break; case 4: /* Extended Linear Address Record */ base_address = (uint32_t)((rec.data[0] << 8) + rec.data[1]) << 16; continue; break; case 3: /* Start Segment Address Record (ignored)*/ case 5: /* Start Linear Address Record (ignored)*/ continue; break; } } else done = true; } switch (rec.status) { case IHX_OK: rcode = CMD_RET_SUCCESS; break; case IHX_BROKEN: case IHX_CHKSUMERR: printf_P(PSTR("Broken Hex Record or loading interrupted!\n")); break; } printf_P(PSTR("Data loaded - ")); if (address_low >= address_high) printf_P(PSTR("None.\n")); else printf_P(PSTR("low: 0x%.5lX high: 0x%.5lX\n"), address_low, address_high); return rcode; }