From 39be73232fc576e9bbe4c1fe0517fd266960fe5a Mon Sep 17 00:00:00 2001 From: Philip Smart Date: Tue, 19 May 2020 00:57:20 +0100 Subject: [PATCH] Tool to create the memory decoder bit map --- software/READ.ME | 2 + software/src/tools/Makefile | 121 ++++++++ software/src/tools/flashmmcfg.c | 501 ++++++++++++++++++++++++++++++++ software/tools/flashmmcfg | Bin 0 -> 13616 bytes 4 files changed, 624 insertions(+) create mode 100644 software/READ.ME create mode 100644 software/src/tools/Makefile create mode 100644 software/src/tools/flashmmcfg.c create mode 100755 software/tools/flashmmcfg diff --git a/software/READ.ME b/software/READ.ME new file mode 100644 index 0000000..b1c2d9d --- /dev/null +++ b/software/READ.ME @@ -0,0 +1,2 @@ +Please see the zSoft repository for the main software components of the tranZPUter/tranZPUterSW. This tree contains software tools to aid +in the development and configuration of the tranZPUter only. diff --git a/software/src/tools/Makefile b/software/src/tools/Makefile new file mode 100644 index 0000000..61804b6 --- /dev/null +++ b/software/src/tools/Makefile @@ -0,0 +1,121 @@ +######################################################################################################### +## +## Name: Makefile +## Created: May 2020 +## Author(s): Philip Smart +## Description: Helper tools for the MZ80A tranZPUter / tranZPUterSW upgrades. +## This makefile builds tools written in C which help with building/setting up the +## tranZPUter/tranZPUterSW and configuration images. +## +## Credits: +## Copyright: (c) 2020 Philip Smart +## +## History: May 2020 - Initial Makefile creation +## +## Notes: +## +######################################################################################################### +## This source file is free software: you can redistribute it and/or modify +## it under the terms of the GNU General Public License as published +## by the Free Software Foundation, either version 3 of the License, or +## (at your option) any later version. +## +## This source file is distributed in the hope that it will be useful, +## but WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with this program. If not, see . +######################################################################################################### +BASE = +CC = $(BASE)gcc +LD = $(BASE)gcc +AS = $(BASE)as +CP = $(BASE)objcopy +DUMP = $(BASE)objdump + +BASEDIR = ../../.. +SWDIR = $(BASEDIR)/software/src +INSTALLDIR = $(BASEDIR)/software/tools + +# we use printf from here +COMMON_DIR = $(SWDIR)/common +INCLUDE_DIR = $(SWDIR)/include + +# Working directory to build object files. +BUILD_DIR = tools_obj + +COMMON_SRC = +COMMON_OBJ = $(patsubst $(COMMON_DIR)/%.c,$(BUILD_DIR)/%.o,$(COMMON_SRC)) + +FLASHMMCFG_PRJ = flashmmcfg +FLASHMMCFG_SRC = flashmmcfg.c +FLASHMMCFG_OBJ = $(COMMON_OBJ) $(patsubst %.c,$(BUILD_DIR)/%.o,$(FLASHMMCFG_SRC)) + +# Commandline options for each tool. +OPTS = + +CFLAGS = -I. -I$(COMMON_DIR) -I$(INCLUDE_DIR) -O3 +# Enable debug output. +OFLAGS += -DDEBUG +LFLAGS = -Wl,--gc-sections -Wl,--relax -Os +# +# Assembler flags. +ASFLAGS = -I. -I$(COMMON_DIR) -I$(INCLUDE_DIR) -I$(STARTUP_DIR) +# + +# Our target. +all: clean $(BUILD_DIR) $(FLASHMMCFG_PRJ) + +install: all + cp $(FLASHMMCFG_PRJ) $(INSTALLDIR) + +clean: + rm -f $(BUILD_DIR)/*.o *.hex *.lss *.elf *.map *.lst *.srec *~ */*.o *.bin *.srec *.dmp *.vhd *.rpt $(FLASHMMCFG_PRJ) + +$(FLASHMMCFG_PRJ): $(FLASHMMCFG_PRJ).elf $(FLASHMMCFG_PRJ).dmp $(FLASHMMCFG_PRJ).lss + +# Convert ELF binary to bin file. +%.bin: %.elf + @$(CP) -O binary $< $@ + +# Convert ELF to srec format for serial upload. +%.srec: %.elf + @$(CP) -O srec $< $@ + +%.dmp: %.elf + @$(DUMP) -x $< >>$@ + +# Create extended listing file from ELF output file. +# testing: option -C +%.lss: %.elf + @echo + @$(DUMP) -h -S -C $< > $@ + +$(FLASHMMCFG_PRJ): $(FLASHMMCFG_OBJ) + $(CC) $(LFLAGS) $(FLASHMMCFG_OBJ) -o $@ $(LIBS) + chmod +x $@ + +# Link - this produces an ELF binary. +$(FLASHMMCFG_PRJ).elf: $(FLASHMMCFG_OBJ) + $(LD) $(LFLAGS) -o $@ $+ $(LIBS) + +$(BUILD_DIR)/%.o: %.c Makefile + $(CC) $(CFLAGS) $(OFLAGS) -o $@ -c $< + +$(BUILD_DIR)/%.o: %.cpp Makefile + $(CC) $(CFLAGS) $(OFLAGS) -o $@ -c $< + +$(BUILD_DIR)/%.o: $(COMMON_DIR)/%.c Makefile + $(CC) $(CFLAGS) $(OFLAGS) -o $@ -c $< + +$(BUILD_DIR)/%.o: %.s + $(AS) $(ASFLAGS) -o $@ $< + +$(BUILD_DIR)/%.o: $(STARTUP_DIR)/%.s + $(AS) $(ASFLAGS) -o $@ $< + +$(BUILD_DIR): + mkdir $(BUILD_DIR) + diff --git a/software/src/tools/flashmmcfg.c b/software/src/tools/flashmmcfg.c new file mode 100644 index 0000000..5571b67 --- /dev/null +++ b/software/src/tools/flashmmcfg.c @@ -0,0 +1,501 @@ +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Name: flashmmcfg.c +// Created: May 2020 +// Author(s): Philip Smart +// Description: tranZPUter SW Memory Map Configuration Tool +// This program creates the 512KB array which forms the tranZPUterSW memory decoder. +// The 512KB Flash has 19 inputs and 8 outputs, the outputs selecting or enabling +// a function on the tranZPUter SW design. +// +// Inputs: +// A0 - Z80_MEM0 = MEM[4:0] for the latched configuration selection. +// A1 - Z80_MEM1 Based on these bits the decoder operates in a +// A2 - Z80_MEM2 differing manner. Basically it will allow areas +// A3 - Z80_MEM3 of the Z80 Memory to use the onboard 512K Static RAM +// A4 - Z80_MEM4 at a 64Byte granularity or the Sharp MZ80A mainboard. +// A5 - Z80_WR = Z80 Write Signal +// A6 - Z80_RD = Z80 Read Signal +// A7 - Z80_IORQ = Z80 IORQ Signal, an IO operation is taking place. +// A8 - Z80_MREQ = Z80 MREQ Signal, a memory operation is taking place. +// A9 - Z80_A6 = A[15:6] Z80 address lines of IO or Memory target. +// A10 - Z80_A7 +// A11 - Z80_A8 +// A12 - Z80_A9 +// A13 - Z80_A10 +// A14 - Z80_A11 +// A15 - Z80_A12 +// A16 - Z80_A13 +// A17 - Z80_A14 +// A18 - Z80_A15 +// +// Memory Modes: 0 - Default, normal Sharp MZ80A operating mode, all memory and IO (except tranZPUter control IO block) are on the mainboard +// 1 - As 0 except Floppy ROM and User ROM are mapped to tranZPUter RAM. +// 31 - tranZPUter, all memory and IO are exclusively to the devices on the tranZPUter board, no mainboard access is made. +// +// +// Credits: +// Copyright: (c) 2020 Philip Smart +// +// History: May 2020 - Initial program written. +// +// Notes: +// +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// This source file is free software: you can redistribute it and#or modify +// it under the terms of the GNU General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This source file is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +///////////////////////////////////////////////////////////////////////////////////////////////////////// + +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "1.0" +#define FLASHRAMBITS 19 +#define FLASHRAMSIZE 1 << FLASHRAMBITS +#define CFGBITS 5 +#define CFGSETS (1 << CFGBITS) +#define TRANCHESIZE (FLASHRAMSIZE) / (CFGSETS) + +#define CFG_IO_CONTROL_ADDR 0x60 + +typedef struct __attribute__((__packed__)) { + uint8_t DISABLE_BUS : 1; + uint8_t ENABLE_BUS : 1; + uint8_t reserved2 : 1; + uint8_t reserved3 : 1; + uint8_t reserved4 : 1; + uint8_t IODECODE : 1; + uint8_t RAM_WE : 1; + uint8_t RAM_OE : 1; +} t_map_output; + +// Structure to represent one of the 32 possible memory map configurations as set by the MEM[4:0] latch. +// +typedef struct __attribute__((__packed__)) { + t_map_output tranche[TRANCHESIZE]; +} t_memmap_tranche; + +static t_memmap_tranche flashRAM[CFGSETS]; +static int verbose_flag = 0; +static uint32_t ioAddr = CFG_IO_CONTROL_ADDR; + + +// Simple help screen to remmber how this utility works!! +// +void usage(void) +{ + printf("FLASHMMCFG v%s\n", VERSION); + printf("\nOptions:-\n"); + printf(" -h | --help This help test.\n"); + printf(" -i | --io-addr Base address for the IO Control Registers.\n"); + printf(" -o | --output Output the final binary image to the given file. This file is programmed into the Flash RAM.\n"); + printf(" -v | --verbose Output more messages.\n"); + + printf("\nExamples:\n"); + printf(" flashmmcfg --output Decode1.bin --io-addr 0x20 Create the mapping binary using 0x20 as the base address for the IO Control Registers.\n"); + +} + +// Method to convert a little endian <-> big endian 32bit unsigned. +// +uint32_t swap_endian(uint32_t value) +{ + uint32_t b[4]; + b[0] = ((value & 0x000000ff) << 24u); + b[1] = ((value & 0x0000ff00) << 8u); + b[2] = ((value & 0x00ff0000) >> 8u); + b[3] = ((value & 0xff000000) >> 24u); + + return(b[0] | b[1] | b[2] | b[3]); +} + +// Method to initialise the structures which represent the output binary image for uploading into the decoder Flash RAM. +// There are a fixed number of 'sets' of configurations which are selected by the MEM[4:0] latch bits, each set gives a +// different decoding action so that different memory maps and IO maps can be realised by the Z80 dependent upon its task +// or machine it is emulating. +// +void initMap(void) +{ + for(uint8_t idx=0; idx < CFGSETS; idx++) + { + for(uint32_t idx2=0; idx2 < TRANCHESIZE; idx2++) + { + flashRAM[idx].tranche[idx2].DISABLE_BUS = 1; + flashRAM[idx].tranche[idx2].ENABLE_BUS = 1; + flashRAM[idx].tranche[idx2].reserved2 = 1; + flashRAM[idx].tranche[idx2].reserved3 = 1; + flashRAM[idx].tranche[idx2].reserved4 = 1; + flashRAM[idx].tranche[idx2].IODECODE = 1; + flashRAM[idx].tranche[idx2].RAM_WE = 1; + flashRAM[idx].tranche[idx2].RAM_OE = 1; + } + } + return; +} + +// This method takes the internal array, organised as sets and tranches and manipulates them to fit the actual hardware +// definition. As the configuration bits MEM[4:0] operate the lowest address select bits of the Flash RAM the output needs +// to be sliced into CFGSETS where byte 0 = byte 0 of config set 0 ..... byte n = byte n of config set n, n = 31 for the +// current hardware design. This slice is repeated for all TRANCHESIZE bytes in each tranche. +// +void outputMap(FILE *fp) +{ + // Locals. + uint32_t idx; + uint8_t idx2; + uint8_t outbuf[CFGSETS]; + + // As the configuration bits MEM[4:0] operate the lowest address select bits of the Flash RAM the output needs to be + // + // + for(idx=0; idx < TRANCHESIZE; idx++) + { + for(idx2=0; idx2 < CFGSETS; idx2++) + { + outbuf[idx2] = flashRAM[idx2].tranche[idx].RAM_OE << 7 | + flashRAM[idx2].tranche[idx].RAM_WE << 6 | + flashRAM[idx2].tranche[idx].IODECODE << 5 | + flashRAM[idx2].tranche[idx].reserved4 << 4 | + flashRAM[idx2].tranche[idx].reserved3 << 3 | + flashRAM[idx2].tranche[idx].reserved2 << 2 | + flashRAM[idx2].tranche[idx].ENABLE_BUS << 1 | + flashRAM[idx2].tranche[idx].DISABLE_BUS; + } + if(fwrite(outbuf, 1, CFGSETS, fp) != CFGSETS) + { + printf("Write Error: Failed to write %d bytes of set:tranche %u:%u\n", CFGSETS, idx2, idx); + } + } + return; +} + +// This method looks at the input signals for a given set and updates the output bits accordingly. +// +void setMap(uint8_t set, uint32_t inSignals) +{ + // Decode the input signals into there components. + uint8_t Z80_WR = (inSignals & 0b00000000000001); + uint8_t Z80_RD = (inSignals & 0b00000000000010) >> 1; + uint8_t Z80_IORQ = (inSignals & 0b00000000000100) >> 2; + uint8_t Z80_MREQ = (inSignals & 0b00000000001000) >> 3; + uint8_t Z80_A6 = (inSignals & 0b00000000010000) >> 4; + uint8_t Z80_A7 = (inSignals & 0b00000000100000) >> 5; + uint8_t Z80_A8 = (inSignals & 0b00000001000000) >> 6; + uint8_t Z80_A9 = (inSignals & 0b00000010000000) >> 7; + uint8_t Z80_A10 = (inSignals & 0b00000100000000) >> 8; + uint8_t Z80_A11 = (inSignals & 0b00001000000000) >> 9; + uint8_t Z80_A12 = (inSignals & 0b00010000000000) >> 10; + uint8_t Z80_A13 = (inSignals & 0b00100000000000) >> 11; + uint8_t Z80_A14 = (inSignals & 0b01000000000000) >> 12; + uint8_t Z80_A15 = (inSignals & 0b10000000000000) >> 13; + uint32_t Z80_ADDR = (inSignals & 0b11111111110000) << 2; // 16 bit memory address. + uint32_t Z80_IO_ADDR = ((inSignals & 0b00000000110000) << 2) | 0b00100000; // 8 bit IO address, bit 5 is hardwired to 1, bit 4 is hardwired to 0. + uint8_t Z80_MEM_WRITE = (Z80_WR == 0 && Z80_MREQ == 0 && Z80_RD == 1 && Z80_IORQ == 1) ? 1 : 0; + uint8_t Z80_MEM_READ = (Z80_RD == 0 && Z80_MREQ == 0 && Z80_WR == 1 && Z80_IORQ == 1) ? 1 : 0; + uint8_t Z80_IO_WRITE = (Z80_WR == 0 && Z80_IORQ == 0 && Z80_RD == 1 && Z80_MREQ == 1) ? 1 : 0; + uint8_t Z80_IO_READ = (Z80_RD == 0 && Z80_IORQ == 0 && Z80_WR == 1 && Z80_MREQ == 1) ? 1 : 0; + + //printf("Signals(%u): Z80_WR=%u, Z80_RD=%u, Z80_IORQ=%u, Z80_MREQ=%u, Z80_ADDR=%u, Z80_IO_ADDR=%u\n", inSignals, Z80_WR, Z80_RD, Z80_IORQ, Z80_MREQ, Z80_ADDR, Z80_IO_ADDR); + //printf("MEMWR=%u, MEMRD=%u, IOWR=%u, IORD=%u\n", Z80_MEM_WRITE, Z80_MEM_READ, Z80_IO_WRITE, Z80_IO_WRITE); + + // Defaults for IO operations, can be overriden for a specific set but should be present in all other sets. + // + if(Z80_IO_WRITE || Z80_IO_READ) + { + // If the address is within configured IO control register range, activate the IODECODE signal. + if(Z80_IO_ADDR == ioAddr) + { + flashRAM[set].tranche[inSignals].DISABLE_BUS = 0; + flashRAM[set].tranche[inSignals].IODECODE = 0; + } + } + + // If the non-standard case of Z80 RD and Z80 WR being set low occurs, enable the ENABLE_BUS signal as the K64F is requesting access to the MZ80A motherboard. + // This signal is not set dependent, it can occur at any time and with any set. + // + if(Z80_RD == 0 && Z80_WR == 0 && Z80_MREQ == 1 && Z80_IORQ == 1) + { + flashRAM[set].tranche[inSignals].DISABLE_BUS = 1; + flashRAM[set].tranche[inSignals].ENABLE_BUS = 0; + flashRAM[set].tranche[inSignals].RAM_OE = 1; + flashRAM[set].tranche[inSignals].RAM_WE = 1; + flashRAM[set].tranche[inSignals].IODECODE = 1; + } + + // Specific mapping for Memory Writes. + if(Z80_MEM_WRITE) + { + switch(set) + { + // Set 0 - default, the Z80 uses the motherboard so no special signal activation is needed. + case 0: + flashRAM[set].tranche[inSignals].ENABLE_BUS = 0; + flashRAM[set].tranche[inSignals].DISABLE_BUS = 1; + flashRAM[set].tranche[inSignals].RAM_OE = 1; + flashRAM[set].tranche[inSignals].RAM_WE = 1; + break; + + // Set 1 - A standard MZ80A.the tranZPUter maps in RAM to the User and Floppy drive slots but otherwise all standard. + case 1: + // Place a bank of RAM into the floppy disk bios area. + if( (Z80_ADDR >= 0xF000 && Z80_ADDR < 0x10000) //|| + // Place RAM into the User ROM socket. + // (Z80_ADDR >= 0xE800 && Z80_ADDR < 0xF000) + ) + { + flashRAM[set].tranche[inSignals].DISABLE_BUS = 0; + flashRAM[set].tranche[inSignals].RAM_WE = 0; + } else + { + flashRAM[set].tranche[inSignals].ENABLE_BUS = 0; + flashRAM[set].tranche[inSignals].RAM_OE = 1; + } + break; + + // Set 31 - All memory and IO are on the tranZPUter board. + case 31: + flashRAM[set].tranche[inSignals].DISABLE_BUS = 0; + flashRAM[set].tranche[inSignals].RAM_WE = 0; + break; + + // For default, do nothing. + default: + break; + } + } + + // Specific mapping for Memory Reads. + else if(Z80_MEM_READ) + { + switch(set) + { + // Set 0 - default, the Z80 uses the motherboard so no signal activation is needed. + case 0: + flashRAM[set].tranche[inSignals].ENABLE_BUS = 0; + flashRAM[set].tranche[inSignals].DISABLE_BUS = 1; + flashRAM[set].tranche[inSignals].RAM_OE = 1; + flashRAM[set].tranche[inSignals].RAM_WE = 1; + break; + + // Set 1 - A standard MZ80A.the tranZPUter maps in RAM to the User and Floppy drive slots but otherwise all standard. + case 1: + // Place a bank of RAM into the floppy disk bios area. + if( (Z80_ADDR >= 0xF000 && Z80_ADDR < 0x10000) //|| + // Place RAM into the User ROM socket. + // (Z80_ADDR >= 0xE800 && Z80_ADDR < 0xF000) + ) + { + flashRAM[set].tranche[inSignals].DISABLE_BUS = 0; + flashRAM[set].tranche[inSignals].RAM_OE = 0; + } else + { + flashRAM[set].tranche[inSignals].ENABLE_BUS = 0; + flashRAM[set].tranche[inSignals].RAM_OE = 1; + } + break; + + // Set 31 - All memory and IO are on the tranZPUter board. + case 31: + flashRAM[set].tranche[inSignals].DISABLE_BUS = 0; + flashRAM[set].tranche[inSignals].RAM_OE = 0; + break; + + // For default, do nothing. + default: + break; + } + } + + // Specific mapping for IO Writes. + else if(Z80_IO_WRITE) + { + switch(set) + { + case 0: + if(Z80_IO_ADDR != ioAddr) + { + flashRAM[set].tranche[inSignals].ENABLE_BUS = 0; + flashRAM[set].tranche[inSignals].DISABLE_BUS = 1; + flashRAM[set].tranche[inSignals].RAM_OE = 1; + flashRAM[set].tranche[inSignals].RAM_WE = 1; + } + break; + + // Set 31 - All memory and IO are on the tranZPUter board. + case 31: + flashRAM[set].tranche[inSignals].DISABLE_BUS = 0; + flashRAM[set].tranche[inSignals].IODECODE = 0; + break; + + // For default, do nothing. + default: + break; + } + } + + // Specific mapping for IO Reads. + else if(Z80_IO_READ) + { + switch(set) + { + case 0: + if(Z80_IO_ADDR != ioAddr) + { + flashRAM[set].tranche[inSignals].ENABLE_BUS = 0; + flashRAM[set].tranche[inSignals].DISABLE_BUS = 1; + flashRAM[set].tranche[inSignals].RAM_OE = 1; + flashRAM[set].tranche[inSignals].RAM_WE = 1; + } + break; + + // Set 31 - All memory and IO are on the tranZPUter board. + case 31: + flashRAM[set].tranche[inSignals].DISABLE_BUS = 0; + flashRAM[set].tranche[inSignals].IODECODE = 0; + break; + + // For default, do nothing. + default: + break; + } + } + + // Actions which generally arent a valid Z80 transaction. + else + { + } +} + + +// A method to create each set definition. At the moment this is manually coded, if I think of a suitable algorithm then this set of +// procedures will change. +// +void createMap(void) +{ + for(uint8_t idx=0; idx < CFGSETS; idx++) + { + for(uint32_t idx2=0; idx2 < TRANCHESIZE; idx2++) + { + setMap(idx, idx2); + } + } +} + + + + +// Main program, to be split up into methods at a later date!! Just quick write as Im concentrating on the tranZPUterSW!! +// +int main(int argc, char *argv[]) +{ + // Locals. + char outputFile[1024]; + FILE *fpOutput; + int help_flag = 0; + int opt; + int option_index = 0; + + // Initialise any other variables as needed. + // + outputFile[0] = '\0'; + + // Modes of operation. + // flashmmcfg --output file + // flashmmcfg --help + static struct option long_options[] = + { + {"help", no_argument, 0, 'h'}, + {"ioaddr", required_argument, 0, 'i'}, + {"output", required_argument, 0, 'o'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} + }; + + // Parse the command line options. + // + while((opt = getopt_long(argc, argv, ":hvo;", long_options, &option_index)) != -1) + { + switch(opt) + { + case 'h': + help_flag = 1; + break; + + case 'i': + ioAddr = atoi(argv[optind]); + break; + + case 'o': + strcpy(outputFile, argv[optind]); + break; + + case 'v': + verbose_flag = 1; + break; + + case ':': + printf("Option %s needs a value\n", argv[optind-1]); + break; + case '?': + printf("Unknown option: %s, ignoring!\n", argv[optind-1]); + break; + } + } + + // Validate the input. + if(help_flag == 1) + { + usage(); + exit(0); + } + if(strlen(outputFile) == 0 ) + { + printf("Output file not specified, please use --output .\n"); + exit(10); + } + + // Open the output file for read/write operations to store the final Flash RAM binary byte image. + fpOutput = fopen(outputFile, "w+"); + if(fpOutput == NULL) + { + printf("Couldnt open the output file:%s.\n", outputFile); + exit(20); + } + if(ioAddr != 0x20 && ioAddr != 0x60 && ioAddr != 0xA0 && ioAddr != 0xF0) + { + printf("IO Control Register Base address is illegal:%04x, it should be one of 0x20, 0x60, 0xA0, 0xF0.\n", ioAddr); + exit(30); + } + + // Initialise the flash map to default unused state. + // + initMap(); + + // Create the required map. + // + createMap(); + + // Output the binary image for flashing into the FlashRAM to perform required decoding. + // + outputMap(fpOutput); + + // Tidy up, close and finish. + fclose(fpOutput); + if(verbose_flag) + printf("Output file created.\n"); +} diff --git a/software/tools/flashmmcfg b/software/tools/flashmmcfg new file mode 100755 index 0000000000000000000000000000000000000000..7ac90312fadfcd565b494bae550d9bed5ac5e877 GIT binary patch literal 13616 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 E0#A5ba{vGU literal 0 HcmV?d00001