···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/lib/mhex.c *
77+ * Created: 2020-05-02 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2020 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#include <stdlib.h>
2424+#include <stdio.h>
2525+2626+#include "mhex.h"
2727+2828+2929+static
3030+int mhex_skip_line (FILE *fp)
3131+{
3232+ int c;
3333+3434+ while ((c = fgetc (fp)) != EOF) {
3535+ if ((c == 0x0a) || (c == 0x0d)) {
3636+ return (0);
3737+ }
3838+ }
3939+4040+ return (1);
4141+}
4242+4343+static
4444+unsigned mhex_get_cksum (unsigned addr, const unsigned char *buf, unsigned cnt)
4545+{
4646+ unsigned val;
4747+4848+ val = (addr & 0xff) + ((addr >> 8) & 0xff);
4949+ val += cnt & 0xff;
5050+5151+ while (cnt-- > 0) {
5252+ val += *(buf++) & 0xff;
5353+ }
5454+5555+ return (val & 0xffff);
5656+}
5757+5858+static
5959+int mhex_read_hex (FILE *fp, unsigned char *buf, unsigned cnt)
6060+{
6161+ int c;
6262+ unsigned i, j, s;
6363+6464+ cnt *= 2;
6565+6666+ for (i = 0; i < cnt; i++) {
6767+ if ((c = fgetc (fp)) == EOF) {
6868+ return (1);
6969+ }
7070+7171+ j = i >> 1;
7272+ s = (~i & 1) << 2;
7373+7474+ buf[j] &= 0xf0 << s;
7575+7676+ if ((c >= '0') && (c <= '9')) {
7777+ buf[j] |= (c - '0') << s;
7878+ }
7979+ else if ((c >= 'A') && (c <= 'F')) {
8080+ buf[j] |= (c - 'A' + 10) << s;
8181+ }
8282+ else if ((c >= 'a') && (c <= 'f')) {
8383+ buf[j] |= (c - 'a' + 10) << s;
8484+ }
8585+ else {
8686+ return (1);
8787+ }
8888+ }
8989+9090+ return (0);
9191+}
9292+9393+static
9494+int mhex_read_record (FILE *fp, unsigned *addr, unsigned char *buf, unsigned *cnt, int *check)
9595+{
9696+ int c;
9797+ unsigned ck;
9898+ unsigned char tmp[2];
9999+100100+ while ((c = fgetc (fp)) != ';') {
101101+ if (c == EOF) {
102102+ return (1);
103103+ }
104104+105105+ if ((c != 0x0a) && (c != 0x0d)) {
106106+ mhex_skip_line (fp);
107107+ }
108108+ }
109109+110110+ if (mhex_read_hex (fp, tmp, 1)) {
111111+ return (1);
112112+ }
113113+114114+ *cnt = tmp[0];
115115+116116+ if (mhex_read_hex (fp, tmp, 2)) {
117117+ return (1);
118118+ }
119119+120120+ *addr = ((tmp[0] & 0xff) << 8) | (tmp[1] & 0xff);
121121+122122+ if (mhex_read_hex (fp, buf, *cnt)) {
123123+ return (1);
124124+ }
125125+126126+ if (mhex_read_hex (fp, tmp, 2)) {
127127+ return (1);
128128+ }
129129+130130+ ck = ((tmp[0] & 0xff) << 8) | (tmp[1] & 0xff);
131131+132132+ *check = (mhex_get_cksum (*addr, buf, *cnt) != ck);
133133+134134+ mhex_skip_line (fp);
135135+136136+ return (0);
137137+}
138138+139139+int mhex_load_fp (FILE *fp, void *ext, mhex_set_f set)
140140+{
141141+ int check;
142142+ unsigned i, addr, cnt, rcnt;
143143+ unsigned char buf[256];
144144+145145+ rcnt = 0;
146146+147147+ while (1) {
148148+ if (mhex_read_record (fp, &addr, buf, &cnt, &check)) {
149149+ break;
150150+ }
151151+152152+ rcnt += 1;
153153+154154+ if (check) {
155155+ return (1);
156156+ }
157157+158158+ if (cnt == 0) {
159159+ if ((addr + 1) != rcnt) {
160160+ return (1);
161161+ }
162162+163163+ rcnt = 0;
164164+ }
165165+166166+ for (i = 0; i < cnt; i++) {
167167+ set (ext, addr + i, buf[i]);
168168+ }
169169+ }
170170+171171+ if (rcnt > 0) {
172172+ return (1);
173173+ }
174174+175175+ return (0);
176176+}
177177+178178+int mhex_load (const char *fname, void *ext, mhex_set_f set)
179179+{
180180+ int r;
181181+ FILE *fp;
182182+183183+ if ((fp = fopen (fname, "rb")) == NULL) {
184184+ return (1);
185185+ }
186186+187187+ r = mhex_load_fp (fp, ext, set);
188188+189189+ fclose (fp);
190190+191191+ return (r);
192192+}
193193+194194+static
195195+void mhex_write_record (FILE *fp, unsigned addr, const unsigned char *buf, unsigned cnt)
196196+{
197197+ unsigned ck;
198198+199199+ ck = mhex_get_cksum (addr, buf, cnt);
200200+201201+ fprintf (fp, ";%02X%04X", cnt & 0xff, addr & 0xffff);
202202+203203+ while (cnt-- > 0) {
204204+ fprintf (fp, "%02X", *(buf++));
205205+ }
206206+207207+ fprintf (fp, "%04X\n", ck & 0xffff);
208208+}
209209+210210+int mhex_save_fp (FILE *fp, unsigned long base, unsigned addr, unsigned size, void *ext, mhex_get_f get)
211211+{
212212+ unsigned i, cnt, rcnt;
213213+ unsigned char buf[16];
214214+215215+ rcnt = 0;
216216+217217+ while (size > 0) {
218218+ cnt = (size < 16) ? size : 16;
219219+220220+ if (((addr + cnt) & 0xffff) < (addr & 0xffff)) {
221221+ cnt = -addr & 0xffff;
222222+ }
223223+224224+ for (i = 0; i < cnt; i++) {
225225+ buf[i] = get (ext, base + ((addr + i) & 0xffff));
226226+ }
227227+228228+ mhex_write_record (fp, addr, buf, cnt);
229229+230230+ rcnt += 1;
231231+ addr += cnt;
232232+ size -= cnt;
233233+ }
234234+235235+ mhex_write_record (fp, rcnt, NULL, 0);
236236+237237+ return (0);
238238+}
239239+240240+int mhex_save (const char *fname, unsigned long base, unsigned addr, unsigned size, void *ext, mhex_get_f set)
241241+{
242242+ int r;
243243+ FILE *fp;
244244+245245+ if ((fp = fopen (fname, "wb")) == NULL) {
246246+ return (1);
247247+ }
248248+249249+ r = mhex_save_fp (fp, base, addr, size, ext, set);
250250+251251+ fclose (fp);
252252+253253+ return (r);
254254+}
+38
src/lib/mhex.h
···11+/*****************************************************************************
22+ * pce *
33+ *****************************************************************************/
44+55+/*****************************************************************************
66+ * File name: src/lib/mhex.h *
77+ * Created: 2020-05-02 by Hampa Hug <hampa@hampa.ch> *
88+ * Copyright: (C) 2020 Hampa Hug <hampa@hampa.ch> *
99+ *****************************************************************************/
1010+1111+/*****************************************************************************
1212+ * This program is free software. You can redistribute it and / or modify it *
1313+ * under the terms of the GNU General Public License version 2 as published *
1414+ * by the Free Software Foundation. *
1515+ * *
1616+ * This program is distributed in the hope that it will be useful, but *
1717+ * WITHOUT ANY WARRANTY, without even the implied warranty of *
1818+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
1919+ * Public License for more details. *
2020+ *****************************************************************************/
2121+2222+2323+#ifndef PCE_LIB_MHEX_H
2424+#define PCE_LIB_MHEX_H 1
2525+2626+2727+typedef void (*mhex_set_f) (void *ext, unsigned long addr, unsigned char val);
2828+typedef unsigned char (*mhex_get_f) (void *ext, unsigned long addr);
2929+3030+3131+int mhex_load_fp (FILE *fp, void *ext, mhex_set_f set);
3232+int mhex_load (const char *fname, void *ext, mhex_set_f set);
3333+3434+int mhex_save_fp (FILE *fp, unsigned long base, unsigned addr, unsigned size, void *ext, mhex_get_f get);
3535+int mhex_save (const char *fname, unsigned long base, unsigned addr, unsigned size, void *ext, mhex_get_f set);
3636+3737+3838+#endif