+/* Extractor for Geraet 32620 ROM files
+ *
+ * Copyright (c) 2020 Michael Gernoth <michael@gernoth.net>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <errno.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+int main(int argc, char **argv)
+{
+ uint8_t header[64];
+ uint32_t adrs[(64/3)+1] = { 0 };
+ uint8_t last_cs = 0;
+ int fd;
+ int r;
+ int i;
+ int count = 0;
+
+ if (argc != 3) {
+ fprintf(stderr, "Syntax: %s in.bin prefix\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ fd = open(argv[1], O_RDONLY);
+ if (fd == -1) {
+ perror("Can't open ROM");
+ exit(EXIT_FAILURE);
+ }
+
+ r = read(fd, header, sizeof(header));
+ if (r != sizeof(header)) {
+ perror("Can't read header");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * From: https://blog.ardy.io/2020/8/geraet-32620/
+ *
+ * 00000000 01000000 01000011 10110111 01001010 01000011 11000011 01011000
+ * ^^^^^^^^ ^^^^^^^^ ^^^^^^^^| |
+ * LIIIIIII LIILIIII I????LII
+ * I I I I +-- Amplification (Default: 3)
+ * I I I +--------- Remaining chip select line? (but not quite?)
+ * I I +----------- Address (HI Byte)
+ * I +---------------- Chip Select lines A15, A14, A13
+ * +-------------------- Address (LO Byte)
+ */
+ for (i = 0; i < 62; i+=3) {
+ uint8_t hi, lo, amp, cs;
+ uint32_t adr;
+
+ lo = header[i];
+ if ((header[i+2] & 0xf8) & 0x40) {
+ cs = ((header[i+1] & 0xe0) >> 5) - 2;
+ } else {
+ cs = (((header[i+1] & 0xe0) >> 5) | (1 << 3)) - 4;
+ }
+
+ //EOF?!
+ if ((header[i+2] & 0xf8) == 0xf8)
+ cs = last_cs;
+ else
+ last_cs = cs;
+
+ hi = header[i+1] & 0x1f;
+ amp = header[i+2] & 0x3;
+
+ adr = ((hi << 8) | lo) + (cs * 8192);
+ if (cs == 0)
+ adr += sizeof(header);
+
+ printf("%02d. hi: 0x%02x, lo: 0x%02x, cs: 0x%02x -> adr: 0x%04x; amp: 0x%02x\n",
+ i/3, hi, lo, cs, adr, amp);
+
+ adrs[i/3] = adr;
+ if ((header[i+2] & 0xf8) == 0xf8)
+ break;
+
+ count++;
+ }
+
+ for (i = 0; i < count; i++) {
+ uint8_t buf[65536];
+ uint32_t len;
+ char file[32];
+ int fd_out;
+
+ lseek(fd, adrs[i], SEEK_SET);
+
+ len = adrs[i+1] - adrs[i];
+
+ if (!len)
+ break;
+
+ printf("%02d. Length: %d\n", i, len);
+ memset(file, 0, sizeof(file));
+ snprintf(file, sizeof(file)-1, "%s-%02d.raw", argv[2], i);
+
+ fd_out = open(file, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd_out == -1) {
+ perror("Can't open out");
+ exit(EXIT_FAILURE);
+ }
+
+ r = read(fd, buf, len);
+ if (r != len) {
+ perror("Can't read content");
+ exit(EXIT_FAILURE);
+ }
+
+ r = write(fd_out, buf, len);
+ if (r != len) {
+ perror("Can't write content");
+ exit(EXIT_FAILURE);
+ }
+
+ close(fd_out);
+
+ }
+
+ close(fd);
+
+ return EXIT_SUCCESS;
+}