Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/ClusterM/famicom-dumper.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2020-11-26 12:11:44 +0300
committerAlexey 'Cluster' Avdyukhin <clusterrr@clusterrr.com>2020-11-26 12:11:44 +0300
commit03128e8ef53bea42187f87c3846c368c56b02618 (patch)
treef47dbce7cc4b13ee58576dcc7c7defdeaf6a1d15
parent526f672775dbe4cda8017c4cba3aa1c4fef66612 (diff)
FDS reader, faster CRC calculations
-rw-r--r--Makefile53
-rw-r--r--comm.c31
-rw-r--r--comm.h4
-rw-r--r--crc.c37
-rw-r--r--crc.h10
-rw-r--r--crc.obin0 -> 4140 bytes
-rw-r--r--dumper.c233
-rw-r--r--dumper.h5
-rw-r--r--famicom-dumper.hex670
9 files changed, 683 insertions, 360 deletions
diff --git a/Makefile b/Makefile
index 444daec..323d533 100644
--- a/Makefile
+++ b/Makefile
@@ -5,7 +5,8 @@ PROGRAMMER_TYPE ?= avr109
PROGRAMMER_PORT ?= com28
PRG = famicom-dumper
-OBJ = dumper.o usart.o comm.o
+OBJ = dumper.o usart.o comm.o crc.o
+HEADERS = defines.h comm.h dumper.h usart.h crc.h
#MCU_TARGET = at90s2313
#MCU_TARGET = at90s2333
#MCU_TARGET = at90s4414
@@ -59,8 +60,6 @@ OPTIMIZE = -O2
DEFS =
LIBS =
-# You should not have to change anything below here.
-
CC = avr-gcc
# Override is only needed by avr-lib build system.
@@ -71,13 +70,12 @@ override LDFLAGS = -Wl,-Map,$(PRG).map
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
-all: $(PRG).elf lst text eeprom
+all: $(PRG).elf lst text
$(PRG).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
-# dependency:
-demo.o: demo.c
+$(OBJ): $(HEADERS)
clean:
rm -rf *.o $(PRG).elf *.eps *.png *.pdf *.bak
@@ -105,46 +103,7 @@ srec: $(PRG).srec
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@
-# Rules for building the .eeprom rom images
-
-eeprom: ehex ebin esrec
-
-ehex: $(PRG)_eeprom.hex
-ebin: $(PRG)_eeprom.bin
-esrec: $(PRG)_eeprom.srec
-
-%_eeprom.hex: %.elf
- $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O ihex $< $@ \
- || { echo empty $@ not generated; exit 0; }
-
-%_eeprom.srec: %.elf
- $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $@ \
- || { echo empty $@ not generated; exit 0; }
-
-%_eeprom.bin: %.elf
- $(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O binary $< $@ \
- || { echo empty $@ not generated; exit 0; }
-
-# Every thing below here is used by avr-libc's build system and can be ignored
-# by the casual user.
-
-FIG2DEV = fig2dev
-EXTRA_CLEAN_FILES = *.hex *.bin *.srec
-
-dox: eps png pdf
-
-eps: $(PRG).eps
-png: $(PRG).png
-pdf: $(PRG).pdf
-
-%.eps: %.fig
- $(FIG2DEV) -L eps $< $@
-
-%.pdf: %.fig
- $(FIG2DEV) -L pdf $< $@
-
-%.png: %.fig
- $(FIG2DEV) -L png $< $@
+# Rules to update
program: hex
avrdude -V -p $(MCU_PROGRAMMER) -c $(PROGRAMMER_TYPE) -P $(PROGRAMMER_PORT) -U flash:w:$(PRG).hex
@@ -155,3 +114,5 @@ reboot:
update: reboot program
build: hex
+
+.PHONY: program reboot update
diff --git a/comm.c b/comm.c
index 36ca781..1c39c21 100644
--- a/comm.c
+++ b/comm.c
@@ -3,6 +3,7 @@
#include <util/delay.h>
#include "comm.h"
#include "usart.h"
+#include "crc.h"
static uint8_t comm_send_crc;
static unsigned int comm_send_length;
@@ -17,35 +18,9 @@ volatile unsigned int comm_recv_length;
volatile uint8_t recv_buffer[RECV_BUFFER+8];
volatile uint8_t comm_recv_done;
-static void comm_calc_send_crc(uint8_t inbyte)
-{
- uint8_t j;
- for (j=0;j<8;j++)
- {
- uint8_t mix = (comm_send_crc ^ inbyte) & 0x01;
- comm_send_crc >>= 1;
- if (mix)
- comm_send_crc ^= 0x8C;
- inbyte >>= 1;
- }
-}
-
-static void comm_calc_recv_crc(uint8_t inbyte)
-{
- uint8_t j;
- for (j=0;j<8;j++)
- {
- uint8_t mix = (comm_recv_crc ^ inbyte) & 0x01;
- comm_recv_crc >>= 1;
- if (mix)
- comm_recv_crc ^= 0x8C;
- inbyte >>= 1;
- }
-}
-
static void comm_send_and_calc(uint8_t data)
{
- comm_calc_send_crc(data);
+ comm_send_crc = calc_crc8(comm_send_crc, data);
USART_TransmitByte(data);
#ifdef SEND_DELAY
_delay_us(SEND_DELAY);
@@ -84,7 +59,7 @@ void comm_proceed(uint8_t data)
comm_recv_crc = 0;
comm_recv_done = 0;
}
- comm_calc_recv_crc(data);
+ comm_recv_crc= calc_crc8(comm_recv_crc, data);
unsigned int l = comm_recv_pos-4;
switch (comm_recv_pos)
{
diff --git a/comm.h b/comm.h
index 44a4d6f..a0804db 100644
--- a/comm.h
+++ b/comm.h
@@ -45,6 +45,10 @@
#define COMMAND_FLASH_WRITE_TIMEOUT 42
#define COMMAND_FLASH_ERASE_ERROR 43
#define COMMAND_FLASH_ERASE_TIMEOUT 44
+#define COMMAND_FDS_READ_REQUEST 45
+#define COMMAND_FDS_READ_RESULT_BLOCK 46
+#define COMMAND_FDS_READ_RESULT_END 47
+#define COMMAND_FDS_TIMEOUT 48
#define COMMAND_BOOTLOADER 0xFE
#define COMMAND_DEBUG 0xFF
diff --git a/crc.c b/crc.c
new file mode 100644
index 0000000..1588e41
--- /dev/null
+++ b/crc.c
@@ -0,0 +1,37 @@
+#include <inttypes.h>
+
+const uint8_t crc8_table[] = { 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65, 157, 195, 33, 127, 252, 162, 64, 30, 95, 1,
+ 227, 189, 62, 96, 130, 220, 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98, 190, 224, 2, 92, 223, 129, 99, 61, 124, 34,
+ 192, 158, 29, 67, 161, 255, 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7, 219, 133, 103, 57, 186, 228, 6, 88, 25, 71,
+ 165, 251, 120, 38, 196, 154, 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36, 248, 166, 68, 26, 153, 199, 37, 123, 58,
+ 100, 134, 216, 91, 5, 231, 185, 140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205, 17, 79, 173, 243, 112, 46, 204, 146,
+ 211, 141, 111, 49, 178, 236, 14, 80, 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238, 50, 108, 142, 208, 83, 13, 239,
+ 177, 240, 174, 76, 18, 145, 207, 45, 115, 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139, 87, 9, 235, 181, 54, 104, 138,
+ 212, 149, 203, 41, 119, 244, 170, 72, 22, 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168, 116, 42, 200, 150, 21, 75,
+ 169, 247, 182, 232, 10, 84, 215, 137, 107, 53 };
+
+const uint16_t crc16_table[] = { 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1,
+ 0xC481, 0x0440, 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, 0x1400, 0xD4C1,
+ 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, 0xF001, 0x30C0, 0x3180, 0xF141,
+ 0x3300, 0xF3C1, 0xF281, 0x3240, 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0,
+ 0x3E80, 0xFE41, 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, 0x2200, 0xE2C1,
+ 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, 0x6600, 0xA6C1, 0xA781, 0x6740,
+ 0xA501, 0x65C0, 0x6480, 0xA441, 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1,
+ 0xA881, 0x6840, 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, 0x5000, 0x90C1,
+ 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, 0x9C01, 0x5CC0, 0x5D80, 0x9D41,
+ 0x5F00, 0x9FC1, 0x9E81, 0x5E40, 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1,
+ 0x8A81, 0x4A40, 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040, };
+
+uint8_t calc_crc8(uint8_t old_crc, uint8_t inbyte)
+{
+ return crc8_table[old_crc ^ inbyte];
+}
+
+uint16_t calc_crc16(uint16_t old_crc, uint8_t inbyte)
+{
+ return (old_crc >> 8) ^ crc16_table[((old_crc ^ inbyte) & 0x00FF) & 0xFF];
+}
diff --git a/crc.h b/crc.h
new file mode 100644
index 0000000..c786e85
--- /dev/null
+++ b/crc.h
@@ -0,0 +1,10 @@
+#ifndef _CRC_H_
+#define _CRC_H_
+
+extern const uint16_t crc8_table[];
+extern const uint16_t crc16_table[];
+
+uint8_t calc_crc8(uint8_t old_crc, uint8_t inbyte);
+uint16_t calc_crc16(uint16_t old_crc, uint8_t inbyte);
+
+#endif
diff --git a/crc.o b/crc.o
new file mode 100644
index 0000000..b76c807
--- /dev/null
+++ b/crc.o
Binary files differ
diff --git a/dumper.c b/dumper.c
index 4f61681..9340782 100644
--- a/dumper.c
+++ b/dumper.c
@@ -30,6 +30,7 @@
#include "usart.h"
#include "comm.h"
#include "dumper.h"
+#include "crc.h"
#define LED_RED_ON PORTB |= (1<<7)
#define LED_RED_OFF PORTB &= ~(1<<7)
@@ -160,20 +161,6 @@ static void read_chr_send(uint16_t address, uint16_t len)
LED_GREEN_OFF;
}
-static uint16_t crc16_update(uint16_t crc, uint8_t a)
-{
- int i;
- crc ^= a;
- for (i = 0; i < 8; ++i)
- {
- if (crc & 1)
- crc = (crc >> 1) ^ 0xA001;
- else
- crc = (crc >> 1);
- }
- return crc;
-}
-
static void read_prg_crc_send(uint16_t address, uint16_t len)
{
LED_GREEN_ON;
@@ -187,7 +174,7 @@ static void read_prg_crc_send(uint16_t address, uint16_t len)
PORTA = address & 0xFF;
PORTC = (address >> 8) & 0xFF;
_delay_us(1);
- crc = crc16_update(crc, PIND);
+ crc = calc_crc16(crc, PIND);
len--;
address++;
}
@@ -205,7 +192,7 @@ static void read_chr_crc_send(uint16_t address, uint16_t len)
uint16_t crc = 0;
while (len > 0)
{
- crc = crc16_update(crc, read_chr_byte(address));
+ crc = calc_crc16(crc, read_chr_byte(address));
len--;
address++;
}
@@ -614,6 +601,212 @@ static void write_flash(uint16_t address, uint16_t len, uint8_t* data)
LED_RED_OFF;
}
+static void read_fds_send(uint8_t start_block, uint8_t block_count)
+{
+ uint8_t status;
+ uint8_t end_of_head = 0;
+ uint8_t current_block = 0;
+ uint16_t b;
+
+ write_prg_byte(0x4022, 0x00); // disable IRQ
+ write_prg_byte(0x4023, 0x00); // disable registers
+ write_prg_byte(0x4023, 0x01); // enable disk registers
+ write_prg_byte(0x4025, 0x2E); // reset
+ // waiting for disk
+ while (1)
+ {
+ status = read_prg_byte(0x4032);
+ if (!(status & 1)) break; // disk inserted
+ }
+ write_prg_byte(0x4025, 0x2E); // reset
+ _delay_ms(800); // 916522 cycles
+ write_prg_byte(0x4025, 0x2F); // start motor
+ write_prg_byte(0x4025, 0x2D); // unreset
+
+ _delay_ms(250); // 268531 cycles
+ write_prg_byte(0x4025, 0x2E); // reset
+ write_prg_byte(0x4025, 0x2F); // start motor
+ write_prg_byte(0x4025, 0x2D); // unreset
+
+ // waiting until drive is rewinded
+ while (1)
+ {
+ status = read_prg_byte(0x4032);
+ if (!(status & 2)) break; // ready
+ }
+
+ _delay_ms(FDS_PAUSE_BEFORE_FIRST_BLOCK); // 486974 cycles
+
+ LED_GREEN_ON;
+ if (start_block == 0)
+ comm_start(COMMAND_FDS_READ_RESULT_BLOCK, 58);
+ write_prg_byte(0x4025, 0x6D); // start transfer
+ write_prg_byte(0x4025, 0xED); // enable IRQ
+ for (b = 0; b < 56; b++)
+ {
+ while (!IRQ_FIRED); // waiting for interrupt
+ uint8_t data = read_prg_byte(0x4031);
+ //write_prg_byte(0x4024, 0xFF); // clear interrupt
+ // status read also clears interrupt
+ status = read_prg_byte(0x4030);
+ end_of_head |= (status >> 6) & 1;
+ if (start_block == 0)
+ comm_send_byte(data);
+ while (IRQ_FIRED); // is interrupt flag cleared?
+ }
+ write_prg_byte(0x4025, 0xED); // enable CRC control
+ while (!IRQ_FIRED); // waiting for interrupt
+ read_prg_byte(0x4031);
+ write_prg_byte(0x4024, 0xFF); // clear interrupt
+ while (IRQ_FIRED); // is interrupt flag cleared?
+ status = read_prg_byte(0x4030);
+ end_of_head |= (status >> 6) & 1;
+ if (start_block == 0)
+ {
+ comm_send_byte(((status >> 4) & 1) ^ 1); // CRC check result
+ comm_send_byte(end_of_head); // end of head meet?
+ }
+ current_block++;
+
+ // reading file amount block
+ if (!end_of_head && ((start_block + block_count > current_block) || (block_count = 0)))
+ {
+ write_prg_byte(0x4025, 0x2D); // motor on without transfer
+ // waiting until drive is ready
+ while (1)
+ {
+ status = read_prg_byte(0x4032);
+ if (!(status & 2)) break; // ready
+ }
+ _delay_ms(FDS_PAUSE_BETWEEN_BLOCKS); // 9026 cycles
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ comm_start(COMMAND_FDS_READ_RESULT_BLOCK, 4);
+ write_prg_byte(0x4025, 0x6D); // start transfer
+ write_prg_byte(0x4025, 0xED); // enable IRQ
+ for (b = 0; b < 2; b++)
+ {
+ while (!IRQ_FIRED); // waiting for interrupt
+ uint8_t data = read_prg_byte(0x4031);
+ //write_prg_byte(0x4024, 0xFF); // clear interrupt
+ // status read also clears interrupt
+ status = read_prg_byte(0x4030);
+ end_of_head |= (status >> 6) & 1;
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ comm_send_byte(data);
+ while (IRQ_FIRED); // is interrupt flag cleared?
+ }
+ write_prg_byte(0x4025, 0xED); // enable CRC control
+ while (!IRQ_FIRED); // waiting for interrupt
+ read_prg_byte(0x4031);
+ write_prg_byte(0x4024, 0xFF); // clear interrupt
+ while (IRQ_FIRED); // is interrupt flag cleared?
+ status = read_prg_byte(0x4030);
+ end_of_head |= (status >> 6) & 1;
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ {
+ comm_send_byte(((status >> 4) & 1) ^ 1); // CRC check result
+ comm_send_byte(end_of_head); // end of head meet?
+ }
+ current_block++;
+ }
+
+ while (!end_of_head && ((start_block + block_count > current_block) || (block_count = 0)))
+ {
+ // reading file header block
+ uint16_t file_size = 0; // size of the next file
+
+ write_prg_byte(0x4025, 0x2D); // motor on without transfer
+ // waiting until drive is ready
+ while (1)
+ {
+ status = read_prg_byte(0x4032);
+ if (!(status & 2)) break; // ready
+ }
+ _delay_ms(FDS_PAUSE_BETWEEN_BLOCKS); // 9026 cycles
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ comm_start(COMMAND_FDS_READ_RESULT_BLOCK, 18);
+ write_prg_byte(0x4025, 0x6D); // start transfer
+ write_prg_byte(0x4025, 0xED); // enable IRQ
+ for (b = 0; b < 16; b++)
+ {
+ while (!IRQ_FIRED); // waiting for interrupt
+ uint8_t data = read_prg_byte(0x4031);
+ //write_prg_byte(0x4024, 0xFF); // clear interrupt
+ // status read also clears interrupt
+ status = read_prg_byte(0x4030);
+ end_of_head |= (status >> 6) & 1;
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ comm_send_byte(data);
+ if (b == 13)
+ file_size |= data;
+ else if (b == 14)
+ file_size |= data << 8;
+ while (IRQ_FIRED); // is interrupt flag cleared?
+ }
+ write_prg_byte(0x4025, 0xED); // enable CRC control
+ while (!IRQ_FIRED); // waiting for interrupt
+ read_prg_byte(0x4031);
+ write_prg_byte(0x4024, 0xFF); // clear interrupt
+ while (IRQ_FIRED); // is interrupt flag cleared?
+ status = read_prg_byte(0x4030);
+ end_of_head |= (status >> 6) & 1;
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ {
+ comm_send_byte(((status >> 4) & 1) ^ 1); // CRC check result
+ comm_send_byte(end_of_head); // end of head meet?
+ }
+ current_block++;
+
+ // reading file data
+ if (!end_of_head && ((start_block + block_count > current_block) || (block_count = 0)))
+ {
+ write_prg_byte(0x4025, 0x2D); // motor on without transfer
+ // waiting until drive is ready
+ while (1)
+ {
+ status = read_prg_byte(0x4032);
+ if (!(status & 2)) break; // ready
+ }
+ _delay_ms(FDS_PAUSE_BETWEEN_BLOCKS); // 9026 cycles
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ comm_start(COMMAND_FDS_READ_RESULT_BLOCK, file_size + 3);
+ write_prg_byte(0x4025, 0x6D); // start transfer
+ write_prg_byte(0x4025, 0xED); // enable IRQ
+ for (b = 0; b < file_size + 1; b++)
+ {
+ while (!IRQ_FIRED); // waiting for interrupt
+ uint8_t data = read_prg_byte(0x4031);
+ //write_prg_byte(0x4024, 0xFF); // clear interrupt
+ // status read also clears interrupt
+ status = read_prg_byte(0x4030);
+ end_of_head |= (status >> 6) & 1;
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ comm_send_byte(data);
+ while (IRQ_FIRED); // is interrupt flag cleared?
+ }
+ write_prg_byte(0x4025, 0xED); // enable CRC control
+ while (!IRQ_FIRED); // waiting for interrupt
+ read_prg_byte(0x4031);
+ write_prg_byte(0x4024, 0xFF); // clear interrupt
+ while (IRQ_FIRED); // is interrupt flag cleared?
+ status = read_prg_byte(0x4030);
+ end_of_head |= (status >> 6) & 1;
+ if ((current_block >= start_block) && ((current_block < start_block + block_count) || (block_count == 0)))
+ {
+ comm_send_byte(((status >> 4) & 1) ^ 1); // CRC check result
+ comm_send_byte(end_of_head); // end of head meet?
+ }
+ current_block++;
+ }
+ }
+
+ write_prg_byte(0x4025, 0x26); // reset, stop
+
+ _delay_ms(50);
+ comm_start(COMMAND_FDS_READ_RESULT_END, 0);
+ LED_GREEN_OFF;
+}
+
void get_mirroring()
{
comm_start(COMMAND_MIRRORING_RESULT, 4);
@@ -672,8 +865,8 @@ int main (void)
comm_init();
comm_start(COMMAND_PRG_STARTED, 0);
- uint16_t address;
- uint16_t length;
+ uint32_t address;
+ uint32_t length;
unsigned long int t = 0;
char led_down = 0;
@@ -799,6 +992,10 @@ int main (void)
comm_start(COMMAND_CHR_WRITE_DONE, 0);
break;
+ case COMMAND_FDS_READ_REQUEST:
+ read_fds_send(recv_buffer[0], recv_buffer[1]);
+ break;
+
case COMMAND_MIRRORING_REQUEST:
get_mirroring();
break;
diff --git a/dumper.h b/dumper.h
index 9f23863..994eb87 100644
--- a/dumper.h
+++ b/dumper.h
@@ -9,4 +9,9 @@
#define COOLBOY_DDR COOLBOY_DDRPORT(COOLBOY_GPIO_PORT)
#define COOLBOY_PIN COOLBOY_INPORT(COOLBOY_GPIO_PORT)
+#define IRQ_FIRED (!(PINF & (1<<6)))
+
+#define FDS_PAUSE_BEFORE_FIRST_BLOCK 300
+#define FDS_PAUSE_BETWEEN_BLOCKS 5
+
#endif
diff --git a/famicom-dumper.hex b/famicom-dumper.hex
index 5704a05..c0014df 100644
--- a/famicom-dumper.hex
+++ b/famicom-dumper.hex
@@ -1,269 +1,403 @@
-:100000000C9446000C9458000C9458000C94580022
-:100010000C9458000C9458000C9458000C94580000
-:100020000C9458000C9458000C9458000C945800F0
-:100030000C9458000C9458000C9458000C945800E0
-:100040000C9458000C9458000C946D010C945800BA
-:100050000C9458000C9458000C9458000C945800C0
-:100060000C9458000C9458000C9458000C945800B0
-:100070000C9458000C9458000C9458000C945800A0
-:100080000C9458000C9458000C94580011241FBE76
-:10009000CFEFD0E1DEBFCDBF29E0A0E0B1E001C0ED
-:1000A0001D92A531B207E1F70E9414030C945E087B
-:1000B0000C9400008BBB95BB95FD06C0809162003F
-:1000C0008061809362000895809162008F7E8093AA
-:1000D00062000895CF93DF93C2E6D0E028812E7F9F
-:1000E00028832881226028832FEF22BB11BA0E9427
-:1000F0005A0088818F7D888382E08A95F1F700C05D
-:1001000080B3988190629883988191609883DF9101
-:10011000CF910895CF93DF93C2E6D0E028812E7F60
-:1001200028832881226028832FEF22BB11BA2881DF
-:10013000206828830E945A00888181608883888192
-:100140008D7F8883C39AC49882E08A95F1F700C0B6
-:1001500080B3988192609883C49ADF91CF9108957B
-:100160001F93CF93DF93162FBC9ABB9AC49AC39A5E
-:10017000C2E6D0E028812260288328812068288375
-:100180000E945A009FEF91BB12BB888181608883D7
-:1001900088818D7F888382E08A95F1F700C0C398BB
-:1001A00082E08A95F1F700C0C39A1BBA15BA88811C
-:1001B0008061888388818260888392BB11BADF91D5
-:1001C000CF911F910895CF93DF93EC01809162004E
-:1001D0008E7F8093620080916200826080936200D3
-:1001E0008FEF81BB809162008F778093620062BB4A
-:1001F000CE010E945A0082E08A95F1F700C08091FA
-:10020000620081608093620080916200D7FD2CC003
-:1002100082608093620082E08A95F1F700C080914D
-:1002200062008E7F80936200809162008260809382
-:10023000620082E08A95F1F700C0809162008068D8
-:10024000809362008FEF82BB11BA1BBA15BA8091FE
-:10025000620080618093620080916200816080937F
-:100260006200DF91CF9108958D7F80936200D3CF9C
-:10027000CF93DF93EC01809162008E7F80936200C8
-:10028000809162008260809362008FEF82BB11BA1E
-:1002900080916200806880936200CE010E945A00C3
-:1002A0008091620081608093620080916200D7FD3E
-:1002B00010C082608093620082E08A95F1F700C0EE
-:1002C00080B390916200926090936200DF91CF9131
-:1002D00008958D7F80936200EFCF1F920F920FB62B
-:1002E0000F9211242F933F934F935F936F937F93BC
-:1002F0008F939F93AF93BF93EF93FF935F9B05C043
-:100300008CB10E9478025F99FBCFFF91EF91BF9172
-:10031000AF919F918F917F916F915F914F913F919D
-:100320002F910F900FBE0F901F901895CF93DF93D2
-:1003300064E070E082E10E943902C69A1BBA15BAE5
-:10034000C2E6D0E088818061888382E08A95F1F7F7
-:1003500000C081B182FB882780F90E9461021BBA2C
-:1003600084E085BB88818061888382E08A95F1F78B
-:1003700000C081B182FB882780F90E9461021BBA0C
-:1003800088E085BB88818061888382E08A95F1F767
-:1003900000C081B182FB882780F90E9461021BBAEC
-:1003A0008CE085BB88818061888382E08A95F1F743
-:1003B00000C081B182FB882780F90E9461021BBACC
-:1003C00015BA888180618883DF91CF91089581E09B
-:1003D00089B91092900088E98AB9E5E9F0E0808156
-:1003E0008660808308955D9BFECF8CB90895982F19
-:1003F00092959F709A3070F4905D8F708A3040F4BF
-:10040000805D5D9BFECF9CB95D9BFECF8CB908954E
-:10041000895CF7CF995CF1CFFC019081992339F089
-:1004200031965D9BFECF9CB991919111FACF0895C1
-:10043000411551056105710551F0FC01480F591F27
-:1004400081915D9BFECF8CB9E417F507C9F708953C
-:1004500090910801382F28E05CE8492F43279695B2
-:1004600040FD952736952150C1F7909308010C94D3
-:10047000F3011F93CF93DF93182FEB011092080124
-:1004800086E40E942802812F0E9428028C2F0E945D
-:1004900028028D2F0E942802D0930701C0930601E5
-:1004A0001092050110920401CD2B21F0DF91CF9124
-:1004B0001F91089580910801DF91CF911F910C94B5
-:1004C000F3010E9428028091040190910501019698
-:1004D000909305018093040120910601309107015A
-:1004E0008217930709F00895809108010C94F30195
-:1004F00090910001992319F0863409F00895109223
-:10050000000160910201709103016115710559F1BB
-:1005100090910101382F28E05CE8432F49279695F8
-:1005200040FD952736952150C1F790930101613028
-:10053000710509F447C0DCF062307105E9F1633000
-:10054000710539F52091090130910A01A901582B53
-:1005500050930A01409309016F5F7F4F709303012D
-:1005600060930201089510920B0190E0D3CF6115C2
-:10057000710579F4863481F381E08093000160E0B5
-:1005800070E082E00E9439026091020170910301E3
-:10059000E3CF9B0124503109283058E0350738F566
-:1005A0004091090150910A012417350770F4F901AF
-:1005B000E35FFE4F8083D0CF90E090930A01809359
-:1005C0000901CACF80930C01C7CF40910901509116
-:1005D0000A012417350709F0BFCF81E0911113C03C
-:1005E00080930B0110920301109202010895109262
-:1005F00003011092020181E08093000160E070E04D
-:1006000084E00C9439028093000160E070E083E0A4
-:100610000E943902E7CF109203011092020110925A
-:100620000B01109200010895CF93DF9300D000D00A
-:10063000CDB7DEB778940E94E70187B3806C87BBA3
-:1006400087EB809361008FEF8093620012981A9A73
-:1006500082BB11BA1BBA15BA909162009061909357
-:1006600062008ABB84BBBC98C498C798C6980E9495
-:100670000B0360E070E080E00E94390277247394FD
-:10068000BEE6AB2EB12C14E1212E312C66246A94E7
-:100690008FB589628FBD21E02EBD20E030E0E0E023
-:1006A00041E050E060E070E080910B01811135C0C5
-:1006B0008FB589628FBD7EBC403187E258076105E6
-:1006C000710508F451C0E11154C0C90101968E367C
-:1006D00091050CF456C0E1E09C012456310939BD66
-:1006E00028BD9C01C501821B930B853191050CF03F
-:1006F0005AC08B30910524F0A101481B590BCA0147
-:10070000880F991F909379008093780040E050E023
-:10071000BA0180910B01882359F210920B011092BB
-:1007200079001092780019BC18BC1FBC55E05EBD62
-:1007300080910C01833109F4B9C2C8F1853209F402
-:10074000D7C208F457C0873209F436C408F42AC364
-:10075000883209F4DDC38E3F09F09ACFF89414BEB5
-:10076000E0E0F8EF099594CF4F5F5F4F6F4F7F4FF9
-:100770009BCF2150310989F4E0E040E050E0BA011C
-:1007800093CF8436910524F02356310939BD28BD15
-:100790009C0140E050E0BA0187CF243631050CF4CB
-:1007A000A1CFC90199CF40E050E0BA017DCF893097
-:1007B00009F4F6C008F064C0863009F452C18730ED
-:1007C00009F41BC1853009F063CF65E070E080E07B
-:1007D0000E94390282E00E94610280E00E94610270
-:1007E00088E00E94610280E00E94610288E00E942D
-:1007F00061024ECF833209F40DC208F038C1823253
-:1008000009F046CF00910D0180910E0110E0182BE8
-:1008100030910F01398380911001432F50E0582B04
-:100820005C834B83C69AC49AC39ABC9ABB9A6B8169
-:100830007C8188E00E9439028B819C81892B71F038
-:10084000C8010E948A000E946102EB81FC813197FD
-:10085000FC83EB830F5F1F4FEF2B91F71BBA15BA89
-:10086000809162008061809362008091620082606A
-:1008700080936200C49AC39ABC98C498C69808CF63
-:100880008D30C9F18131A1F18B3009F001CF009198
-:100890000D0180910E0110E0182BF0910F01F983EA
-:1008A000809110012F2F30E0382B3C832B83C69A88
-:1008B0006B817C818CE00E9439024B815C81452BED
-:1008C00071F0C8010E946A000E9461028B819C81C4
-:1008D00001979C838B830F5F1F4F892B91F71BBA66
-:1008E00015BA80916200806180936200C698D0CE74
-:1008F0000E949601CDCEE0900D0180910E01F12C69
-:10090000F82A30910F01398380911001432F50E074
-:10091000582B5C834B83C79A452BD9F101E111E039
-:10092000F80191918F01809162008E7F8093620027
-:100930008091620082608093620061BA92BBC701BD
-:100940000E945A00809162008B7F80936200F2E0E7
-:10095000FA95F1F700C08091620084608093620094
-:1009600062BA11BA1BBA15BA809162008061809395
-:100970006200809162008160809362002FEFE21A32
-:10098000F20A4B815C81415051095C834B83452BBA
-:1009900039F6C79860E070E08EE00E94390278CEA8
-:1009A000E0900D0180910E01F12CF82A20910F01A9
-:1009B000298380911001422F50E0582B5C834B8398
-:1009C000C79A452B99F001E111E0F80161918F017F
-:1009D000C7010E94E300FFEFEF1AFF0A2B813C8161
-:1009E000215031093C832B83232B79F7C79860E092
-:1009F00070E08AE00E9439024BCE00910D01809197
-:100A00000E0110E0182B80910F0189838091100155
-:100A1000F981EF2FF0E0F82BFC83EB83C69A6B8112
-:100A20007C8188E00E9439022B813C81232B09F4D0
-:100A300056CFC8010E9438010E9461024B815C813F
-:100A4000415051095C834B830F5F1F4F452B89F742
-:100A50001BBA15BA80916200806180936200C698CB
-:100A600017CE60E070E081E00E94390211CE209143
-:100A70000D01298380910E01422F50E0582B5C8399
-:100A80004B8300910F018091100110E0182BC79A41
-:100A90000115110509F4B0C061E1862E61E0962EC2
-:100AA0002B813C81207C6401EB80FC80512C06C0B2
-:100AB000C701807C2817390709F04AC0F6018191E7
-:100AC0006F018F3F09F05394FFEFEF1AFF0A0150B7
-:100AD000110971F7552009F48FC060EF80E090E0B4
-:100AE0000E94B0006AEA8AEA9AE00E94B00065E5D6
-:100AF00085E595E00E94B00065E280E090E00E940C
-:100B0000B0005A94652D80E090E00E94B000F4019E
-:100B100060816F3F99F08B819C810E94B000F4014D
-:100B200041904F018B819C8101965520B9F09C83A7
-:100B30008B835A94F40160816F3F69F72B813C816C
-:100B40002F5F3F4F3C832B833FEF831A930ADFCF06
-:100B50005110C3CF4601FC82EB82A2CF69E280E054
-:100B600090E00E94B0001DBC1CBC2B813C81306811
-:100B70003C832B838CB59DB584389E4108F043C0DF
-:100B80008B819C810E948A00882E8B819C810E948F
-:100B90008A00982E8B819C810E948A00582E882D75
-:100BA000892586FF18C0892D852586FF14C081FC04
-:100BB00074C285FEDFCF63E070E08AE20E943902F2
-:100BC000882D0E946102892D0E946102852D0E945C
-:100BD0006102C7985DCD8B819C810E948A00982E0E
-:100BE0008B819C810E948A009812C4CF4910C2CF89
-:100BF0000115110509F0AECF60E070E08AE00E94B7
-:100C00003902C79845CD60E070E08AE20E9439025F
-:100C1000C7983ECDC79A60EF80E090E00E94B00098
-:100C20006AEA8AEA9AE00E94B00065E585E595E007
-:100C30000E94B00060E88AEA9AE00E94B0006AEA86
-:100C40008AEA9AE00E94B00065E585E595E00E9499
-:100C5000B00060E380E090E00E94B0001DBC1CBCCE
-:100C60008CB59DB58D389B45D0F480E090E80E940E
-:100C70008A0089838CB59DB58D389B4580F480E0D2
-:100C800090E80E948A008A8359815827547409F495
-:100C9000F6C189838CB59DB58D389B4580F360E0A6
-:100CA00070E08CE20E943902C798F2CCC79AC69ACB
-:100CB000809162008E7F80936200809162008260EA
-:100CC00080936200FFEF20E732E0F1502040304097
-:100CD000E1F700C0000080916200816080936200B3
-:100CE000C798C69860E070E084E10E943902D0CCD9
-:100CF000C79A60EF80E090E80E94E3006AEA8AEA1F
-:100D00009AE80E94E30065E585E595E80E94E30026
-:100D100060E88AEA9AE80E94E3006AEA8AEA9AE8C6
-:100D20000E94E30065E585E595E80E94E30060E345
-:100D300080E090E80E94E3001DBC1CBC8CB59DB512
-:100D40008D389B4508F0ABCF80E090E80E943801D9
-:100D500089838CB59DB58D389B4508F0A0CF80E088
-:100D600090E80E9438015981851771F089838CB50C
-:100D70009DB58D389B4508F092CF80E090E80E94A9
-:100D8000380159818513F2CFF981FF3F09F434CF3F
-:100D900061E070E08BE20E94390289810E94610269
-:100DA000C79876CC40900D0180910E01512C582AA5
-:100DB00020910F01298380911001422F50E0582B80
-:100DC0005C834B83C79A452B09F49BC051E1852E68
-:100DD00051E0952E9201207C64018201F12C06C025
-:100DE000C801807C2817390709F050C0F6018191AD
-:100DF0006F018F3F09F0F3940F5F1F4F4B815C81B0
-:100E0000415051095C834B83452B51F7FF2009F476
-:100E100078C060EF80E090E80E94E3006AEA8AEA26
-:100E20009AE80E94E30065E585E595E80E94E30005
-:100E300065E280E090E80E94E300FA94F9826F2D69
-:100E400080E090E80E94E300F40160816F3FB9F018
-:100E500072016894F7F8C7010E94E300F401219140
-:100E60004F012A833FEF431A530A4981442399F0E3
-:100E7000598151505983F40160816F3F49F74FEF19
-:100E8000441A540A5FEF851A950ADECFF110C1CFDC
-:100E9000460128019FCF69E280E090E80E94E300CC
-:100EA0001DBC1CBC8CB59DB584389E4108F0ABCEF2
-:100EB000C7010E943801882EC7010E943801982E70
-:100EC000C7010E943801582E882D892586FF09C048
-:100ED000892D852586FF05C081FCDFC085FEE2CF18
-:100EE0006ACEC7010E943801982EC7010E943801BE
-:100EF0009812D8CF8A818911D5CFEB81FC81EF2B55
-:100F000039F660E070E08AE00E943902C798C0CBF1
-:100F1000E0900D0180910E01F12CF82A00910F0153
-:100F20008091100110E0182BC69A0115110509F4E3
-:100F3000C2C01C821B82C7010E946A00EB81FC8137
-:100F4000E827FC83EB8388E090E00CC02B813C8198
-:100F50003695279541E0242740EA34273C832B83AC
-:100F6000019759F0FB81F0FDF1CFEB81FC81F69503
-:100F7000E795FC83EB830197A9F701501109FFEF77
-:100F8000EF1AFF0A01151105B1F61B812C81298387
-:100F90001BBA15BA8091620080618093620062E0A2
-:100FA00070E08CE00E943902812F0E9461028981E9
-:100FB0000E946102C6986CCB40910D0180910E0198
-:100FC00050E0582B60910F018091100170E0782B58
-:100FD000C69A62BA11BA80916200806880936200FA
-:100FE000809162008160809362008091620057FD71
-:100FF00058C08260809362006115710509F458C081
-:1010000080E090E04BBB55BBE2E0EA95F1F700C011
-:1010100020B3822728E030E009C096958795F1E05B
-:101020008F27F0EA9F272150310939F080FDF5CF55
-:101030009695879521503109C9F7615071094F5F25
-:101040005F4F61157105F1F68A8399838091620083
-:101050008260809362001BBA15BA80916200806141
-:101060008093620062E070E088E00E9439028A8129
-:101070000E94610289810E946102C69809CBFA81AF
-:10108000FF3F09F4B9CD61E070E08BE20E943902C4
-:101090008A810E946102C798FBCA63E070E089E21E
-:1010A0008DCD8D7F809362006115710509F0A8CF09
-:1010B00019821A82CBCF198210E06ACFF894FFCF41
+:100000000C9446000C9463000C9463000C94630001
+:100010000C9463000C9463000C9463000C946300D4
+:100020000C9463000C9463000C9463000C946300C4
+:100030000C9463000C9463000C9463000C946300B4
+:100040000C9463000C9463000C948E090C94630070
+:100050000C9463000C9463000C9463000C94630094
+:100060000C9463000C9463000C9463000C94630084
+:100070000C9463000C9463000C9463000C94630074
+:100080000C9463000C9463000C94630011241FBE55
+:10009000CFEFD0E1DEBFCDBF14E0A0E0B1E0E8E1FA
+:1000A000F6E102C005900D92A030B107D9F71CE02F
+:1000B000A0E0B4E001C01D92A531B107E1F70E94B4
+:1000C000BC010C940A0B0C9400008BBB95BB95FDF6
+:1000D00006C08091620080618093620008958091E3
+:1000E00062008F7E8093620008950F931F938C01AE
+:1000F000809162008E7F80936200809162008260B6
+:10010000809362008FEF82BB11BA80916200806899
+:1001100080936200C8010E94650080916200816046
+:100120008093620017FD0EC0809162008260809310
+:10013000620080B3909162009260909362001F9180
+:100140000F910895809162008D7F80936200F1CFBE
+:100150000F931F9302E610E0F80120812E7F208389
+:100160002081226020832FEF22BB11BA0E946500FC
+:10017000F80180818F7D808382E08A95F1F780B3DA
+:100180009081906290839081916090831F910F91F4
+:1001900008950F931F9302E610E0F80120812E7F4F
+:1001A00020832081226020832FEF22BB11BA20817F
+:1001B000206820830E946500F8018081816080832F
+:1001C00080818D7F8083C39AC49882E08A95F1F7FD
+:1001D00080B3908192609083C49A1F910F9108958B
+:1001E0000F931F938C01809162008E7F8093620039
+:1001F000809162008260809362008FEF81BB80916A
+:1002000062008F778093620062BBC8010E94650024
+:1002100082E08A95F1F780916200816080936200AC
+:1002200017FD29C08091620082608093620092E095
+:10023000892F8A95F1F7809162008E7F809362000A
+:10024000809162008260809362009A95F1F78091BC
+:1002500062008068809362008FEF82BB11BA80E0F9
+:1002600090E00E946500809162008160809362004E
+:100270001F910F910895809162008D7F809362009D
+:10028000D6CF90680E94F0000895EF92FF920F93EE
+:100290001F93E62EBC9ABB9AC49AC39A02E610E05A
+:1002A000F8012081226020832081206820830E9421
+:1002B0006500FF24FA94F1BAE2BAF8018081816006
+:1002C000808380818D7F808382E0982F9A95F1F7DB
+:1002D000C3988A95F1F7C39A80E090E00E94650088
+:1002E000F801808182608083F2BA11BA1F910F9168
+:1002F000FF90EF9008951F9382E164E070E00E9408
+:10030000310AC69A80E090E00E94650012E0812FD9
+:100310008A95F1F781B18695869581700E94190AB8
+:1003200080E094E00E946500812F8A95F1F781B109
+:100330008695869581700E94190A80E098E00E9457
+:100340006500812F8A95F1F781B186958695817038
+:100350000E94190A80E09CE00E9465001A95F1F75E
+:1003600081B18695869581700E94190A80E090E09F
+:100370000E9465001F9108952F923F924F925F92C5
+:100380006F927F928F929F92AF92BF92CF92DF92A5
+:10039000EF92FF920F931F93DF93CF93CDB7DEB70A
+:1003A000A9970FB6F894DEBF0FBECDBF78940E9418
+:1003B000B70987B3806C87BB87EB809361001FEF21
+:1003C0001093620012981A9A12BB11BA80E090E062
+:1003D0000E9465001ABB14BBBC98C498C798C69805
+:1003E0000E94020A80E060E070E00E94310A48EC5E
+:1003F000642E712C8FB589628FBD21E02EBD21E066
+:1004000030E040E050E0E0E060E070E080910B041C
+:10041000882309F042C08FB589628FBD81E08EBD0F
+:10042000203197E2390790E0490790E0590708F436
+:1004300070C0EE2309F072C06F5F7F4F6E3671059A
+:100440000CF0E1E06436710534F06456704079BD1B
+:1004500068BD6C597F4FEE2309F46AC08EE690E0C8
+:10046000861B970B853191050CF062C08B3091058E
+:100470002CF024E130E0281B390BC901880F991FAB
+:10048000909379008093780020E030E040E050E0E5
+:1004900080910B04882309F4BECF10920B041092B4
+:1004A000790010927800809178009091790099BD40
+:1004B00088BD88B599B58FBD35E03EBD80910C04EF
+:1004C000823209F42CC68332C0F5893009F437C171
+:1004D0008A3008F09FC0863009F498C1873009F44B
+:1004E00062C1853009F086CF80E065E070E00E944F
+:1004F000310A82E00E94190A80E00E94190A88E00D
+:100500000E94190A80E00E94190A88E00E94190AD4
+:1005100071CF2F5F3F4F4F4F5F4F78CF615070408B
+:1005200009F090CF20E030E040E050E0E0E06ECF16
+:1005300020E030E040E050E069CF863209F4F5C3B6
+:10054000873208F055C0843209F418C5853208F4A2
+:10055000C5C4C79A80E090E060EF0E9441018AEA3A
+:100560009AE06AEA0E94410185E595E065E50E940E
+:1005700041018AEA9AE060E80E9441018AEA9AE031
+:100580006AEA0E94410185E595E065E50E94410126
+:1005900080E090E060E30E9441011DBC1CBC8CB572
+:1005A0009DB58D589B45E8F4EE24EA94FE2C02C0DC
+:1005B000E12EFF2480E090E80E947500182F3FEFA5
+:1005C000E3163FEFF30641F090E0EFEFEE22FF2459
+:1005D0008E159F0509F40BC68CB59DB58D589B45AE
+:1005E00038F38CE260E070E00E94310AC79802CFD5
+:1005F000883209F458C3883208F4FAC28D3209F4FB
+:100600000BC18E3F09F0F6CEF89414BEE0E0F8EF8F
+:100610000995F0CE8D30C1F18E3008F0BFC58B301A
+:1006200009F0E8CEE0900D04F0900E0490910F04D4
+:10063000809110048D8F1C8E092F10E02C8D3D8D24
+:10064000022B132BC69A8CE0B8010E94310A0115C7
+:100650001105A1F0FF8E1E8EFF248E8D9F8DE82A3E
+:10066000F92AC7010E94A8000E94190A01501040EF
+:100670000894E11CF11C0115110599F780E090E048
+:100680000E946500C698B6CE30910D0420910E04EC
+:1006900090910F04809110048DA31CA2E92EFF24D9
+:1006A0008CA19DA1E82AF92AC79AE114F10409F462
+:1006B0003FC02FA31EA2032F10E0EEA1FFA10E2B1F
+:1006C0001F2BCC24DD24F601E35FFB4F9481809146
+:1006D00062008E7F809362008091620082608093CE
+:1006E0006200FFEFF1BB92BBC601800F911F0E9419
+:1006F0006500809162008B7F8093620082E08A9522
+:10070000F1F7809162008460809362002FEF22BB3A
+:1007100011BA80E090E00E946500809162008160E3
+:10072000809362000894C11CD11CEC14FD0459F69E
+:10073000C7988EE060E070E00E94310A5BCE309195
+:100740000D0420910E0490910F04809110048D8768
+:100750001C86E92EFF24EC85FD85EE2AFF2AC79A28
+:10076000E114F104C9F02F871E86032F10E02E85B7
+:100770003F85022B132BCC24DD24F601E35FFB4FD6
+:10078000C601800F911F64810E94F0000894C11C73
+:10079000D11CEC14FD0489F7C7988AE060E070E092
+:1007A0000E94310A27CEE0900D04F0900E04909143
+:1007B0000F04809110048D831C82092F10E08C811E
+:1007C0009D81082B192BC69A88E0B8010E94310A36
+:1007D0000115110509F452CFFF821E82FF24EE811C
+:1007E000FF81EE2AFF2AC7010E9475000E94190AA4
+:1007F000015010400894E11CF11C0115110599F7F6
+:1008000080E090E00E946500C698F4CD81E060E051
+:1008100070E00E94310AEECDC0900D0430900E04BD
+:1008200082E290E460E00E94F00083E290E460E005
+:100830000E94F00083E290E461E00E94F00085E213
+:1008400090E46EE20E94F00082E390E40E94750062
+:1008500080FDFACF85E290E46EE20E94F00020E491
+:100860003FE1C3010197F1F721503040D1F785E214
+:1008700090E46FE20E94F00085E290E46DE20E9455
+:10088000F00024EC39E0C3010197F1F7215030402A
+:10089000D1F785E290E46EE20E94F00085E290E4F8
+:1008A0006FE20E94F00085E290E46DE20E94F000A9
+:1008B00082E390E40E94750081FDFACF28EB3BE0D3
+:1008C000C3010197F1F721503040D1F7C69ACC20EF
+:1008D00029F48EE26AE370E00E94310A85E290E436
+:1008E0006DE60E94F00085E290E46DEE0E94F0005B
+:1008F00000E0EE24FF240699FECF81E390E40E94FD
+:100900007500182F80E390E40E947500829586950B
+:1009100086958170082BCC2009F4DEC0069BFECFA3
+:100920000894E11CF11C38E3E316F10421F785E299
+:1009300090E46DEE0E94F0000699FECF81E390E412
+:100940000E94750084E290E46FEF0E94F000069B25
+:10095000FECF80E390E40E947500182F1295169543
+:1009600016951170102BCC2051F482958F7091E068
+:10097000892781700E94190A812F0E94190A112368
+:1009800009F08CC08C2C99245401A30CB11CE2E01A
+:10099000AE16B1040CF040C45401DD24D3943324CA
+:1009A00081E090E08A159B050CF078C085E290E428
+:1009B0006DE20E94F00082E390E40E94750081FDE8
+:1009C000FACF80E197E20197F1F7DC1428F08EE28C
+:1009D00062E170E00E94310A85E290E46DE60E94D7
+:1009E000F00085E290E46DEE0E94F00000E019A6B0
+:1009F00018A6EE24FF240699FECF81E390E40E941E
+:100A00007500182F80E390E40E947500829586950A
+:100A100086958170082BDC1418F0812F0E94190A2A
+:100A2000E8A5F9A53D9709F44DC028A539A52E30B4
+:100A3000310509F44CC0069BFECF88A599A5019607
+:100A400099A788A74097B9F685E290E46DEE0E94D9
+:100A5000F0000699FECF81E390E40E94750084E2E5
+:100A600090E46FEF0E94F000069BFECF80E390E4DD
+:100A70000E947500182F1295169516951170102B5F
+:100A8000DC1450F082958F7091E0892781700E946C
+:100A9000190A812F0E94190A112311F185E290E4AD
+:100AA00066E20E94F00024EF31E0C3010197F1F704
+:100AB00021503040D1F78FE260E070E00E94310AAF
+:100AC000C69898CC812F90E0E82AF92AB4CF512E0D
+:100AD0004424E428F528AFCF812F0E94190A1ECFA5
+:100AE000D3948D2D90E08A159B055CF0332420E093
+:100AF00030E05901A80CB91C8A159B050CF456CF9F
+:100B0000CDCF85E290E46DE20E94F00082E390E4B4
+:100B10000E94750081FDFACF80E197E20197F1F71D
+:100B2000DC1430F0B7016D5F7F4F8EE20E94310A16
+:100B300085E290E46DE60E94F00085E290E46DEEBF
+:100B40000E94F0000894E11CF11CE114F104F9F09A
+:100B5000AA24BB240699FECF81E390E40E9475008D
+:100B6000082F80E390E40E94750082958695869513
+:100B70008170182BDC1418F0802F0E94190A069B34
+:100B8000FECF0894A11CB11CAE14BF0418F385E27B
+:100B900090E46DEE0E94F0000699FECF81E390E4B0
+:100BA0000E94750084E290E46FEF0E94F000069BC3
+:100BB000FECF80E390E40E947500082F0295069511
+:100BC00006950170012BDC1450F082958F70E1E0E6
+:100BD0008E2781700E94190A802F0E94190A002313
+:100BE00009F05CCFD394232D30E08D2D90E081CFA0
+:100BF00090910D0480910E0489871886E92EFF24B8
+:100C000028853985E22AF32A90910F0480911004F7
+:100C10008B871A86092F10E08A859B85082B192B54
+:100C2000C69A9FEF92BB11BA809162008068809350
+:100C3000620080916200816080936200F7FCE6C2EE
+:100C4000809162008260809362000115110509F4B1
+:100C50005FC380E090E0EBBAF5BA22E02A95F1F7A5
+:100C600060B30E94F80A015010400894E11CF11C86
+:100C70000115110581F7182F092F809162008260FC
+:100C80008093620080E090E00E94650088E062E06E
+:100C900070E00E94310A812F0E94190A802F0E9461
+:100CA000190AC698A7CB30910D0420910E0490919B
+:100CB0000F048091100489A318A2E92EFF24E8A153
+:100CC000F9A1EE2AFF2AC69AE114F10409F423C31C
+:100CD0002BA31AA2C32EDD242AA13BA1C22AD32A08
+:100CE00000E010E0C6010E94A800682FC8010E9421
+:100CF000F80A8C010894E108F1080894C11CD11C81
+:100D0000E114F10479F7F82E80E090E00E9465008C
+:100D10008CE062E070E00E94310A8F2D0E94190A77
+:100D2000812F0E94190AC69865CB30910D0420913D
+:100D30000E0490910F0480911004898F188E092F52
+:100D400010E0888D998D082B192BC79A0115110574
+:100D500009F4DEC12B8F1A8EE32FF0E02A8D3B8D34
+:100D6000E22BF32BF9A7E8A791E1892E94E0992EC5
+:100D700019822224332428A539A5207CA8A4B9A44B
+:100D80006401FF2405C0C501807C2817390781F460
+:100D9000F60180818F3F09F0F3940894A11CB11CE7
+:100DA000015010400894C11CD11C0115110559F7C0
+:100DB000FF2041F40115110509F4AAC1B9A6A8A69E
+:100DC0004601D9CF80E090E060EF0E9441018AEABD
+:100DD0009AE06AEA0E94410185E595E065E50E9496
+:100DE000410180E090E065E20E9441016F2D615079
+:100DF00080E090E00E94410109C028A539A52F5F3D
+:100E00003F4F39A728A70894811C911CF4016081E9
+:100E10006F3F51F088A599A50E944101F401F0812E
+:100E2000F983FA9428A439A4FF2039F780E090E0F0
+:100E300069E20E9441011DBC1CBCC101906899A7D8
+:100E400088A78CB59DB584589E4108F040C088A500
+:100E500099A50E947500E82E88A599A50E947500A5
+:100E6000F82E88A599A50E947500982E8F2D8E25A5
+:100E700086FF18C0892D8F2586FF14C0E1FCC4C1F0
+:100E8000E5FEDFCF8AE263E070E00E94310A8E2D3A
+:100E90000E94190A8F2D0E94190A892D0E94190A91
+:100EA000C798A8CA88A599A50E947500F82E88A59C
+:100EB00099A50E947500F81621F6F981FF1509F42D
+:100EC00079CF8CB59DB584589E4108F4C0CF8AE295
+:100ED00060E070E00E94310AC7988CCAC79A80E02F
+:100EE00090E060EF0E9445018AEA9AE06AEA0E9477
+:100EF000450185E595E065E50E9445018AEA9AE0AD
+:100F000060E80E9445018AEA9AE06AEA0E94450187
+:100F100085E595E065E50E94450180E090E060E3AD
+:100F20000E9445011DBC1CBC8CB59DB58D589B45D0
+:100F300008F057CBEE24EA94FE2C02C0E12EFF24E9
+:100F400080E090E80E94C900182F2FEFE2162FEFE3
+:100F5000F20649F090E0E826F92634E4E322FF2483
+:100F6000EF2809F444C18CB59DB58D589B4530F3ED
+:100F70008CE260E070E00E94310A38CB30910D04C1
+:100F800020910E0490910F04809110048D8B1C8A87
+:100F9000092F10E08C899D89082B192BC79A011500
+:100FA000110509F4B5C02F8B1E8AE32FF0E02E89BE
+:100FB0003F89E22BF32BF9A7E8A721E1822E24E059
+:100FC000922E33241B821A8228A539A5207CA8A43E
+:100FD000B9A46401FF2405C0C501807C2817390726
+:100FE00081F4F60180818F3F09F0F3940894A11CED
+:100FF000B11C015010400894C11CD11C01151105F1
+:1010000059F7FF2041F40115110509F481C0B9A673
+:10101000A8A64601D9CF80E090E060EF0E9445018C
+:101020008AEA9AE06AEA0E94450185E595E065E56D
+:101030000E94450180E090E065E20E9445016F2D2D
+:10104000615080E090E00E94450108C088A599A504
+:10105000019699A788A70894811C911CF4016081CE
+:101060006F3F59F088A599A50E944501F401308091
+:10107000FA9428A539A53B832A83FF2039F780E01D
+:1010800090E069E20E9445011DBC1CBCEA81FB8125
+:10109000F068F9A7E8A78CB59DB584589E4100F586
+:1010A00088A599A50E94C900E82E88A599A50E9447
+:1010B000C900F82E88A599A50E94C900982E8F2DE9
+:1010C0008E2586FF14C0892D8F2586FF10C0E1FC78
+:1010D0009BC0E5FCD7CE8CB59DB584589E4100F3EE
+:1010E0008AE260E070E00E94310AC79883C988A54F
+:1010F00099A50E94C900F82E88A599A50E94C9004B
+:10110000F81649F63F1439F60115110509F07FCF9D
+:101110008AE060E070E00E94310AC7986BC9E090F5
+:101120000D04F0900E0490910F0480911004898BAF
+:10113000188A092F10E088899989082B192BC69ADB
+:10114000C49AC39ABC9ABB9A88E0B8010E94310A3B
+:1011500001151105A1F0FB8A1A8AFF24EA89FB898F
+:10116000EE2AFF2AC7010E94C9000E94190A0150F5
+:1011700010400894E11CF11C0115110599F780E05D
+:1011800090E00E946500809162008260809362001E
+:10119000C49AC39ABC98C498C6982CC9813121F1CD
+:1011A000833109F027C9C79AC69A809162008E7F61
+:1011B000809362008091620082608093620028EEDA
+:1011C00033E0C3010197F1F721503040D1F780910E
+:1011D0006200816080936200C798C69884E160E0F5
+:1011E00070E00E94310A06C90E947B0103C91F3FBB
+:1011F00009F483C08BE261E070E00E94310A812F24
+:101200000E94190AC798F6C889E23DCE8091620013
+:101210008D7F8093620019CD85E290E46DE20E949B
+:10122000F00082E390E40E94750081FDFACF80E136
+:1012300097E20197F1F7F1E0FC1528F08EE264E007
+:1012400070E00E94310A85E290E46DE60E94F000B1
+:1012500085E290E46DEE0E94F00000E0EE24FF24B1
+:101260000699FECF81E390E40E947500182F80E379
+:1012700090E40E9475008295869586958170082B72
+:1012800021E02C1508F040C0069BFECF0894E11C1D
+:10129000F11C32E0E316F10419F785E290E46DEEFB
+:1012A0000E94F0000699FECF81E390E40E94750051
+:1012B00084E290E46FEF0E94F000069BFECF80E393
+:1012C00090E40E947500182F1295169516951170CE
+:1012D000102B91E09C1548F082958F7089278170C2
+:1012E0000E94190A812F0E94190A112309F0D6CBF6
+:1012F00082E0D82E82E090E055CB8AE060E070E09A
+:101300000E94310AC79876C8812F0E94190ABCCF63
+:1013100010E000E0B2CCFF2410E0F6CC1F920F9258
+:101320000FB60F9211242F933F934F935F936F93B8
+:101330007F938F939F93AF93BF93EF93FF935F9BA5
+:1013400005C08CB10E94560A5F99FBCFFF91EF91C7
+:10135000BF91AF919F918F917F916F915F914F91CD
+:101360003F912F910F900FBE0F901F90189581E025
+:1013700089B91092900088E98AB9E5E9F0E08081A6
+:101380008660808308955D9BFECF8CB90895982F69
+:1013900092959F709A3070F4905D8F708A3040F40F
+:1013A000805D5D9BFECF9CB95D9BFECF8CB908959F
+:1013B000895CF7CF995CF1CFFC018081882339F0FB
+:1013C0005D9BFECF8CB9319680818823C9F7089543
+:1013D0009C01411551056105710599F080E090E08F
+:1013E000A0E0B0E0F901E80FF91FE0815D9BFECFBE
+:1013F000ECB90196A11DB11D84179507A607B70783
+:1014000088F30895109206041092050410920B04BC
+:101410001092080408951F93182F80910004612FE3
+:101420000E94F10A80930004812F0E94C3091F913A
+:1014300008950E940B0A8091030490910404019680
+:1014400090930404809303042091010430910204DA
+:101450008217930709F00895809100040E94C30940
+:101460000895FF920F931F93F82E8B0110920004A2
+:1014700086E40E940B0A8F2D0E940B0A802F0E9487
+:101480000B0A812F0E940B0A10930204009301049F
+:101490001092040410920304012B21F480910004A3
+:1014A0000E94C3091F910F91FF9008951F93182F59
+:1014B00080910804882321F0163411F01F910895BB
+:1014C000109208048091050490910604892B21F460
+:1014D0001092070410920B0480910704612F0E9460
+:1014E000F10A282F809307044091050450910604C7
+:1014F0004130510559F1423051050CF445C042309C
+:101500005105D9F14330510559F1FA01349788E07A
+:10151000E830F80708F04FC08091090490910A0460
+:10152000E817F90708F443C08091090490910A0470
+:10153000E817F90769F4222309F04AC081E0809393
+:101540000B041092060410920504B8CF10930C04FB
+:101550004F5F5F4F50930604409305041F91089519
+:101560002091090430910A04912F80E0822B932B63
+:1015700090930A0480930904EBCF812F90E090931D
+:101580000A0480930904E4CF4115510509F0BDCF49
+:101590001634F1F281E08093080482E060E070E0AC
+:1015A0000E94310A4091050450910604D1CFE35FB7
+:1015B000FB4F1083CDCF109206041092050481E0FA
+:1015C0008093080484E060E070E00E94310A76CFE6
+:1015D00081E08093080483E060E070E00E94310ABB
+:1015E000B0CF6827E0E0F1E0E60FF11D80810895BB
+:1015F0009C01E62FF0E0E827F927F070EE0FFF1FBF
+:10160000E050FE4F232F33278081918128273927EF
+:08161000C9010895F894FFCF11
+:10161800005EBCE2613FDD83C29C7E20A3FD1F41CA
+:101628009DC3217FFCA2401E5F01E3BD3E6082DCBA
+:10163800237D9FC1421CFEA0E1BF5D0380DE3C62AA
+:10164800BEE0025CDF81633D7C22C09E1D43A1FF9A
+:101658004618FAA427799BC584DA3866E5BB59078A
+:10166800DB856739BAE406581947A5FB7826C49A7A
+:10167800653BD987045AB8E6A7F91B45C6987A246A
+:10168800F8A6441A99C7257B3A6486D85B05E7B95A
+:101698008CD2306EEDB3510F4E10F2AC2F7193CD4A
+:1016A800114FADF3702ECC92D38D6F31B2EC0E503A
+:1016B800AFF1134DCE90722C6D33D18F0C52B0EE2A
+:1016C800326C8ED0530DEFB1F0AE4C1291CF2D731A
+:1016D800CA947628ABF517490856B4EA6937D58B0A
+:1016E8005709EBB536688AD495CB2977F4AA4816FA
+:1016F800E9B7550B88D6346A2B7597C94A14F6A8EA
+:10170800742AC896154BA9F7B6E80A54D7896B35D9
+:101718000000C1C081C1400101C3C003800241C2B1
+:1017280001C6C006800741C70005C1C581C4400481
+:1017380001CCC00C800D41CD000FC1CF81CE400E31
+:10174800000AC1CA81CB400B01C9C009800841C841
+:1017580001D8C018801941D9001BC1DB81DA401AB1
+:10176800001EC1DE81DF401F01DDC01D801C41DC81
+:101778000014C1D481D5401501D7C017801641D6B1
+:1017880001D2C012801341D30011C1D181D04010C1
+:1017980001F0C030803141F10033C1F381F24032B1
+:1017A8000036C1F681F7403701F5C035803441F481
+:1017B800003CC1FC81FD403D01FFC03F803E41FE31
+:1017C80001FAC03A803B41FB0039C1F981F8403841
+:1017D8000028C1E881E9402901EBC02B802A41EAB1
+:1017E80001EEC02E802F41EF002DC1ED81EC402C81
+:1017F80001E4C024802541E50027C1E781E64026B1
+:101808000022C1E281E3402301E1C021802041E0C0
+:1018180001A0C060806141A10063C1A381A24062B0
+:101828000066C1A681A7406701A5C065806441A480
+:10183800006CC1AC81AD406D01AFC06F806E41AE30
+:1018480001AAC06A806B41AB0069C1A981A8406840
+:101858000078C1B881B9407901BBC07B807A41BAB0
+:1018680001BEC07E807F41BF007DC1BD81BC407C80
+:1018780001B4C074807541B50077C1B781B64076B0
+:101888000072C1B281B3407301B1C071807041B0C0
+:101898000050C190819140510193C05380524192B0
+:1018A8000196C056805741970055C1958194405480
+:1018B800019CC05C805D419D005FC19F819E405E30
+:1018C800005AC19A819B405B0199C0598058419840
+:1018D8000188C04880494189004BC18B818A404AB0
+:1018E800004EC18E818F404F018DC04D804C418C80
+:1018F8000044C184818540450187C04780464186B0
+:101908000182C042804341830041C18181804040BF
:00000001FF