diff --git a/arduino/.cproject b/arduino/.cproject deleted file mode 100644 index eeec63d..0000000 --- a/arduino/.cproject +++ /dev/null @@ -1,212 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/arduino/.gitignore b/arduino/.gitignore deleted file mode 100644 index 9337138..0000000 --- a/arduino/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -/Debug/ -/Bootloader/ -/Flash/ diff --git a/arduino/.project b/arduino/.project deleted file mode 100644 index 08b0e42..0000000 --- a/arduino/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - mac-floppy-emu - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean,full,incremental, - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - de.innot.avreclipse.core.avrnature - - diff --git a/arduino/.settings/org.eclipse.cdt.core.prefs b/arduino/.settings/org.eclipse.cdt.core.prefs deleted file mode 100644 index 206bd4d..0000000 --- a/arduino/.settings/org.eclipse.cdt.core.prefs +++ /dev/null @@ -1,17 +0,0 @@ -eclipse.preferences.version=1 -environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/LANG/delimiter=\: -environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/LANG/operation=replace -environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/LANG/value=en-US -environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/PATH/delimiter=\: -environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/PATH/operation=replace -environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/PATH/value=/opt/local/bin\:/usr/bin\:/bin\:/usr/sbin\:/sbin -environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/append=true -environment/project/de.innot.avreclipse.configuration.app.debug.46313178.1895685496/appendContributed=true -environment/project/de.innot.avreclipse.configuration.app.debug.46313178/LANG/delimiter=\: -environment/project/de.innot.avreclipse.configuration.app.debug.46313178/LANG/operation=replace -environment/project/de.innot.avreclipse.configuration.app.debug.46313178/LANG/value=en-US -environment/project/de.innot.avreclipse.configuration.app.debug.46313178/PATH/delimiter=\: -environment/project/de.innot.avreclipse.configuration.app.debug.46313178/PATH/operation=replace -environment/project/de.innot.avreclipse.configuration.app.debug.46313178/PATH/value=/usr/local/arduinotool/bin\:/opt/local/bin\:/usr/bin\:/bin\:/usr/sbin\:/sbin -environment/project/de.innot.avreclipse.configuration.app.debug.46313178/append=true -environment/project/de.innot.avreclipse.configuration.app.debug.46313178/appendContributed=true diff --git a/arduino/CPLD-Xilinx/firmware.xvf b/arduino/CPLD-Xilinx/firmware.xvf deleted file mode 100755 index 443eb73..0000000 Binary files a/arduino/CPLD-Xilinx/firmware.xvf and /dev/null differ diff --git a/arduino/CPLD-Xilinx/floppyemu.prj b/arduino/CPLD-Xilinx/floppyemu.prj deleted file mode 100755 index 08e89be..0000000 --- a/arduino/CPLD-Xilinx/floppyemu.prj +++ /dev/null @@ -1 +0,0 @@ -verilog work "floppyemu.v" diff --git a/arduino/CPLD-Xilinx/floppyemu.ucf b/arduino/CPLD-Xilinx/floppyemu.ucf deleted file mode 100755 index 56ecd5a..0000000 --- a/arduino/CPLD-Xilinx/floppyemu.ucf +++ /dev/null @@ -1,41 +0,0 @@ -#PACE: Start of Constraints generated by PACE -#PACE: Start of PACE I/O Pin Assignments -NET "stepAck_diskInserted" LOC = "P8" ; -NET "_enable" LOC = "P20" ; -NET "_rst" LOC = "P37" ; -NET "_wreq" LOC = "P18" ; -NET "_wreqMCU" LOC = "P5" ; -NET "byteReady_tk0" LOC = "P7" ; -NET "ca0" LOC = "P12" ; -NET "ca1" LOC = "P13" ; -NET "ca2" LOC = "P14" ; -NET "clk" LOC = "P43" ; -NET "data<0>" LOC = "P31" ; -NET "data<1>" LOC = "P32" ; -NET "data<2>" LOC = "P33" ; -NET "data<3>" LOC = "P34" ; -NET "data<4>" LOC = "P36" ; -NET "data<5>" LOC = "P38" ; -NET "data<6>" LOC = "P41" ; -NET "driveCurrentSide" LOC = "P3" ; -NET "stepDirectionMotorOn" LOC = "P1" ; -NET "driveTach" LOC = "P28" ; -NET "ejectRequest" LOC = "P30" ; -NET "led" LOC = "P40" ; -NET "lstrb" LOC = "P16" ; -NET "outputEnable" LOC = "P2" ; -NET "rd" LOC = "P21" ; -NET "rdAckWrTick" LOC = "P44" ; -NET "SEL" LOC = "P19" ; -NET "stepRequest" LOC = "P39" ; -NET "wr" LOC = "P22" ; -NET "zero" LOC = "P6" ; -NET "pwm" LOC = "P23" ; -NET "test" LOC = "P27" ; - -#PACE: Start of PACE Area Constraints -#PACE: Start of PACE Prohibit Constraints -#PACE: End of Constraints generated by PACE -#Created by Constraints Editor (xc9572xl-vq44-10) - 2013/11/07 -NET "clk" TNM_NET = clk; -TIMESPEC TS_clk = PERIOD "clk" 50 ns HIGH 50%; diff --git a/arduino/CPLD-Xilinx/floppyemu.v b/arduino/CPLD-Xilinx/floppyemu.v deleted file mode 100755 index 7721945..0000000 --- a/arduino/CPLD-Xilinx/floppyemu.v +++ /dev/null @@ -1,433 +0,0 @@ -/* - Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved. - - Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported - license. (CC BY-NC 3.0) The terms of the license may be viewed at - http://creativecommons.org/licenses/by-nc/3.0/ - - Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/ - - Permissions beyond the scope of this license may be available at www.bigmessowires.com - or from mailto:steve@bigmessowires.com. - - -------------------------------------------------------------------------------------- - - Disk registers (read): - State-control lines Register - CA2 CA1 CA0 SEL addressed Information in register - - 0 0 0 0 DIRTN Head step direction (0 = toward track 79, 1 = toward track 0) - 0 0 0 1 CSTIN Disk in place (0 = disk is inserted) - 0 0 1 0 STEP Drive head stepping (setting to 0 performs a step, returns to 1 when step is complete) - 0 0 1 1 WRTPRT Disk locked (0 = locked) - 0 1 0 0 MOTORON Drive motor running (0 = on, 1 = off) - 0 1 0 1 TK0 Head at track 0 (0 = at track 0) - 0 1 1 0 SWITCHED Disk switched (1 = yes?) SWIM3: relax, also eject in progress - 0 1 1 1 TACH GCR: Tachometer (produces 60 pulses for each rotation of the drive motor), MFM: Index pulse - 1 0 0 0 RDDATA0 Read data, lower head, side 0 - 1 0 0 1 RDDATA1 Read data, upper head, side 1 - 1 0 1 0 SUPERDR Drive is a Superdrive (0 = no, 1 = yes) SWIM3: two meg drive. - 1 0 1 1 MFM_MODE SWIM3: MFM_MODE, 1 = yes (opposite of writing?) - 1 1 0 0 SIDES Single- or double-sided drive (0 = single side, 1 = double side), SWIM: 0 = 4MB, 1 = not 4MB - 1 1 0 1 READY 0 = yes, SWIM3: SEEK_COMPLETE - 1 1 1 0 INSTALLED 0 = yes, only used by SWIM, not IWM? SWIM3: drive present. - 1 1 1 1 HSHK_HD 400K/800K: implements ready handshake if 1, Superdrive: Inserted disk capacity (0 = HD, 1 = DD), SWIM3: 1 = ONE_MEG_MEDIA - - - Disk registers (write): - Control lines Register - CA1 CA0 SEL addressed Register function - - 0 0 0 DIRTN Set stepping direction (0 = toward track 79, 1 = toward track 0), SWIM3: SEEK_POSITIVE - 0 0 1 SWITCHED Reset disk switched flag (writing 1 sets switch flag to 0) - 0 1 0 STEP Step the drive head one track (setting to 0 performs a step, returns to 1 when step is complete) - 1 0 0 MOTORON Turn drive motor on/off (0 = on, 1 = off) - 1 0 0 TWOMEGMEDIA_CHECK The first time zero is written, changes the behavior when reading SIDES - 0 1 1 MFM_MODE 0 = MFM, 1 = GCR - 1 1 0 EJECT Eject the disk (writing 1 ejects the disk) - 1 1 0 INDEX if writing 0 -*/ - -`define DRIVE_REG_DIRTN 0 -`define DRIVE_REG_CSTIN 1 -`define DRIVE_REG_STEP 2 -`define DRIVE_REG_WRTPRT 3 -`define DRIVE_REG_MOTORON 4 -`define DRIVE_REG_TK0 5 -`define DRIVE_REG_EJECT 6 -`define DRIVE_REG_TACH 7 -`define DRIVE_REG_RDDATA0 8 -`define DRIVE_REG_RDDATA1 9 -`define DRIVE_REG_SUPERDR 10 -`define DRIVE_REG_UNUSED 11 -`define DRIVE_REG_SIDES 12 -`define DRIVE_REG_READY 13 -`define DRIVE_REG_INSTALLED 14 -`define DRIVE_REG_HSHK_HD 15 - -`define FIRMWARE_VERSION_NUMBER 11 - -module floppyemu( - input clk, - - // Macintosh interface - input ca0, // PH0 - input ca1, // PH1 - input ca2, // PH2 - input lstrb, // PH3 - input SEL, // HDSEL from VIA - input _enable, - input wr, - input _wreq, - input pwm, // unused - output rd, - - // microcontroller interface - input _rst, - - output stepDirectionMotorOn, - output reg stepRequest, - input stepAck_diskInserted, - - output _wreqMCU, - output reg rdAckWrTick, - output reg driveCurrentSide, - output reg ejectRequest, - - input driveTach, - input byteReady_tk0, - - input outputEnable, - inout [6:0] data, - - output zero, - - // status display - output led, - - // debugging - output test -); - - /********** drive state data **********/ - reg _driveRegTK0; - reg _driveRegMotorOn; - reg driveRegStepDirection; - reg _driveRegWriteProtect; - reg _driveRegDiskInserted; - reg _driveRegMFMMode; - - /********** serial to parallel interface **********/ - // GCR: One bit every 2 microseconds - // The exact rate on the Macintosh is actually 16 clocks @ 7.8336 MHz = 2.04 microseconds. - // MFM: One bit every 1 microsecond - reg [7:0] shifter; - reg [5:0] bitTimer; - reg [3:0] bitCounter; - reg [6:0] wrData; - reg rdHead; - reg [1:0] wrHistory; - reg mfmWriteSynced; - reg wrClear; - - always @(posedge clk) begin - wrHistory <= { wrHistory[0], wr }; - end - - always @(posedge clk or negedge _rst) begin - if (_rst == 0) begin - rdAckWrTick <= 0; - _driveRegWriteProtect <= 1; - _driveRegDiskInserted <= 1; - _driveRegMFMMode <= 1; - wrData <= `FIRMWARE_VERSION_NUMBER; - mfmWriteSynced <= 0; - wrClear <= 0; - end - else begin - // one-way switch for disk inserted register - until next reset, stepAck_diskInserted will act only as stepAck - if (_driveRegDiskInserted == 1 && stepAck_diskInserted == 0) begin - _driveRegDiskInserted <= 0; - end - // is the Macintosh currently writing to the disk? - if (_wreq == 0) begin - // was there a transition on the wr line? - // GCR: any transition - // MFM: falling edge - if (((wrHistory[1] != wrHistory[0]) && (_driveRegMFMMode == 1)) || - ((wrHistory[1] && ~wrHistory[0]) && (_driveRegMFMMode == 0))) begin - // has at least half a bit cell time elpased since the last cell boundary? - if ((bitTimer >= 20 && _driveRegMFMMode == 1) || - (bitTimer >= 10 && _driveRegMFMMode == 0)) begin - shifter <= { shifter[6:0], 1'b1 }; - bitCounter <= bitCounter - 1'b1; - end - // do nothing if the clock count was less than half a cell - - // reset the bit timer - bitTimer <= 0; - end - else begin - // have one and a half bit cell times elapsed? - if ((bitTimer >= 60 && _driveRegMFMMode == 1) || - (bitTimer >= 30 && _driveRegMFMMode == 0)) begin - shifter <= { shifter[6:0], 1'b0 }; - bitCounter <= bitCounter - 1'b1; - - if (_driveRegMFMMode == 1) - bitTimer <= 20; - else - bitTimer <= 10; - end - else begin - // init shifter at the beginning of a write, so we can recognize the framing bits later - if (wrClear == 0) begin - shifter <= 0; - wrClear <= 1; - end - // has a complete byte been shifted in? - else if (_driveRegMFMMode == 1) begin - // GCR - if (shifter[7] == 1) begin - // GCR: The complete byte is shifter[7:0], but only 7 bits are stored in wrData, since the MSB is always 1. - wrData <= shifter[6:0]; // store the byte for the mcu - shifter <= 0; // clear the byte from the shifter - rdAckWrTick <= ~rdAckWrTick; // signal the mcu that a new byte is ready - end - end - else begin - // MFM - // If we're in write mode, but haven't yet synched (framed the bytes in the bit stream), - // and we see 01000100 in the shifter, assume that it's the first half of an A1 sync - if ((bitCounter == 0) || - (shifter == 8'h44 && mfmWriteSynced == 0)) begin - // MFM: send the mcu the data nibble in the low 4 bits, and clock bit C2 in bit 4 - wrData[0] <= shifter[0]; - wrData[1] <= shifter[2]; - wrData[2] <= shifter[4]; - wrData[3] <= shifter[6]; - wrData[4] <= shifter[5]; // clock bit - bitCounter <= 8; - - rdAckWrTick <= (shifter == 8'h44 && mfmWriteSynced == 0) ? 0 : ~rdAckWrTick; // signal the mcu that a new nibble is ready - mfmWriteSynced <= mfmWriteSynced | (shifter == 8'h44); - end - end - - bitTimer <= bitTimer + 1'b1; - end - end - end - else begin - mfmWriteSynced <= 0; - wrClear <= 0; - // is it time for a new bit? - if ((bitTimer == 40 && _driveRegMFMMode == 1) || - (bitTimer == 20 && _driveRegMFMMode == 0)) - begin - // are all the bits done? - if (bitCounter == 0) begin - // is there a new byte ready to read? - if (byteReady_tk0 == 1) begin - // if there's a byte ready, but no disk inserted, then load config options from the MCU - if (_driveRegDiskInserted == 1) begin - _driveRegWriteProtect <= data[0]; - _driveRegMFMMode <= data[1]; - end - else begin - // load the new byte. - if (_driveRegMFMMode == 1) begin - // Only 7 bits are transferred, since the MSB is always 1. - shifter <= { 1'b1, data }; - end - else begin - // For MFM, the 7 bits received from the MCU are: - // 0 0 m d3 d2 d1 d0 - // From this we can constuct the MFM-encoded byte with clock and data bits: - // c3 d3 c2 d2 c1 d1 c0 d0 - // where cN = dN+1 NOR dN. - // If m is 1, then this is part of a mark byte, and c2 should be forced to 0. - shifter[7] <= ~(shifter[7] | data[3]); - shifter[6] <= data[3]; - shifter[5] <= ~(data[3] | data[2]) & ~data[4]; - shifter[4] <= data[2]; - shifter[3] <= ~(data[2] | data[1]); - shifter[2] <= data[1]; - shifter[1] <= ~(data[1] | data[0]); - shifter[0] <= data[0]; - end - bitCounter <= 7; - rdAckWrTick <= 1; - end - end - else begin - // insert a sync byte - if (_driveRegMFMMode == 1) - begin - shifter <= { 8'b11111111 }; - bitCounter <= 9; // sync "byte" sends 10 bits rather than 8 - end - else begin - shifter <= { 8'b10101010 }; // logical 0x0, encoded 0xA. Should sync byte be 0x4E instead? - bitCounter <= 7; - end - end - end - else begin - if (bitCounter == 7) begin - // Clear rdAck after the first bit is done. This gives the microcontroller 2 microseconds - // to react to rdAck before it's deasserted. - rdAckWrTick <= 0; - end - - // there are still more bits remaining, so shift the next bit - shifter <= { shifter[6:0], 1'b0 }; // left shift - bitCounter <= bitCounter - 1'b1; - end - end - /* GCR: After the bit shift is completed, update the read head state, using the MSB of the shift register. - A logical 1 is sent as a falling (high to low) transition on the read head at a bit cell boundary time, - a logical 0 is sent as no falling transition. */ - else if (bitTimer == 2 && shifter[7] == 1 && _driveRegMFMMode == 1) begin - rdHead <= 1'b0; - end - /* GCR: Half-way through the bit cell time, set the read head to 1 - to prepare for a possible falling transition for the next bit. */ - else if (bitTimer == 20 && _driveRegMFMMode == 1) - begin - rdHead <= 1'b1; - end - /* MFM: At the start of the bit cell time, set the read head to 0 if the logical value is 1. */ - else if (bitTimer == 2 && shifter[7] == 1 && _driveRegMFMMode == 0) - begin - rdHead <= 1'b0; - end - /* MFM: About a quarter-way through the bit cell time, always reset read head to 1. */ - else if (bitTimer == 7 && _driveRegMFMMode == 0) - begin - rdHead <= 1'b1; - end - - // increment bit timer modulo 40 (20 MFM) - if ((bitTimer == 40 && _driveRegMFMMode == 1) || - (bitTimer == 20 && _driveRegMFMMode == 0)) - bitTimer <= 0; - else - bitTimer <= bitTimer + 1'b1; - end - end - end - - // enable the data output only if the MCU says its data lines are Hi Z - assign data = (outputEnable == 1) ? wrData : 7'hZZ; - - /********** register read **********/ - wire [3:0] driveReadRegisterSelect = {ca2,ca1,ca0,SEL}; - - reg registerContents; - always @* begin - case (driveReadRegisterSelect) - `DRIVE_REG_DIRTN: - registerContents = driveRegStepDirection; // step direction - `DRIVE_REG_CSTIN: - registerContents = _driveRegDiskInserted; // disk in drive, 0 = yes - `DRIVE_REG_STEP: - registerContents = ~stepRequest; // STEP, 1 = complete - `DRIVE_REG_WRTPRT: - registerContents = _driveRegWriteProtect; // write protect, 0 = on, 1 = off - `DRIVE_REG_MOTORON: - registerContents = _driveRegMotorOn; // 0 = motor on - `DRIVE_REG_TK0: - registerContents = _driveRegTK0; // TK0: track 0 indicator - `DRIVE_REG_EJECT: - registerContents = 1'b0; // disk switched? - `DRIVE_REG_TACH: - registerContents = driveTach; // TACH: 60 pulses for each rotation of the drive motor - `DRIVE_REG_RDDATA0: - registerContents = rdHead; // RDDATA0 - `DRIVE_REG_RDDATA1: - registerContents = rdHead; // RDDATA1 - `DRIVE_REG_SUPERDR: - registerContents = 1'b1; // SUPERDR, 1 = yes - `DRIVE_REG_UNUSED: - registerContents = 1'b0; // UNUSED - `DRIVE_REG_SIDES: - registerContents = 1'b1; // SIDES = double-sided drive - `DRIVE_REG_READY: - registerContents = 1'b0; // READY = yes - `DRIVE_REG_INSTALLED: - registerContents = 1'b0; // INSTALLED = yes - `DRIVE_REG_HSHK_HD: - registerContents = _driveRegMFMMode; // HSHK_HD = implements ready handshake, or DD/HD media - - endcase - end - assign rd = _enable == 1'b1 ? 1'bZ : registerContents; - - always @(posedge clk or negedge _rst) begin - if (_rst == 0) begin - driveCurrentSide = 0; - end - else if (_enable == 1'b0 && lstrb == 1'b0) begin - if (driveReadRegisterSelect == `DRIVE_REG_RDDATA0) - driveCurrentSide = 0; - else if (driveReadRegisterSelect == `DRIVE_REG_RDDATA1) - driveCurrentSide = 1; - end - end - - // compute the effective _wreq state for the microcontroller - assign _wreqMCU = ~(_wreq == 0 && _enable == 0 && _driveRegMotorOn == 0); - - // cheesy: during a step request, stepDirectionMotorOn is the step direction. Otherwise it's motorOn. - assign stepDirectionMotorOn = stepRequest ? driveRegStepDirection : _driveRegMotorOn; - - /********** register write **********/ - wire [2:0] driveWriteRegisterSelect = {ca1,ca0,SEL}; - - reg [4:0] lstrbHistory; - always @(posedge clk) begin - lstrbHistory <= { lstrbHistory[3:0], lstrb }; - end - - always @(posedge clk or negedge _rst) begin - if (_rst == 1'b0) begin - _driveRegTK0 <= 0; - _driveRegMotorOn <= 1; - driveRegStepDirection <= 0; - stepRequest <= 0; - ejectRequest <= 0; - end - // was there a rising edge on lstrb? - else if (_enable == 1'b0 && lstrbHistory == 5'b01111) begin - case (driveWriteRegisterSelect) - `DRIVE_REG_DIRTN: - driveRegStepDirection <= ca2; - //`DRIVE_REG_SWITCHED: // unused - `DRIVE_REG_STEP: - begin - stepRequest <= 1; // tell the microcontroller that a step was performed - end - `DRIVE_REG_MOTORON: - _driveRegMotorOn <= ca2; - `DRIVE_REG_EJECT: - if (ca2 == 1'b1) begin - ejectRequest <= 1; // tell the microcontroller that the disk was ejected. This stays on forever (until next reset) - end - endcase - end - else begin - // clear step request after mcu acknowledges it, and get the new track 0 state - if (stepRequest == 1 && stepAck_diskInserted == 1'b1) begin - stepRequest <= 0; - _driveRegTK0 <= byteReady_tk0; - end - end - end - - /********** Revision 1.0 board: status LEDs and fake SD writeProtect **********/ - assign led = _driveRegMotorOn; - assign zero = 0; - - -endmodule \ No newline at end of file diff --git a/arduino/CPLD-Xilinx/floppyemu.xise b/arduino/CPLD-Xilinx/floppyemu.xise deleted file mode 100755 index 0f0e6af..0000000 --- a/arduino/CPLD-Xilinx/floppyemu.xise +++ /dev/null @@ -1,210 +0,0 @@ - - - -
- - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/arduino/CPLD-Xilinx/testbench.v b/arduino/CPLD-Xilinx/testbench.v deleted file mode 100755 index 55613ed..0000000 --- a/arduino/CPLD-Xilinx/testbench.v +++ /dev/null @@ -1,163 +0,0 @@ -`timescale 1ns / 1ps - -//////////////////////////////////////////////////////////////////////////////// -// Company: -// Engineer: -// -// Create Date: 15:13:07 11/30/2011 -// Design Name: floppyemu -// Module Name: C:/Users/steve/Documents/floppyemu/CPLD-Xilinx/testbench.v -// Project Name: floppyemu -// Target Device: -// Tool versions: -// Description: -// -// Verilog Test Fixture created by ISE for module: floppyemu -// -// Dependencies: -// -// Revision: -// Revision 0.01 - File Created -// Additional Comments: -// -//////////////////////////////////////////////////////////////////////////////// - -module testbench; - - // Inputs - reg clk; - reg wr; - - // Outputs - wire [7:0] wrData; - wire rdAckWrByte; - - // Instantiate the Unit Under Test (UUT) - floppyemu uut ( - .clk(clk), - .wr(wr), - .wrData(wrData), - .rdAckWrByte(rdAckWrByte) - ); - - initial begin - clk = 0; - end - - always begin - #70 clk = 1; - #70 clk = 0; - end - - initial begin - // Initialize Inputs - wr = 0; - - // Wait 100 ns for global reset to finish - #4000; - - // send 10-bit sync byte - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 ; - #2000 ; - - // send 10-bit sync byte - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 ; - #2000 ; - - // send 10-bit sync byte - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 ; - #2000 ; - - // send 10-bit sync byte - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 ; - #2000 ; - - // send 10-bit sync byte - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 ; - #2000 ; - - // D5 = 1101 0101 - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 ; - #2000 wr = ~wr; - #2000 ; - #2000 wr = ~wr; - #2000 ; - #2000 wr = ~wr; - - // AA = 1010 1010 - #2000 wr = ~wr; - #2000 ; - #2000 wr = ~wr; - #2000 ; - #2000 wr = ~wr; - #2000 ; - #2000 wr = ~wr; - #2000 ; - - // 96 = 1001 0110 - #2000 wr = ~wr; - #2000 ; - #2000 ; - #2000 wr = ~wr; - #2000 ; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 ; - - // 96 = 1001 0110 - #2000 wr = ~wr; - #2000 ; - #2000 ; - #2000 wr = ~wr; - #2000 ; - #2000 wr = ~wr; - #2000 wr = ~wr; - #2000 ; - - $stop; - end - -endmodule - diff --git a/arduino/eagle/floppyemu 1.1.1/board-layout.png b/arduino/eagle/floppyemu 1.1.1/board-layout.png deleted file mode 100755 index b0e7ed3..0000000 Binary files a/arduino/eagle/floppyemu 1.1.1/board-layout.png and /dev/null differ diff --git a/arduino/eagle/floppyemu 1.1.1/board-schematic.png b/arduino/eagle/floppyemu 1.1.1/board-schematic.png deleted file mode 100755 index a4f1df8..0000000 Binary files a/arduino/eagle/floppyemu 1.1.1/board-schematic.png and /dev/null differ diff --git a/arduino/eagle/floppyemu 1.1.1/floppyemu.brd b/arduino/eagle/floppyemu 1.1.1/floppyemu.brd deleted file mode 100755 index bfd9c7e..0000000 --- a/arduino/eagle/floppyemu 1.1.1/floppyemu.brd +++ /dev/null @@ -1,4669 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -PREV -SELECT -NEXT -RESET -STATUS -ISP -LCD1 -LCD2 -CPLD -AVR -244 -X1 -R4 -R1 -R3 -C12 -C13 -C11 -1117 -MACINTOSH FLOPPY EMU -VERSION 1.2 -WWW.BIGMESSOWIRES.COM -3V3 -LED -CE -RST -D/C -MOSI -SCLK - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -POWER -R5 -C10 -C8 -IC1 -IC2 -IC3 -IC4 -J1 -J2 -J3 -C2 -C1 -C3 -C9 -C4 -C6 -C5 -C7 -U1 -SD Card -DESIGNED AND PRODUCED BY -LIGHT - - - - - - - - - - - -Extra-long pads for easier hand soldering - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -Extra-long pads for easier hand soldering - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>SUB-D</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -1 -10 -11 -19 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - -Omron B3FS SMD tactile switch - - - - - - - - - -> Name - - -<b>Shrink Small Outline Package</b><p> -package type SS - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - -<b>CONNECTOR</b><p> -series 057 contact pc board low profile headers<p> -straight - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>CHIPLED</b><p> -Source: http://www.osram.convergy.de/ ... LG_R971.pdf - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - -<b>Smal Outline Transistor</b> - - - - - - - - ->NAME ->VALUE - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find connectors and sockets- basically anything that can be plugged into or onto.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> CC v3.0 Share-Alike You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find anything that moves- switches, relays, buttons, potentiometers. Also, anything that goes on a board but isn't electrical in nature- screws, standoffs, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> CC v3.0 Share-Alike You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - -<b>Stand Off</b><p> -This is the mechanical footprint for a #4 phillips button head screw. Use the keepout ring to avoid running the screw head into surrounding components. SKU : PRT-00447 - - - - - - - - - - -<b>Test Pins/Pads</b><p> -Cream on SMD OFF.<br> -new: Attribute TP_SIGNAL_NAME<br> -<author>Created by librarian@cadsoft.de</author> - - -<b>TEST PAD</b> - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> CC v3.0 Share-Alike You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - - ->NAME ->VALUE - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> CC v3.0 Share-Alike You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - -1/6W Thru-hole Resistor - *UNPROVEN* - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - -<b>EAGLE Design Rules</b> -<p> -Die Standard-Design-Rules sind so gewählt, dass sie für -die meisten Anwendungen passen. Sollte ihre Platine -besondere Anforderungen haben, treffen Sie die erforderlichen -Einstellungen hier und speichern die Design Rules unter -einem neuen Namen ab. -<b>Smart Prototyping Design Rules</b> -<p> -http://smart-prototyping.com/index.php?route=product/product&product_id=142 -<b>NOA-Labs EAGLE Design Rules</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/arduino/eagle/floppyemu 1.1.1/floppyemu.sch b/arduino/eagle/floppyemu 1.1.1/floppyemu.sch deleted file mode 100755 index 68478da..0000000 --- a/arduino/eagle/floppyemu 1.1.1/floppyemu.sch +++ /dev/null @@ -1,7254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Extra-long pads for easier hand soldering - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -Extra-long pads for easier hand soldering - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>SUB-D</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -1 -10 -11 -19 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - -Omron B3FS SMD tactile switch - - - - - - - - - -> Name - - -<b>Shrink Small Outline Package</b><p> -package type SS - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - -<b>CONNECTOR</b><p> -series 057 contact pc board low profile headers<p> -straight - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - ->VALUE ->NAME - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - ->NAME -VCC_INT -GND -VCC_IO - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -MOSI -RESET -SCK -MISO -VCC -GND - - - - - - - - - - - - - - - ->NAME - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - ->NAME -GND -VCC - - - - - - - - - - - - - - - - - - - - - - -SD & MMC - - - - -<b>8-bit Microcontroller</b> with 128K Bytes In-System Programmable Flash<p> -Source: http://www.atmel.com/dyn/resources/prod_documents/doc2593.pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>SUB-D</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>AVR ISP 6 Pin - Locking Pins</b> -This is the reduced ISP connector for AVR programming. Common on Arduino. This footprint will take up less PCB space and can be used with a 10-pin to 6-pin adapter such as SKU: BOB-08508 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -Omron B3FS-10XX SMD tactile switch - - - - - - - - - - - - - - - - - - -<b>MEMORY</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>SD MMC Card holder</b> -<p> -4UCON part #06132 - easy to solder - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -JST crimp connector: 1mm pitch, top entry - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - ->Name ->Value - - - - - - - - - ->Name ->Value - - - - - - ->NAME ->VALUE - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - ->NAME ->VALUE - - - - - -<b>CAPACITOR</b><p> -chip - - - - - - - - - ->NAME ->VALUE - - - - - - - - ->Name ->Value - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - - -CTZ3 Series land pattern for variable capacitor - CTZ3E-50C-W1-PF - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->Name ->Value - - -<b>RESISTOR</b><p> -chip - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>CAPACITOR</b><p> -chip - - - - - - - - ->NAME ->VALUE - - - - - - -1/6W Thru-hole Resistor - *UNPROVEN* - - - - - - ->NAME ->VALUE - - - - - - ->NAME ->VALUE - - - - -1/4W Resistor, 0.4" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -1/2W Resistor, 0.5" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -1W Resistor, 0.6" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -2W Resistor, 0.8" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>Header 8</b> -Standard 8-pin 0.1" header. Use with straight break away headers (SKU : PRT-00116), right angle break away headers (PRT-00553), swiss pins (PRT-00743), machine pins (PRT-00117), and female headers (PRT-00115). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Capacitor</b> -Standard 0603 ceramic capacitor, and 0.1" leaded capacitor. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Resistor</b> -Basic schematic elements and footprints for 0603, 1206, and PTH resistors. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - - - -Low cost SMT crystals, no capacitors included -<p>http://www.ladyada.net/library/eagle</p> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE - - - - - ->VALUE - - - - - ->VALUE - - - - - -<b>SUPPLY SYMBOL</b> - - - - - - - - - - - - -<b>SUPPLY SYMBOL</b> - - - - - - - - - - - - -<b>SUPPLY SYMBOL</b> - - - - - - - - - - - - - - - - -<b>CHICAGO MINIATURE LAMP, INC.</b><p> -7022X Series SMT LEDs 1206 Package Size - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - -<B>LED</B><p> -5 mm, square, Siemens - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - -<B>LED</B><p> -2 x 5 mm, rectangle - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - -<B>LED</B><p> -3 mm, round - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<B>LED</B><p> -5 mm, round - - - - - - - - - - - ->NAME ->VALUE - - -<B>LED</B><p> -1 mm, round, Siemens - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - -<B>LED BLOCK</B><p> -1 LED, Siemens - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - -<b>LED HOLDER</b><p> -Siemens - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<b>LED HOLDER</b><p> -Siemens - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<b>LED HOLDER</b><p> -Siemens - - - - - - - - - - - - - - - - - -A+ -K- ->NAME ->VALUE - - - - - -<b>LED HOLDER</b><p> -Siemens - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -+ -- - - -<B>IR LED</B><p> -infrared emitting diode, Infineon -TO-18, lead spacing 2.54 mm, cathode marking<p> -Inifineon - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<B>IR LED</B><p> -infrared emitting diode, Infineon -TO-18, lead spacing 2.54 mm, cathode marking<p> -Inifineon - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<B>LED</B><p> -rectangle, 5.7 x 3.2 mm - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<B>IR LED</B><p> -IR transmitter Siemens - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -<b>TOPLED® High-optical Power LED (HOP)</b><p> -Source: http://www.osram.convergy.de/ ... ls_t675.pdf - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -A -C - - - - - - - -<b>BLUE LINETM Hyper Mini TOPLED® Hyper-Bright LED</b><p> -Source: http://www.osram.convergy.de/ ... LB M676.pdf - - - - - - - - - - - - - - -A -C ->NAME ->VALUE - - - - - - - -<b>Super SIDELED® High-Current LED</b><p> -LG A672, LP A672 <br> -Source: http://www.osram.convergy.de/ ... LG_LP_A672.pdf (2004.05.13) - - - - - - - - - - - - - - - - - - - -C -A ->NAME ->VALUE - - - - - - - -<b>SmartLEDTM Hyper-Bright LED</b><p> -Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY L896.pdf - - - - - - - - ->NAME ->VALUE - - - - - -<b>Hyper TOPLED® RG Hyper-Bright LED</b><p> -Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY T776.pdf - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -A -C - - - - - - - - - - -<b>Hyper Micro SIDELED®</b><p> -Source: http://www.osram.convergy.de/ ... LA_LO_LS_LY Y876.pdf - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - -<b>Power TOPLED®</b><p> -Source: http://www.osram.convergy.de/ ... LA_LO_LA_LY E67B.pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE -C -A -C -C - - - - - - - - - - - -<b>Hyper CHIPLED Hyper-Bright LED</b><p> -LB Q993<br> -Source: http://www.osram.convergy.de/ ... Lb_q993.pdf - - - - ->NAME ->VALUE - - - - - - - -<b>Hyper CHIPLED Hyper-Bright LED</b><p> -LB R99A<br> -Source: http://www.osram.convergy.de/ ... lb_r99a.pdf - - - - ->NAME ->VALUE - - - - - - - -<b>Mini TOPLED Santana®</b><p> -Source: http://www.osram.convergy.de/ ... LG M470.pdf - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - -<b>CHIPLED</b><p> -Source: http://www.osram.convergy.de/ ... LG_R971.pdf - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - -<b>CHIPLED</b><p> -Source: http://www.osram.convergy.de/ ... LG_LY N971.pdf - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - -<b>CHIPLED</b><p> -Source: http://www.osram.convergy.de/ ... LG_LY Q971.pdf - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - -<b>CHIPLED-0603</b><p> -Recommended Solder Pad useable for SmartLEDTM and Chipled - Package 0603<br> -Package able to withstand TTW-soldering heat<br> -Package suitable for TTW-soldering<br> -Source: http://www.osram.convergy.de/ ... LO_LS_LY L89K.pdf - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - -<b>SmartLED TTW</b><p> -Recommended Solder Pad useable for SmartLEDTM and Chipled - Package 0603<br> -Package able to withstand TTW-soldering heat<br> -Package suitable for TTW-soldering<br> -Source: http://www.osram.convergy.de/ ... LO_LS_LY L89K.pdf - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - -<b>Lumileds Lighting. LUXEON®</b> with cool pad<p> -Source: K2.pdf - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Lumileds Lighting. LUXEON®</b> without cool pad<p> -Source: K2.pdf - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - -<B>LED</B><p> -10 mm, round - - - - - - - - - - - - - ->NAME ->VALUE - - -<b>SURFACE MOUNT LED LAMP</b> 3.5x2.8mm<p> -Source: http://www.kingbright.com/manager/upload/pdf/KA-3528ASYC(Ver1189474662.1) - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - -<b>LED</b><p> -<u>OSRAM</u>:<br> - -- <u>CHIPLED</u><br> -LG R971, LG N971, LY N971, LG Q971, LY Q971, LO R971, LY R971 -LH N974, LH R974<br> -LS Q976, LO Q976, LY Q976<br> -LO Q996<br> - -- <u>Hyper CHIPLED</u><br> -LW Q18S<br> -LB Q993, LB Q99A, LB R99A<br> - -- <u>SideLED</u><br> -LS A670, LO A670, LY A670, LG A670, LP A670<br> -LB A673, LV A673, LT A673, LW A673<br> -LH A674<br> -LY A675<br> -LS A676, LA A676, LO A676, LY A676, LW A676<br> -LS A679, LY A679, LG A679<br> - -- <u>Hyper Micro SIDELED®</u><br> -LS Y876, LA Y876, LO Y876, LY Y876<br> -LT Y87S<br> - -- <u>SmartLED</u><br> -LW L88C, LW L88S<br> -LB L89C, LB L89S, LG L890<br> -LS L89K, LO L89K, LY L89K<br> -LS L896, LA L896, LO L896, LY L896<br> - -- <u>TOPLED</u><br> -LS T670, LO T670, LY T670, LG T670, LP T670<br> -LSG T670, LSP T670, LSY T670, LOP T670, LYG T670<br> -LG T671, LOG T671, LSG T671<br> -LB T673, LV T673, LT T673, LW T673<br> -LH T674<br> -LS T676, LA T676, LO T676, LY T676, LB T676, LH T676, LSB T676, LW T676<br> -LB T67C, LV T67C, LT T67C, LS T67K, LO T67K, LY T67K, LW E67C<br> -LS E67B, LA E67B, LO E67B, LY E67B, LB E67C, LV E67C, LT E67C<br> -LW T67C<br> -LS T679, LY T679, LG T679<br> -LS T770, LO T770, LY T770, LG T770, LP T770<br> -LB T773, LV T773, LT T773, LW T773<br> -LH T774<br> -LS E675, LA E675, LY E675, LS T675<br> -LS T776, LA T776, LO T776, LY T776, LB T776<br> -LHGB T686<br> -LT T68C, LB T68C<br> - -- <u>Hyper Mini TOPLED®</u><br> -LB M676<br> - -- <u>Mini TOPLED Santana®</u><br> -LG M470<br> -LS M47K, LO M47K, LY M47K -<p> -Source: http://www.osram.convergy.de<p> - -<u>LUXEON:</u><br> -- <u>LUMILED®</u><br> -LXK2-PW12-R00, LXK2-PW12-S00, LXK2-PW14-U00, LXK2-PW14-V00<br> -LXK2-PM12-R00, LXK2-PM12-S00, LXK2-PM14-U00<br> -LXK2-PE12-Q00, LXK2-PE12-R00, LXK2-PE12-S00, LXK2-PE14-T00, LXK2-PE14-U00<br> -LXK2-PB12-K00, LXK2-PB12-L00, LXK2-PB12-M00, LXK2-PB14-N00, LXK2-PB14-P00, LXK2-PB14-Q00<br> -LXK2-PR12-L00, LXK2-PR12-M00, LXK2-PR14-Q00, LXK2-PR14-R00<br> -LXK2-PD12-Q00, LXK2-PD12-R00, LXK2-PD12-S00<br> -LXK2-PH12-R00, LXK2-PH12-S00<br> -LXK2-PL12-P00, LXK2-PL12-Q00, LXK2-PL12-R00 -<p> -Source: www.luxeon.com<p> - -<u>KINGBRIGHT:</U><p> -KA-3528ASYC<br> -Source: www.kingbright.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<b>Smal Outline Transistor</b> - - - - - - - - ->NAME ->VALUE - - - - - - -<b>DPAC</b> - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - ->NAME ->VALUE - - - - - - - -<b>800mA and 1A Low Dropout (LDO) Positive Regulator</b><p> -1.8V, 2.5V, 2.85V, 3.3V, 5V, and Adj - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find connectors and sockets- basically anything that can be plugged into or onto.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> CC v3.0 Share-Alike You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - -2mm SMD side-entry connector. tDocu layer indicates the actual physical plastic housing. +/- indicate SparkFun standard batteries and wiring. - - - - - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - -This footprint was designed to help hold the alignment of a through-hole component (i.e. 6-pin header) while soldering it into place. -You may notice that each hole has been shifted either up or down by 0.005 of an inch from it's more standard position (which is a perfectly straight line). -This slight alteration caused the pins (the squares in the middle) to touch the edges of the holes. Because they are alternating, it causes a "brace" -to hold the component in place. 0.005 has proven to be the perfect amount of "off-center" position when using our standard breakaway headers. -Although looks a little odd when you look at the bare footprint, once you have a header in there, the alteration is very hard to notice. Also, -if you push a header all the way into place, it is covered up entirely on the bottom side. This idea of altering the position of holes to aid alignment -will be further integrated into the Sparkfun Library for other footprints. It can help hold any component with 3 or more connection pins. - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - ->Name ->Value -+ -- - - -<H3>JST-2-PTH-KIT</h3> -2-Pin JST, through-hole connector<br> -<br> -<b>Warning:</b> This is the KIT version of this package. This package has a smaller diameter top stop mask, which doesn't cover the diameter of the pad. This means only the bottom side of the pads' copper will be exposed. You'll only be able to solder to the bottom side. - - - - - - - - - ->Name ->Value -+ -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ->VALUE ->NAME - - - - - - -Standard 2-pin 0.1" header. Use with <br> -- straight break away headers ( PRT-00116)<br> -- right angle break away headers (PRT-00553)<br> -- swiss pins (PRT-00743)<br> -- machine pins (PRT-00117)<br> -- female headers (PRT-00115)<br><br> - - Molex polarized connector foot print use with: PRT-08233 with associated crimp pins and housings.<br><br> - -2.54_SCREWTERM for use with PRT-10571.<br><br> - -3.5mm Screw Terminal footprints for PRT-08084<br><br> - -5mm Screw Terminal footprints for use with PRT-08433 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find anything that moves- switches, relays, buttons, potentiometers. Also, anything that goes on a board but isn't electrical in nature- screws, standoffs, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> CC v3.0 Share-Alike You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - -<b>Stand Off</b><p> -This is the mechanical footprint for a #4 phillips button head screw. Use the keepout ring to avoid running the screw head into surrounding components. SKU : PRT-00447 - - - - - - - - -<b>Stand Off</b><p> -This is the mechanical footprint for a #4 phillips button head screw. Use the keepout ring to avoid running the screw head into surrounding components. SKU : PRT-00447 - - - - - - - - - - - - - - - -<b>#4 Stand Off</b><p> -This is the mechanical footprint for a #4 phillips button head screw. Use the keepout ring to avoid running the screw head into surrounding components. SKU : PRT-00447 - - - - - - - - - - - - - - - - - - - -<b>Test Pins/Pads</b><p> -Cream on SMD OFF.<br> -new: Attribute TP_SIGNAL_NAME<br> -<author>Created by librarian@cadsoft.de</author> - - -<b>TEST PAD</b> - - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - - - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - - -<b>TEST PAD</b> - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - - -<b>TEST PAD</b> - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - - -<b>TEST PAD</b> - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - - -<b>TEST PAD</b> - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - - -<b>TEST PAD</b> - - ->NAME ->VALUE ->TP_SIGNAL_NAME - - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - -<b>TEST PAD</b> - ->NAME ->VALUE ->TP_SIGNAL_NAME - - - - - - - - - - - - - - - - - - - - - - - ->NAME ->TP_SIGNAL_NAME - - - - - - -<b>TEST PIN</b> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> CC v3.0 Share-Alike You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - - - ->NAME ->VALUE - - - - - - - - -47uF Tantalum SMT<br> -CAP-08310- 10V 10% (EIA-3528) - - - - - - - - - - - - - - - - - - - - - -<h3>SparkFun Electronics' preferred foot prints</h3> -In this library you'll find resistors, capacitors, inductors, test points, jumper pads, etc.<br><br> -We've spent an enormous amount of time creating and checking these footprints and parts, but it is the end user's responsibility to ensure correctness and suitablity for a given componet or application. If you enjoy using this library, please buy one of our products at www.sparkfun.com. -<br><br> -<b>Licensing:</b> CC v3.0 Share-Alike You are welcome to use this library for commercial purposes. For attribution, we ask that when you begin to sell your device using our footprint, you email us with a link to the product being sold. We want bragging rights that we helped (in a very small part) to create your 8th world wonder. We would like the opportunity to feature your device on our homepage. - - -1/6W Thru-hole Resistor - *UNPROVEN* - - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - - - - - - ->Name ->Value - - -<b>RESISTOR</b><p> -chip - - - - - - - - - - ->NAME ->VALUE - - - - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - - - - - - - ->NAME ->VALUE - - - - -1/4W Resistor, 0.4" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -1/2W Resistor, 0.5" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -1W Resistor, 0.6" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -2W Resistor, 0.8" wide<p> - -Yageo CFR series <a href="http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf">http://www.yageo.com/pdf/yageo/Leaded-R_CFR_2008.pdf</a> - - - - - - ->Name ->Value - - -<h3>AXIAL-0.3-KIT</h3> - -Commonly used for 1/4W through-hole resistors. 0.3" pitch between holes.<br> -<br> - -<b>Warning:</b> This is the KIT version of the AXIAL-0.3 package. This package has a smaller diameter top stop mask, which doesn't cover the diameter of the pad. This means only the bottom side of the pads' copper will be exposed. You'll only be able to solder to the bottom side. - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - - - - - - - - - - -This is the "EZ" version of the standard .3" spaced resistor package.<br> -It has a reduced top mask to make it harder to install upside-down. - - - - - - - - - - ->Name ->Value - - - - - - - - - - - - - - - - - ->NAME ->VALUE - - - - - - -<b>Resistor</b> -Basic schematic elements and footprints for 0603, 1206, and PTH resistors. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/arduino/eagle/floppyemu 1.1.1/gerbers.zip b/arduino/eagle/floppyemu 1.1.1/gerbers.zip deleted file mode 100755 index 840a7aa..0000000 Binary files a/arduino/eagle/floppyemu 1.1.1/gerbers.zip and /dev/null differ diff --git a/arduino/eagle/floppyemu 1.1.1/parts-1.1.txt b/arduino/eagle/floppyemu 1.1.1/parts-1.1.txt deleted file mode 100755 index 37381e5..0000000 --- a/arduino/eagle/floppyemu 1.1.1/parts-1.1.txt +++ /dev/null @@ -1,33 +0,0 @@ -ICs: -XC9572XL, 44-pin TQFP package = http://search.digikey.com/us/en/products/XC9572XL-10VQG44C/122-1448-ND/966629?wt.z_cid=ref_octopart_dkc_buynow -ATMega1284P, 44-pin TQFP package = http://search.digikey.com/us/en/products/ATMEGA1284P-AU/ATMEGA1284P-AU-ND/1914519 -74LVC244A level converter, 20-pin SSOP package = http://search.digikey.com/us/en/products/74LVC244ADB,112/568-1582-5-ND/763186 -800mA 1117 3.3V regulator, SOT223 package = http://search.digikey.com/us/en/products/LD1117S33TR/497-1242-1-ND/586242 -20 MHz 8pF SMD crystal, NX5032 package = http://search.digikey.com/us/en/products/NX5032GA-20.000000MHZ-LN-CD-1/644-1039-1-ND/1128911 - -Connectors: -DB-19 connector, male solder type = http://www.iec-usa.com/cgi-bin/iec/fullpic?G2FS4qvh;DB19MS;41 -IDC20 connector = http://search.digikey.com/us/en/products/SBH11-PBPC-D10-ST-BK/S9172-ND/1990065 -AVR ISP connector (2x3 IDC) = http://search.digikey.com/us/en/products/75869-131LF/609-2845-ND/1302569 -8-pin male 0.1 inch header -2-pin male 0.1 inch header -8-pin female 0.1 inch header -2-pin female 0.1 inch header - -Passives: -10x 0.1uF capacitors, 0805 package -1x 33uF tantalum cap, 0805 package -2x 18pF caps, 0805 package -3x 220 ohm resistors, 0805 package -1x 10K ohm resistor, 0805 package - -Miscellaneous: -Nokia 5110 graphical LCD = https://www.sparkfun.com/products/10168 -2x LEDs, 0805 package = http://search.digikey.com/us/en/products/APT2012SGC/754-1131-1-ND/1747848 -4x B3FS tactile switch, SMD = http://search.digikey.com/scripts/dksearch/dksus.dll?pname&WT.z_cid=ref_octopart_dkc_buynow&site=us&lang=en&name=SW1141-ND -TE 2041021-4 SD card holder = http://search.digikey.com/us/en/products/2041021-4/A101492CT-ND/2571152 - -Tools: -AVRISP mkII AVR programmer (or equivalent) = http://www.digikey.com/product-detail/en/ATAVRISP2/ATAVRISP2-ND/898891?WT.mc_id=PLA_898891&gclid=CO_xwcjWnbQCFYp_QgodXX0AUQ -SD or SDHC card - diff --git a/arduino/firmware/firmware.xvf b/arduino/firmware/firmware.xvf deleted file mode 100755 index 443eb73..0000000 Binary files a/arduino/firmware/firmware.xvf and /dev/null differ diff --git a/arduino/firmware/readme.txt b/arduino/firmware/readme.txt deleted file mode 100755 index 8e480df..0000000 --- a/arduino/firmware/readme.txt +++ /dev/null @@ -1,24 +0,0 @@ -To update the Xilinx CPLD firmware: - -1. Copy firmware.xvf to the root directory of your SD card, and insert it into Floppy Emu. -2. Hold down the PREV and NEXT buttons. -3. Press and release the RESET button. -4. Follow the on-screen prompts. - - -To update the microcontroller application software: - -If you have the SD bootloader already installed: -1. Copy femu.bin to the root directory of your SD card, and insert it into Floppy Emu. -2. Hold down the PREV and SELECT buttons. -3. Press and release the RESET button. -4. Follow the on-screen prompts. - -If you don't have the SD bootloader installed: -1. Use your AVR ISP programmer to flash floppyemu.hex to the microcontroller. - -If you want to install the SD bootloader: -1. Use your AVR ISP programmer to flash merged.hex to the microcontroller. -2. Use the ISP programmer to set the BOOTRST fuse to 1 (on), and the BOOTSZ fuse to 2048W_F800. (Fuses should be Extended: 0xFF, High: 0xDA, Low: 0xBF) - - diff --git a/arduino/floppyemu/Release/Makefile b/arduino/floppyemu/Release/Makefile deleted file mode 100755 index c6ce998..0000000 --- a/arduino/floppyemu/Release/Makefile +++ /dev/null @@ -1,212 +0,0 @@ -################################################################################ -# Automatically-generated file. Do not edit! -################################################################################ - -SHELL := /bin/csh -RM := rm -rf - -USER_OBJS := - -LIBS := -PROJ := - -O_SRCS := -C_SRCS := -S_SRCS := -S_UPPER_SRCS := -OBJ_SRCS := -ASM_SRCS := -PREPROCESSING_SRCS := -OBJS := -OBJS_AS_ARGS := -C_DEPS := -C_DEPS_AS_ARGS := -EXECUTABLES := -OUTPUT_FILE_PATH := -OUTPUT_FILE_PATH_AS_ARGS := -AVR_APP_PATH :=$$$AVR_APP_PATH$$$ -QUOTE := " -ADDITIONAL_DEPENDENCIES:= -OUTPUT_FILE_DEP:= - -# Every subdirectory with source files must be described here -SUBDIRS := - - -# Add inputs and outputs from these tool invocations to the build variables -C_SRCS += \ -../cardtest.cpp \ -../diskmenu.cpp \ -../floppyemu.cpp \ -../millitimer.cpp \ -../noklcd.cpp \ -../SdFat/Sd2Card.cpp \ -../SdFat/SdBaseFile.cpp \ -../SdFat/SdFat.cpp \ -../SdFat/SdVolume.cpp \ -../xsvf/lenval.cpp \ -../xsvf/micro.cpp \ -../xsvf/ports.cpp - - -PREPROCESSING_SRCS += - - -ASM_SRCS += - - -OBJS += \ -cardtest.o \ -diskmenu.o \ -floppyemu.o \ -millitimer.o \ -noklcd.o \ -Sd2Card.o \ -SdBaseFile.o \ -SdFat.o \ -SdVolume.o \ -lenval.o \ -micro.o \ -ports.o - - -OBJS_AS_ARGS += \ -cardtest.o \ -diskmenu.o \ -floppyemu.o \ -millitimer.o \ -noklcd.o \ -Sd2Card.o \ -SdBaseFile.o \ -SdFat.o \ -SdVolume.o \ -lenval.o \ -micro.o \ -ports.o - - -C_DEPS += \ -cardtest.d \ -diskmenu.d \ -floppyemu.d \ -millitimer.d \ -noklcd.d \ -Sd2Card.d \ -SdBaseFile.d \ -SdFat.d \ -SdVolume.d \ -lenval.d \ -micro.d \ -ports.d - - -C_DEPS_AS_ARGS += \ -cardtest.d \ -diskmenu.d \ -floppyemu.d \ -millitimer.d \ -noklcd.d \ -Sd2Card.d \ -SdBaseFile.d \ -SdFat.d \ -SdVolume.d \ -lenval.d \ -micro.d \ -ports.d - - -OUTPUT_FILE_PATH +=floppyemu.elf - -OUTPUT_FILE_PATH_AS_ARGS +=floppyemu.elf - -ADDITIONAL_DEPENDENCIES:= - -OUTPUT_FILE_DEP:= ./makedep.mk - -# AVR32/GNU C Compiler - - - - - - - - - - - - - - - - - - - - - - - -./%.o: .././%.cpp - @echo Building file: $< - @echo Invoking: AVR8/GNU C++ Compiler - $(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<" - @echo Finished building: $< - -./%.o: ../SdFat/%.cpp - @echo Building file: $< - @echo Invoking: AVR8/GNU C++ Compiler - $(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<" - @echo Finished building: $< - -./%.o: ../xsvf/%.cpp - @echo Building file: $< - @echo Invoking: AVR8/GNU C++ Compiler - $(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -funsigned-char -funsigned-bitfields -DF_CPU=20000000 -I"../SdFat" -I"../xsvf" -O2 -ffunction-sections -fpack-struct -fshort-enums -Wall -c -MD -MP -MF "$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -mmcu=atmega1284p -o"$@" "$<" - @echo Finished building: $< - - - -# AVR32/GNU Preprocessing Assembler - - - -# AVR32/GNU Assembler - - - - -ifneq ($(MAKECMDGOALS),clean) -ifneq ($(strip $(C_DEPS)),) --include $(C_DEPS) -endif -endif - -# Add inputs and outputs from these tool invocations to the build variables - -# All Target -all: $(OUTPUT_FILE_PATH) $(ADDITIONAL_DEPENDENCIES) - -$(OUTPUT_FILE_PATH): $(OBJS) $(USER_OBJS) $(OUTPUT_FILE_DEP) - @echo Building target: $@ - @echo Invoking: AVR8/GNU C++ Linker - $(QUOTE)C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-g++.exe$(QUOTE) -o$(OUTPUT_FILE_PATH_AS_ARGS) $(OBJS_AS_ARGS) $(USER_OBJS) $(LIBS) -Wl,-Map="floppyemu.map" -Wl,-lm -Wl,--gc-sections -mrelax -Wl,-section-start=.bootldrinfo=0x1eff8 -mmcu=atmega1284p - @echo Finished building target: $@ - "C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -O ihex -R .eeprom -R .fuse -R .lock -R .signature "floppyemu.elf" "floppyemu.hex" - "C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -O binary -R .eeprom -R .fuse -R .lock -R .signature "floppyemu.elf" "femu.bin" - "C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objcopy.exe" -j .eeprom --set-section-flags=.eeprom=alloc,load --change-section-lma .eeprom=0 --no-change-warnings -O ihex "floppyemu.elf" "floppyemu.eep" || exit 0 - "C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-objdump.exe" -h -S "floppyemu.elf" > "floppyemu.lss" - srec_cat "floppyemu.hex" -intel "..\bootldr\bootldr\Release\bootldr.hex" -intel -o "merged.hex" -intel - "C:\Program Files (x86)\Atmel\AVR Studio 5.1\extensions\Atmel\AVRGCC\3.3.1.27\AVRToolchain\bin\avr-size.exe" -C --mcu=atmega1284p "floppyemu.elf" - - - - - - - -# Other Targets -clean: - -$(RM) $(OBJS_AS_ARGS)$(C_DEPS_AS_ARGS) $(EXECUTABLES) - rm -rf "floppyemu.hex" "floppyemu.lss" "floppyemu.eep" "floppyemu.map" - \ No newline at end of file diff --git a/arduino/floppyemu/Release/femu.bin b/arduino/floppyemu/Release/femu.bin deleted file mode 100755 index 7980912..0000000 Binary files a/arduino/floppyemu/Release/femu.bin and /dev/null differ diff --git a/arduino/floppyemu/Release/floppyemu.hex b/arduino/floppyemu/Release/floppyemu.hex deleted file mode 100755 index 3bbc610..0000000 --- a/arduino/floppyemu/Release/floppyemu.hex +++ /dev/null @@ -1,1983 +0,0 @@ -:10000000B2C30000DFC30000DDC30000DBC300009B -:100010000C941F0ED7C300000C94AB0A0C94F70984 -:10002000D1C30000CFC30000CDC30000CBC300008C -:10003000C9C30000C7C30000C5C30000C3C300009C -:10004000C1C30000BFC300000C945A1DBBC3000015 -:10005000B9C30000B7C30000B5C30000B3C30000BC -:10006000B1C30000AFC30000ADC30000ABC30000CC -:10007000A9C30000A7C30000A5C30000A3C30000DC -:10008000A1C300009FC300009DC3000000000C003E -:100090001800240030003C004800540060006C0050 -:1000A0007800840090009C00A800B400C000CB0041 -:1000B000D600E100EC00F70002010D011801230158 -:1000C0002E01390144014F015A01650170017A0185 -:1000D00084018E019801A201AC01B601C001CA01E0 -:1000E000D401DE01E801F201FC010602100219024E -:1000F00022022B0234023D0246024F0258026102E4 -:100100006A0273027C0285028E029702A002A80294 -:10011000B002B802C002C802D002D802E002E8026F -:10012000F002F80200030803100318030C0C0C0C77 -:100130000C0C0C0C0C0C0C0C0C0C0C0C0B0B0B0B03 -:100140000B0B0B0B0B0B0B0B0B0B0B0B0A0A0A0A03 -:100150000A0A0A0A0A0A0A0A0A0A0A0A0909090903 -:100160000909090909090909090909090808080803 -:1001700008080808080808080808080896979A9BBD -:100180009D9E9FA6A7ABACADAEAFB2B3B4B5B6B7AC -:10019000B9BABBBCBDBEBFCBCDCECFD3D6D7D9DAD3 -:1001A000DBDCDDDEDFE5E6E7E9EAEBECEDEEEFF2E6 -:1001B000F3F4F5F6F7F9FAFBFCFDFEFF0001FFFF93 -:1001C0000203FF040506FFFFFFFFFFFF0708FFFF15 -:1001D000FF090A0B0C0DFFFF0E0F10111213FF1475 -:1001E00015161718191AFFFFFFFFFFFFFFFFFFFF8C -:1001F000FF1BFF1C1D1EFFFFFF1FFFFF2021FF2213 -:10020000232425262728FFFFFFFFFF292A2BFF2C69 -:100210002D2E2F303132FFFF333435363738FF394A -:100220003A3B3C3D3E3F0000211042206330844079 -:10023000A550C660E770088129914AA16BB18CC1B5 -:10024000ADD1CEE1EFF13112100273325222B5522C -:100250009442F772D662399318837BB35AA3BDD305 -:100260009CC3FFF3DEE36224433420040114E664FC -:10027000C774A44485546AA54BB528850995EEE555 -:10028000CFF5ACC58DD55336722611163006D7760C -:10029000F6669556B4465BB77AA719973887DFF7A5 -:1002A000FEE79DD7BCC7C448E5588668A7784008D4 -:1002B000611802282338CCC9EDD98EE9AFF94889F5 -:1002C00069990AA92BB9F55AD44AB77A966A711A6C -:1002D000500A333A122AFDDBDCCBBFFB9EEB799B45 -:1002E000588B3BBB1AABA66C877CE44CC55C222CBC -:1002F000033C600C411CAEED8FFDECCDCDDD2AAD95 -:100300000BBD688D499D977EB66ED55EF44E133E4B -:10031000322E511E700E9FFFBEEFDDDFFCCF1BBFE4 -:100320003AAF599F788F8891A981CAB1EBA10CD1BE -:100330002DC14EF16FE18010A100C230E3200450C6 -:10034000254046706760B9839893FBA3DAB33DC339 -:100350001CD37FE35EF3B1029012F322D232354216 -:10036000145277625672EAB5CBA5A89589856EF5C9 -:100370004FE52CD50DC5E234C324A0148104667466 -:10038000476424540544DBA7FAB79987B8975FE719 -:100390007EF71DC73CD7D326F2369106B0165766B6 -:1003A0007676154634564CD96DC90EF92FE9C899A1 -:1003B000E9898AB9ABA94458654806782768C01806 -:1003C000E1088238A3287DCB5CDB3FEB1EFBF98B79 -:1003D000D89BBBAB9ABB754A545A376A167AF10A56 -:1003E000D01AB32A923A2EFD0FED6CDD4DCDAABD89 -:1003F0008BADE89DC98D267C076C645C454CA23CA6 -:10040000832CE01CC10C1FEF3EFF5DCF7CDF9BAF58 -:10041000BABFD98FF89F176E367E554E745E932EF5 -:10042000B23ED10EF01E20202020202020202020AF -:100430002020202020202020202020002049646C23 -:1004400065002052656164005772697465005472DA -:1004500061636B202020205369646500313434309F -:100460004B204469736B436F707920696D616765D8 -:10047000003830304B204469736B436F70792069CA -:100480006D616765003430304B204469736B436F96 -:10049000707920696D61676500313434304B2072AA -:1004A000617720696D616765003830304B2072617B -:1004B0007720696D616765003430304B2072617759 -:1004C00020696D61676500696D616765206E6F7495 -:1004D00020636F6E746967756F7573006572726FF4 -:1004E00072206F70656E696E6720696D6167650067 -:1004F000505245563A2043616E63656C004E455834 -:10050000543A204C6F6164206669726D7761726540 -:1005100000626567696E0052656C65617365206293 -:100520007574746F6E7320746F0043504C44204692 -:1005300049524D574152452055504441544500437E -:100540006F6E74726173743A200053454C45435486 -:100550003A2053617665004E4558543A2044617202 -:100560006B657200505245563A204C696768746555 -:100570007200626567696E0052656C656173652023 -:10058000627574746F6E7320746F00434F4E5452D3 -:100590004153542041444A5553544D454E54004113 -:1005A00070702056657273696F6E20312E30204C4A -:1005B000002020202020464C4F50505920454D55BA -:1005C00020202020202000507265737320616E79F6 -:1005D00020627574746F6E006669726D7761726502 -:1005E0002E78766600436F756C64206E6F74206F92 -:1005F00070656E005570646174696E67206669721B -:100600006D776172652E2E2E00464154414C204577 -:1006100052524F52202020202020202020200057FE -:1006200052495445204552524F522020202020202C -:1006300020202020000000000017000300031F0AF4 -:100640001F0A1F050904120F171C000303000E11D7 -:10065000110E00050205040E041008000404040035 -:1006600010001804031E110F021F00191512151592 -:100670000A07041F1715091E151D1905031A150B66 -:1006800017150F000A00040C04040E1F0A0A0A1FA3 -:100690000E040115030E15161E051E1F150A0E1158 -:1006A000111F110E1F15151F05050E151D1F041F07 -:1006B000111F1108100F1F041B1F10101F061F1FF2 -:1006C0000E1F0E110E1F05020E191E1F0D161215FC -:1006D00009011F010F101F0718071F0C1F1B041B08 -:1006E000031C031915131F101002040810101F0417 -:1006F00006041010100003031A161C1F120C0C1213 -:10070000120C121F0C1A16041E050C2A1E1F021CA6 -:10071000001D0010201D1F0C12111F101E0E1E1E8A -:10072000021C0C120C3E120C0C123E1C0202141E77 -:100730000A021F120E101E0E180E1E1C1E120C1284 -:1007400006281E1A1F16041B11001F00111B040887 -:100750000C047C3C3E5E2B3D3F2F5B5D3B2C2A22F4 -:100760005C00451D491D11241FBECFEFD0E4DEBF44 -:10077000CDBF13E0A0E0B1E0EAE9F9E700E00BBF8C -:1007800002C007900D92A831B107D9F717E3A8E18D -:10079000B3E001C01D92AD3DB107E1F717E000E005 -:1007A000C4E6D7E040E006C022974109FE014BBFF6 -:1007B0000E947A39C236D1074007B1F70E94191852 -:1007C0000C94BC3C1DCC2F923F924F925F926F9243 -:1007D0007F928F929F92AF92BF92CF92DF92EF92D1 -:1007E000FF920F931F93DF93CF93CDB7DEB72D9773 -:1007F0000FB6F894DEBF0FBECDBF8B014A013E019C -:100800000894611C711CD301E4E2F1E02DE0019039 -:100810000D922150E1F7BB244424AA2452E8552E1E -:1008200042E2E42EF12CE80EF91E3EE0C32ED12C5C -:10083000CC0EDD1E22E8222E312C280C391CC701DB -:10084000B80140E250E00E94C92480329105A1F431 -:10085000D8011B968C911B9790E09C012F733070F0 -:100860002F30310559F183FD23C0F8018081853E89 -:1008700019F1882309F05AC0D4011C9280E02D960A -:100880000FB6F894DEBF0FBECDBFCF91DF911F91A1 -:100890000F91FF90EF90DF90CF90BF90AF909F901F -:1008A0008F907F906F905F904F903F902F90089522 -:1008B000F8018081882301F3BB24C1CFBB2021F53F -:1008C0008C91982F907E903409F0B9CF9FE1A92E9A -:1008D000A8221D964C90F1011082A5E7B0E085E7B3 -:1008E000582EF301AD01480D591D81919801280F33 -:1008F000311DD9018C91DA018D93AD01EC15FD0507 -:10090000A1F7BB24B3949BCFD8018C91AA948A15EC -:1009100099F61D968C911D97841571F6552009F452 -:100920008ECFB3EF5B0EA52DB0E0DBCF8E3221F280 -:10093000BB2081F031962BE090E001C08191392FEE -:100940003795332737959695932B980F2150B1F70C -:10095000941531F0C801B4010E94092481E08FCFC1 -:10096000FA2DF130B9F7452D50E043385105B4F771 -:100970009A0160E080E090E0880D991D280D391DF6 -:10098000D9012C91FC0120836F5F862F90E09C01A0 -:10099000240F351F233831057CF381E070CFEF92AF -:1009A000FF920F931F93DF93CF93CDB7DEB7A99735 -:1009B0000FB6F894DEBF0FBECDBFFC01DB018C91FA -:1009C0008E32A9F1838590E0887190708031910515 -:1009D00009F466C0009759F5848D958DA68DB78D65 -:1009E000803020E4920726E0A20720E0B20709F455 -:1009F00059C0803020E892072CE0A20720E0B2071F -:100A000009F454C0803020E8920726E1A20720E0D4 -:100A1000B20709F449C081509044A640B0408F3FCE -:100A20002FE2920721E1A20720E0B20778F020E050 -:100A3000822FA9960FB6F894DEBF0FBECDBFCF911F -:100A4000DF911F910F91FF90EF900895CF017E01EC -:100A50000894E11CF11CB7010E9409241E86198A22 -:100A60008E01025F1F4FC801B70141E00E94342A86 -:100A7000882371F0C80165E773E340E052E00E940B -:100A8000C924C8010E9433278091C733813081F087 -:100A90008989882361F2C8010E94332720E0C8CFEA -:100AA00021E0C6CF23E0C4CF25E0C2CF24E0C0CFF1 -:100AB0008091C833882361F78091B63390E0A0E03D -:100AC000B0E0BA2FA92F982F88272091B733820F33 -:100AD000911DA11DB11DB695A79597958795B695C2 -:100AE000A79597958795803921E0920720E0A20786 -:100AF00020E0B207F1F0803223E0920720E0A20765 -:100B000020E0B207A1F0803A25E0920720E0A2079A -:100B100020E0B20709F0BCCF28E08989882309F4D6 -:100B200087CFC80129A70E94332729A581CF27E0B5 -:100B3000F4CF26E0F2CF2F923F924F925F926F92C6 -:100B40007F928F929F92AF92BF92CF92DF92EF925D -:100B5000FF920F931F93DF93CF93CDB7DEB7C05FA4 -:100B6000D0400FB6F894DEBF0FBECDBF7C0110920F -:100B7000190310921803829640E050E0BA010E94D7 -:100B80004B2603E4C02ED12CCC0EDD1E13E6A12E85 -:100B9000B12CAC0EBD1EB4E26B2E712CC701B60198 -:100BA000A50111DE8823E1F18091180390911903CA -:100BB00021E08734920708F0A7C1C601B501EFDE36 -:100BC000882E882359F38091180390911903869DEC -:100BD0008001879D100D969D100D11240B581C4F00 -:100BE000C801B50146E150E00E94B339B8016A5E20 -:100BF0007F4FC6010E940924809118039091190328 -:100C0000869DF001879DF00D969DF00D1124EB5807 -:100C1000FC4F83A201969093190380931803BECFD3 -:100C20002091180330911903C751DF4F398328836E -:100C3000C95ED040F70185A182508230A8F184E2DC -:100C400090E0C751DF4FE881F981C95ED040E89F4D -:100C50008001E99F100DF89F100D11240B581C4FB7 -:100C6000C80160E071E046E150E00E94B339C8017C -:100C7000469660E071E04DE050E00E94B33982E0BA -:100C8000F80183A3C751DF4F28813981C95ED04065 -:100C90002F5F3F4FC751DF4F39832883C95ED04054 -:100CA0003093190320931803A8E92A2EA3E03A2EC3 -:100CB00080E090E07E010894E11CF11CF7E1CF2E6A -:100CC000D12CCC0EDD1EC751DF4FE881F981C95E02 -:100CD000D0408E179F0708F01EC1FC013196C3510A -:100CE000DF4FF983E883CD5ED040C751DF4F2881C5 -:100CF0003981C95ED040E217F30708F026C1C1016F -:100D00008397F101B496C151DF4FF983E883CF5E39 -:100D1000D0405F01C351DF4F48805980CD5ED04045 -:100D2000CA51DF4F8883C65ED04091012D503040BC -:100D3000C551DF4F39832883CB5ED040C951DF4F87 -:100D400039822882C75ED040392EC701CA51DF4F91 -:100D50006881C65ED040732D46E150E00E94B339F1 -:100D600088240AC00E0D1F1DF801808190E00E94AA -:100D70007E39F80180838394F70101900020E9F720 -:100D80003197EE19FF09082D10E00E171F0750F3D9 -:100D9000EDED8E2EEFEF9E2E8A0C9B1C682C292CDD -:100DA000C601B40146E150E00E94B33977240AC07D -:100DB0000C0D1D1DF801808190E00E947E39F80124 -:100DC00080837394F60101900020E9F73197EC19C4 -:100DD000FD09072D10E00E171F0750F3C701B601DC -:100DE00046E150E00E94A539282F392FC951DF4F25 -:100DF000E881F981C75ED04080818150823008F45B -:100E000080C0F50180818150823008F477C01216CD -:100E100013060CF055C0CE018D96CA51DF4F688184 -:100E2000C65ED040732D46E150E00E94B339CA51EE -:100E3000DF4F8881C65ED040932D662D722D46E12E -:100E400050E00E94B339862D922DBE01635D7F4F25 -:100E500046E150E00E94B339CE018D96C551DF4F77 -:100E600068817981CB5ED0404DE050E00E94B3397B -:100E700084010A5E1F4FC551DF4F88819981CB5E87 -:100E8000D040B8014DE050E00E94B339C801BE0126 -:100E9000635D7F4F4DE050E00E94B339C951DF4F91 -:100EA000E881F981C75ED0408081F5019081C95108 -:100EB000DF4FE881F981C75ED0409083F5018083E0 -:100EC0000894411C511C24E230E0A20EB31EC7510D -:100ED000DF4F88819981C95ED0404816590608F4D1 -:100EE00034CFC151DF4F28803980CF5ED040C3510D -:100EF000DF4F88819981CD5ED040E5CE28513C4FAF -:100F000086CF285E33407DCFC751DF4F99838883DA -:100F1000C95ED0408FCEC051DF4F0FB6F894DEBF10 -:100F20000FBECDBFCF91DF911F910F91FF90EF903A -:100F3000DF90CF90BF90AF909F908F907F906F90F9 -:100F40005F904F903F902F900895C1018496C151BA -:100F5000DF4F99838883CF5ED040C3CF8F929F921B -:100F6000AF92BF92CF92DF92EF92FF920F931F93B7 -:100F7000CF93DF9380911A0390911B0320911C0360 -:100F800030911D032817390728F430931B03209351 -:100F90001A03C90104968217930730F42450304095 -:100FA00030931B0320931A0380E060E00E949A1D97 -:100FB00081E06FE70E948B1DC3E1D0E081E060E437 -:100FC0000E948B1D2197D1F783E091E00E948F1E34 -:100FD000C3E1D0E081E060E40E948B1D2197D1F74E -:100FE00081E06FE70E948B1D209118033091190357 -:100FF0002115310509F464C140911A0350911B0376 -:10100000CA0105964817590708F033C1421753071C -:1010100008F02FC164E270E0469F7001479FF00C1A -:10102000569FF00C112488E993E0E80EF91EEA01BE -:1010300091E0C92ED12CBB24B39480911C039091D4 -:101040001D03C817D90709F0BB24AC2C80E06C2D18 -:101050000E949A1D04E510E007C060E081E00E9454 -:101060008B1D0150104049F0BB20B9F36FE781E0C0 -:101070000E948B1D01501040B9F781E06A2D0E943B -:101080009A1D870103521040902E812EC8016B2DAE -:1010900043E50E94A61DF70180818150823008F44B -:1010A000BDC0BB2009F0A4C08601219640911A035F -:1010B00050911B03CA010596C817D907E0F120918A -:1010C0001803309119032630310508F047C0EE248B -:1010D000E39482E56E2D0E949A1D81E060E00E94FB -:1010E0008B1D81E060E00E948B1DE3947E2D7630A5 -:1010F00081F780911A0390911B039801280F391FE3 -:1011000040911C0350911D034217530708F4E2C09D -:101110002150304030931D0320931C0304301105EF -:1011200009F02CCF009709F429CF019790931B0366 -:1011300080931A0323CF2091180330911903089448 -:10114000C11CD11C64E270E0E60EF71EC217D30783 -:1011500008F471CF2630310508F4B9CFE7E2F0E0AA -:101160004E9FC0014F9F900D5E9F900D11248D5397 -:101170009F4FB9010E94293988E0E82EE60E83ECE2 -:1011800090E0B9010E942939CE2CC61AC8E0D0E0FF -:10119000BB24B39482E56B2D0E949A1D81E060E030 -:1011A0000E948B1D4C2F9E01295F3F4F2C173D073E -:1011B0000CF484C060E00AC0E41650F066956068E4 -:1011C0004F5F842F90E0281739074CF04C15A0F79B -:1011D00066954F5F842F90E028173907BCF781E0B0 -:1011E0000E948B1DB39428967B2D763099F681CF83 -:1011F00084E393E0692D782D46E150E00E94B339F5 -:10120000B8016A5E7F4F8EE193E04DE050E00E94AE -:10121000B339F701808180934A0346CF89E46A2D70 -:101220000E949A1DBB2041F181E06FE70E948B1D57 -:1012300081E063E40E948B1D81E06DE50E948B1DBF -:1012400081E06DE50E948B1D81E06DE50E948B1DA4 -:1012500081E06BE50E948B1D81E06BE50E948B1D98 -:1012600081E063E40E948B1D6FE781E00E948B1D8B -:1012700018CF00E010E027CF81E060E00E948B1DD6 -:1012800081E06CE30E948B1D81E062E20E948B1D75 -:1012900081E062E20E948B1D81E062E20E948B1D70 -:1012A00081E064E20E948B1D81E064E20E948B1D5C -:1012B00081E06CE30E948B1D60E0D7CF60E08FCFB0 -:1012C00080E061E00E949A1D8FE091E060E044E5DB -:1012D0000E94A61DDF91CF911F910F91FF90EF907B -:1012E000DF90CF90BF90AF909F908F900895813006 -:1012F000910559F0009721F48091A135882309F4D4 -:1013000008958EE995E30C94332710929E35109240 -:10131000A13508958FE781B9559A209A3A9A3D9A56 -:101320003E9A3B9A239A5C9A599A5A9A5F9A5B9A88 -:10133000179A589A409A419A289A429A45984698FC -:10134000439A2B9AE3E7F0E0808181608083EDE6A9 -:10135000F0E0808182608083808181608083089555 -:101360001F93DF93CF93CDB7DEB72A970FB6F894CC -:10137000DEBF0FBECDBFCE010196DC01EEEDF2E087 -:101380002AE001900D922150E1F7E0914C03F0E04A -:10139000F595E795F595E795F595E795F595E79535 -:1013A0001FB7F894E53008F0E4E0F0E0EE0FFF1F1F -:1013B000E80FF91F20813181220F331F40E050E0F8 -:1013C00060E07DE281E391E00E945F3930935B034E -:1013D00020935A031FBF82E086BB2A960FB6F8946B -:1013E000DEBF0FBECDBFCF91DF911F9108951F9239 -:1013F0000F920FB60F920BB60F9211242F933F93BB -:101400004F935F936F937F938F939F93AF93BF930C -:10141000CF93DF93EF93FF93489B2FC0E0914C0352 -:1014200080915503882309F03DC0F0E0E45DFE4F54 -:10143000249130E0220F331F21153105A9F537998A -:101440005DC080914C038F5F80934C0380914C036F -:10145000882309F064C04598429A4899FECF429883 -:10146000459A7EDFC0919435D0919535C330D10532 -:1014700008F057C081E080935103FF91EF91DF9115 -:10148000CF91BF91AF919F918F917F916F915F911C -:101490004F913F912F910F900BBE0F900FBE0F9069 -:1014A0001F90189524E230E080E090E040E050E0AA -:1014B00068E188589A4CFC01808180FF03C0683144 -:1014C00059F1542F4F5F842F90E0821793070CF14E -:1014D000561708F4B4CF862FE82FF0E0E858FA4CFE -:1014E000908191FF03C0908191609083908194607E -:1014F00090838F5F581780F7379BA3CF80914C0361 -:10150000882309F4A3CF80914C03815080934C032E -:101510009DCF4831E9F2CDCF542F642FD3CF459AD8 -:101520009BCF8FE593E061E371E046E150E00E94DC -:10153000B339C851DC4FD0937735C09376351092CC -:10154000500381E0809351038093520310929535AC -:10155000109294358FCF1F920F920FB60F920BB649 -:101560000F9211241F932F933F934F935F936F9389 -:101570007F938F939F93AF93BF93CF93DF93EF931B -:10158000FF9386B190E095958795817090914E0379 -:10159000891791F090915803923009F46DC0109220 -:1015A0004E0311E010935103C0919435D0919535BD -:1015B000C330D10508F047C086B1817011E08127A2 -:1015C000909150038917C9F0809350038091500384 -:1015D000882349F58FE781B9469880916B008F7712 -:1015E00080936B00C0919435D0919535C330D1056F -:1015F00008F045C081E080935103FF91EF91DF91A6 -:10160000CF91BF91AF919F918F917F916F915F919A -:101610004F913F912F911F910F900BBE0F900FBED6 -:101620000F901F90189511B8469A80916B008068B2 -:1016300080936B0080B180788093933510929535BC -:1016400010929435D7CF8FE593E061E371E046E1E6 -:1016500050E00E94B339C053D84FD0937735C09330 -:101660007635109250031093510310935203109249 -:10167000953510929435A0CF80934E0392CF8FE58D -:1016800093E061E371E046E150E00E94B339C85451 -:10169000D44FD0937735C093763510925003109382 -:1016A0005103109352031092953510929435A2CFA6 -:1016B0001F93E0B1E0688091943590919535843026 -:1016C000910588F48330910509F487C0DC01A153AA -:1016D000BD4F2C912E1709F404C11092953510922C -:1016E00094351F910895F0E0EA5DFE4FE49132E0F9 -:1016F0008F3B930748F59C012370307022303105F1 -:1017000009F4BBC02330310509F449C1213031054A -:1017100009F418C1EE0FEE0FE093963540919A351B -:1017200050E09A01220F232F221F330B20939B3569 -:10173000440F551F422B40939A350196909395354F -:10174000809394351F910895F2E08F3B9F0709F431 -:10175000C1C022E0803C920709F4CEC032E0813C57 -:10176000930709F4E2C1F2E0823C9F0709F0B5CF8C -:1017700080919635982F990F990F90939635E82B75 -:1017800090919A35E917C9F08FE593E062E971E02D -:1017900046E150E00E94B33980E490E090937735C1 -:1017A000809376351092500381E0809351038093AB -:1017B00052031092953510929435E0919735F0E0F0 -:1017C000E858FA4C808182608083808181608083C8 -:1017D00080818B7F80832B9A80CFF0E0EA5DFE4F83 -:1017E0001491E0914C0380915503882309F082C045 -:1017F000F0E0E45DFE4FE4911E1708F04DC1E0916A -:101800004C03882309F074C0F0E0E45DFE4FE491DE -:1018100080914E03E89F802D1124810F809397358E -:1018200090E0DC01A858BA4C2C9122FDE0C0982F22 -:101830008827990F8B589C4F90939D3580939C35AA -:101840008C9184608C938C918D7F8C9380914C03D0 -:101850008093903580914E0380939135109392350B -:101860002B9810929A351092993510929835809154 -:10187000943590919535019661CF50919635452FCD -:10188000407C4E2B2091983542278431910578F089 -:10189000E0919C35F0919D354193F0939D35E09317 -:1018A0009C35509196358091943590919535609105 -:1018B0009B352091993530E0260F311D240F311DC5 -:1018C0002093993530939B35550F550F509396358E -:1018D000019634CFEE0FEE0FE093963580EC92E058 -:1018E0002DCF20915403222309F0F7CE019626CF65 -:1018F000E2E18ECFE2E180CF80919635982F990F6B -:10190000990F90939635807C8E2B909198358917FE -:1019100009F46AC08FE593E06CE671E046E150E0BF -:101920000E94B3398EE390E09093773580937635BB -:101930001092500381E0809351038093520381E021 -:1019400090E0FCCE50919635452F407C4E2B209157 -:101950009A3542278431910578F0E0919C35F091D9 -:101960009D354193F0939D35E0939C35509196358C -:10197000809194359091953560919B352091983563 -:1019800030E0260F311D240F311D20939835309300 -:101990009B35550F550F509396350196CFCE4091FC -:1019A00096354E2B2091993542278431910568F068 -:1019B000E0919C35F0919D354193F0939D35E093F6 -:1019C0009C35809194359091953550919B3520911F -:1019D0009A3530E0250F311D240F311D20939A35A3 -:1019E00030939B350196AACE81EC92E0A7CE309140 -:1019F0004C0320914E038DB79EB70C970FB6F89409 -:101A00009EBF0FBE8DBFADB7BEB711968FE593E0F9 -:101A1000EDB7FEB79283818386E190E013969C93A5 -:101A20008E93129788E591E015969C938E93149768 -:101A300016963C93169717961C92179718962C9308 -:101A4000189719961C9219971A961C931A971B9619 -:101A50001C920E94C2398DE390E090937735809379 -:101A600076351092500381E08093510380935203A6 -:101A700010929535109294358091973590E02DB75E -:101A80003EB7245F3F4F0FB6F8943EBF0FBE2DBF49 -:101A9000DC01A858BA4CCBCE20914C038DB79EB731 -:101AA0000A970FB6F8949EBF0FBE8DBFADB7BEB7F5 -:101AB00011968FE593E0EDB7FEB79283818386E1BF -:101AC00090E013969C938E93129782E491E0159682 -:101AD0009C938E93149716961C93169717961C92A8 -:101AE000179718962C93189719961C920E94C23932 -:101AF0008CE390E090937735809376351092500385 -:101B000081E0809351038093520310929535109297 -:101B10009435809155032DB73EB7265F3F4F0FB6E2 -:101B2000F8943EBF0FBE2DBF6ACE80919635982F98 -:101B3000990F990F90939635807C8E2B90919935C3 -:101B4000891759F08FE593E06FE771E046E150E0C7 -:101B50000E94B3398FE390E0E7CE82EC92E0EECDC5 -:101B60004091560350915703E2EEF2E025913491F3 -:101B700060E07FEF2627372791EA692F632770E01F -:101B8000660F771F6A5D7D4FFB0165917491322F5F -:101B90002227262737279327E92FF0E0EE0FFF1F94 -:101BA000EA5DFD4F65917491322F22272627372752 -:101BB000EBEFE327F0E0EE0FFF1FEA5DFD4F6591CD -:101BC0007491322F222726273727B82FBB0FA0E08A -:101BD000AB58BC4F80E090E0722F6627ED91E32771 -:101BE000F0E0EE0FFF1FEA5DFD4F259134912627AF -:101BF0003727019662E08030960771F730935703DC -:101C00002093560342175307C9F08FE593E065EA26 -:101C100071E046E150E00E94B33986E490E0909391 -:101C20007735809376351092500381E0809351038D -:101C300080935203109295351092943508951F9217 -:101C40000F920FB60F920BB60F9211242F933F9362 -:101C50004F935F936F937F938F939F93AF93BF93B4 -:101C6000EF93FF9390B180915003882309F456C0FD -:101C7000892F807890919335891709F44FC080930C -:101C8000933590915503992309F46FC0882309F483 -:101C900061C020B12F7080919635282B2093963506 -:101CA00080919435909195358230910509F45FC00B -:101CB000009709F446C08130910509F46DC032E007 -:101CC0008330930708F458C0A2E083309A0709F4E0 -:101CD0009AC0B2E084309B0709F530E0809156034A -:101CE00090915703822B932B909357038093560325 -:101CF0008091973535DFE0919735F0E0E858FA4C60 -:101D000080818260808380818160808380818B7FFD -:101D100080832B9A1092953510929435FF91EF9114 -:101D2000BF91AF919F918F917F916F915F914F91F3 -:101D30003F912F910F900BBE0F900FBE0F901F90F1 -:101D40001895213A59F781E090E09093953580936A -:101D50009435E4CF80B190E082959295907F98275A -:101D6000807F982780939635D9CFA2DCD7CF2B3FA1 -:101D7000E9F0213A79F6D2CF30919735F32FFF0F62 -:101D8000E0E0E80FF91FEE58FC4F20830196909396 -:101D9000953580939435C2CF213A09F0BBCF82E0CC -:101DA00090E09093953580939435B8CF83E090E0A0 -:101DB00090939535809394352091590320939735CE -:101DC000822F90E0FC01E858FA4C308132FD26C0A9 -:101DD000982F8827990F8B589C4F90939D3580930F -:101DE0009C3580818460808380818D7F8083809119 -:101DF0004C038093903580914E03809391352093CE -:101E000092352B988BCF109256032093570384E082 -:101E100092E0909395358093943580CF50914C0308 -:101E200040914E032DB73EB72C5030400FB6F8947A -:101E30003EBF0FBE2DBFEDB7FEB731962FE533E0A5 -:101E4000ADB7BEB712963C932E93119726E130E0C2 -:101E50003383228328E531E0358324835683178238 -:101E600040871186938782870E94C23987E490E079 -:101E700090937735809376351092500381E080936C -:101E800051038093520310929535109294352DB7DB -:101E90003EB7245F3F4F0FB6F8943EBF0FBE2DBF35 -:101EA0003DCFF89490915003992341F48F7782B9F4 -:101EB000459A079BFECF0799FECF459878940895E1 -:101EC0008AE082B9459A079BFECF0799FECF4598D5 -:101ED000E091570381EAE827F0E0EE0FFF1FEA5D8B -:101EE000FD4F859194913091560320E082279327EE -:101EF000909357038093560381E182B9459A079BDB -:101F0000FECF0799FECF45980895982F92959F7020 -:101F100092B9459A079BFECF0799FECF4598482F67 -:101F20004F70E0915703E827F0E0EE0FFF1FEA5DE6 -:101F3000FD4F859194913091560320E0822793279D -:101F4000909357038093560342B9459A079BFECF5F -:101F50000799FECF459808952F923F924F925F9236 -:101F60006F927F928F929F92AF92BF92CF92DF92A9 -:101F7000EF92FF920F931F93DF93CF9300D00F92B6 -:101F8000CDB7DEB78983692EA2EDCA2EA2E0DA2E84 -:101F9000992422243324EE24FF2400E010E088C09A -:101FA0001070C801880F991F2801440C452C441C4F -:101FB00055085194482A592AF6010191852D9927EF -:101FC000820D931D800F911DAFEF4A225524D6013B -:101FD0001196AC906F010894C11CD11CA7014A0D49 -:101FE000511D9C0120703170232F3327420F531F46 -:101FF0003FEF232E312C2822392271802FEFE22E41 -:10200000F12CE422F522872C8E24042510E0A22452 -:10201000BB24F501E07CF070F595E795F595E79523 -:10202000F595E795F595E7959801207C3070359505 -:10203000279535952795E22BF32B882D829586954C -:102040008695837090E0E82BF92BE458FE4F84913D -:102050004A835B8326DF0F73107004581E4FF8010C -:1020600084911FDF809151034A815B81882309F0AD -:10207000A9C00894C11CD11C8201070D111D40701C -:102080005170452F5527040F151FF501EF73F070A0 -:10209000E458FE4F849105DFE82DF0E0EF73F07017 -:1020A000E458FE4F8491FDDE9394F92DFE3A41F001 -:1020B000292D243009F074CF9981C92ED62C70CFE8 -:1020C0001070C801880F991F5801AA0CAB2CAA1CCC -:1020D000BB08B194A82AB92AD6010C91200E311C54 -:1020E0008B2D9927280E391E1196CC90EC0CF11CE3 -:1020F000C10180709170892F9927E80EF91E0A2579 -:1021000010E0C224DD24F601E07CF070F595E7953F -:10211000F595E795F595E795F595E795C801807CE8 -:1021200090709595879595958795E82BF92BE458B0 -:10213000FE4F8491B6DEF801EF73F070E458FE4F65 -:102140008491AFDEF601EF73F070E458FE4F849196 -:10215000A8DEF101E07CF070F695E795F695E7953D -:10216000C501807C90700024880F991F001C880F87 -:10217000991F001C892F902DE82BF92BC701807C1B -:102180009070929582958F7089279F708927E82B90 -:10219000F92BE458FE4F849184DEF101EF73F07067 -:1021A000E458FE4F84917DDEF701EF73F070E45840 -:1021B000FE4F849176DEF501EF73F070E458FE4F28 -:1021C00084916FDE0F900F900F90CF91DF911F9150 -:1021D0000F91FF90EF90DF90CF90BF90AF909F90C6 -:1021E0008F907F906F905F904F903F902F900895C9 -:1021F000CF93DF9380E060E00E949A1D81EB95E031 -:1022000061E00E94271E8FE995E00E948639819542 -:10221000880F865D62E00E949A1D8FE995E060E07C -:102220000E94271E4DB75EB7485050400FB6F89435 -:102230005EBF0FBE4DBFEDB7FEB73196CFE5D3E021 -:10224000ADB7BEB71296DC93CE93119786E190E0BE -:102250009383828383EB91E09583848380915E03F3 -:10226000868317820E94C239FE0101900020E9F79F -:102270003197EC1BFD0B4DB75EB7485F5F4F0FB654 -:10228000F8945EBF0FBE4DBF8E2F8195880F865D7F -:1022900063E00E949A1DCE0160E044E50E94A61D05 -:1022A0002B980E94531D95E028E04FEF53ED60E31B -:1022B000415050406040E1F700C0000085B18227E6 -:1022C00085B9915091F70E94571DDF91CF910895E4 -:1022D000CF92DF92EF92FF920F931F93DF93CF93F2 -:1022E00000D000D0CDB7DEB780E060E00E949A1D3C -:1022F0000E94D21E80E060E00E949A1D8BE895E06B -:1023000060E00E94271E80E062E00E949A1D88E73C -:1023100095E060E00E94271E80E063E00E949A1D25 -:1023200082E795E060E00E94271E499BFECF4A9B12 -:10233000FCCF4C9BFACF80E060E00E949A1D0E9487 -:10234000D21E80E062E00E949A1D84E695E060E083 -:102350000E94271E80E063E00E949A1D87E595E0B9 -:1023600060E00E94271E80E064E00E949A1D8AE4DB -:1023700095E060E00E94271E8E010F5F1F4F84ECE6 -:10238000E82E81E0F82EB4E0CB2ED12C16C080913F -:10239000C7358F3F29F08091C7358F5F8093C73550 -:1023A00080E061E20E948B1D6091C73580E00E9451 -:1023B0008B1D80E060E20E948B1D80E060E00E9447 -:1023C0009A1D8FE395E060E00E94271E8091C7353B -:1023D0002DB73EB7285030400FB6F8943EBF0FBE21 -:1023E0002DBFEDB7FEB73196ADB7BEB712961C93B1 -:1023F0000E931197D382C282F582E482868317827C -:102400000E94C2392DB73EB7285F3F4F0FB6F894F0 -:102410003EBF0FBE2DBFC80160E044E50E94A61D6F -:102420008FEF99E6A8E181509040A040E1F700C00D -:102430000000499B04C04A9B02C04C99FACF4A9BBA -:10244000A6CF49990BC08091C735813808F4A8CF31 -:102450008091C73581508093C735A2CF4C99A0CFCA -:102460006091C73581E090E00E940A3C0F900F9088 -:102470000F900F90CF91DF911F910F91FF90EF90F0 -:10248000DF90CF9008951F930E94D21E80E060E0FD -:102490000E949A1D84E393E060E044E50E94A61D3B -:1024A00080E061E00E949A1D8EE995E36EE173E0A1 -:1024B00043E00E94342A882309F48AC080914A03A9 -:1024C000833029F1863019F182E0809358038EE938 -:1024D00095E36BEB75E34FEB55E30E94562388239E -:1024E000D1F487EC94E060E00E94271E8FEF93E226 -:1024F000A4EF81509040A040E1F700C0000010E040 -:102500008EE995E30E943327812F1F91089581E082 -:1025100080935803DCCF80E061E00E949A1D809197 -:102520004A03853009F4BFC0863008F05FC08330AD -:1025300009F4A1C0843039F489EA94E060E00E9493 -:10254000271E80914A0391E0863008F490E0909332 -:1025500075354F998CC0992309F45CC081E0809354 -:10256000540348E754E060E070E08EE995E30E9490 -:102570004B268EE995E365E773E040E052E00E9468 -:10258000C924E0917503F0E0EA58FC4F10821092E4 -:102590008B0380E062E00E949A1D86E793E060E092 -:1025A00044E50E94A61D80E064E00E949A1D8EE42E -:1025B00094E060E00E94271E80915403882379F5FF -:1025C00011E08EE995E30E943327812F1F91089532 -:1025D0008EE995E36EE173E041E00E94342A88239E -:1025E00009F464C081E08093540371CF873009F40B -:1025F00052C0873008F447C0883009F0A4CF8CE57A -:1026000094E060E00E94271E81E080935503809152 -:102610004A0399CF44E254E060E070E0A6CF8DE435 -:1026200060E00E949A1D81E060E00E948B1D81E0C5 -:1026300068E70E948B1D81E06EE70E948B1D81E0A0 -:1026400069E70E948B1D81E069E70E948B1D81E094 -:102650006EE70E948B1D81E068E70E948B1D11E0F0 -:102660008EE995E30E943327812F1F91089581E021 -:102670008093540370CF88EB94E060E00E94271EA3 -:1026800080914A0360CF85E894E060E00E94271EB5 -:1026900080914A0358CF81E794E060E00E94271EB2 -:1026A00080914A0350CF89E994E0ABCF8CED94E060 -:1026B00060E00E94271E1ACF1F931FB7F894E09185 -:1026C0004C03F0E0EE0FFF1FE850F0418081809353 -:1026D0004C030E948A0910924C0310924D031092F1 -:1026E000510310924E0310924F0310925003109218 -:1026F000530382E0809358031092590310925403BD -:10270000109255031092520310925D0310925C03D5 -:102710001092773510927635109295351092943547 -:1027200080E090E0FC01E858FA4C10820196883174 -:102730009105C1F711B8469A28988FE798E3A1E070 -:1027400081509040A040E1F700C0000080B18F7739 -:1027500080935E0346988FE781B9289A8091640040 -:10276000877F8093640083E48093800089E1809375 -:1027700081000E94B0090E94DE1E0E94D21E1FBF6F -:102780001F910895FF920F931F93CF93DF938C01B6 -:10279000F0905203C0917635D09177358DDF0E944D -:1027A000D21E80E060E00E949A1DFF2009F43FC025 -:1027B0008FE196E061E00E94271E80E061E00E94C8 -:1027C0009A1DC80160E044E50E94A61D8DB79EB722 -:1027D00008970FB6F8949EBF0FBE8DBFEDB7FEB73A -:1027E00031960FE513E0ADB7BEB712961C930E936A -:1027F000119786E190E09383828387EC91E0958343 -:102800008483D783C6830E94C2398DB79EB708964A -:102810000FB6F8949EBF0FBE8DBF80E065E00E94AA -:102820009A1DC80160E044E50E94A61DFFCF89E023 -:1028300096E061E00E94271E80E061E00E949A1D00 -:10284000C80160E044E50E94A61DF0CF1F93CF931E -:10285000DF930E94D21E80E060E00E949A1D84EF08 -:1028600095E060E00E94271E4A9BFECF8FEF99E61D -:10287000A8E181509040A040E1F700C000008EE93F -:1028800095E36AEC71E041E00E94342A882331F537 -:1028900062E00E949A1D85EE95E060E00E94271E8E -:1028A00080E063E00E949A1D88ED95E060E00E9460 -:1028B000271E80E065E00E949A1D87EC95E060E0AD -:1028C0000E94271E499B04C04A9B02C04C99FACF24 -:1028D0000E94D21EDF91CF911F9108958EE995E35A -:1028E00065E773E040E052E00E94C92497FD4DC0C7 -:1028F0001092BA351092B93586E195E10E94C93837 -:102900001FB7F8940E947338EC011FBF8EE995E35E -:102910000E94332780E062E00E949A1D209761F1B7 -:10292000ADB7BEB718970FB6F894BEBF0FBEADBF18 -:10293000EDB7FEB731968FE593E012969C938E9398 -:10294000119786E190E09383828387EF91E09583EE -:102950008483D783C6830E94C2398DB79EB70896F9 -:102960000FB6F8949EBF0FBE8DBF8FE593E060E079 -:1029700044E50E94A61D9DCF8FE593E067EE71E0D0 -:1029800046E150E00E94B339F0CF87ED91E0FADEE6 -:10299000AFCF80E060E00E949A1D0E94D21E80E0CE -:1029A00060E00E949A1D8AE295E060E00E94271E86 -:1029B00080E062E00E949A1D87E195E060E00E945D -:1029C000271E80E063E00E949A1D81E195E060E0AF -:1029D0000E94271E499BFECF4A9BFCCF4C9BFACFFF -:1029E00080E062E00E949A1D8DEF94E060E00E941A -:1029F000271E80E063E00E949A1D80EF94E060E073 -:102A00000E94271E8FEF99E6A8E181509040A040D8 -:102A1000E1F700C00000499B04C04A9B02C04C99EA -:102A2000FACF4A9B02C00C94D21E10CF2091B93528 -:102A30003091BA3582E02030380759F0F901EB586F -:102A4000FC4F80812F5F3F4F3093BA352093B935CB -:102A500008958EE995E365E773E040E052E00E9457 -:102A6000C92497FD0BC01092BA351092B93585B1C3 -:102A700098E0892785B920E030E0E0CF87ED91E04C -:102A800081DEF1CF909155039923E1F4E82FF0E036 -:102A9000E45DFE4FE491F0E0262F30E02E173F0773 -:102AA000B4F4AF014F5F5F4F55954795E0FD14C0FB -:102AB00031972E173F0759F06417B0F0862F8F5FBC -:102AC000841B0895262F30E02131310514F080E079 -:102AD0000895862F8F5F0895E42FF0E031972E1729 -:102AE0003F0751F780E00895842F860F0895FF92E5 -:102AF0000F931F938C01F22E0E945520882379F1A9 -:102B0000C80165E773E30E94AD1F882391F1E9ECEA -:102B1000F3E3BF2DBB0FA0E0AB58BC4F81918D9369 -:102B200085E3E537F807D1F7C80165E773E30E944D -:102B3000AD1F882311F1E5E7F3E3BF2DBB0FA0E044 -:102B4000AF5DBA4F81918D9383E3E93CF807D1F7EC -:102B5000C8010E943D201F910F91FF90089588E0C9 -:102B600092E010DEC80165E773E30E94AD1F882381 -:102B700071F68CE192E006DECACF8CE192E002DED3 -:102B8000DACF2F923F924F925F927F928F929F92D5 -:102B9000AF92BF92CF92DF92EF92FF920F931F936B -:102BA000DF93CF93CDB7DEB760970FB6F894DEBF53 -:102BB0000FBECDBF982E792E862E80915503882387 -:102BC00009F4B7C004E210E062E1462E512C80E027 -:102BD00090E020E0FF2458E1E52E46E1A42EB12C40 -:102BE0003CE2C32E32E0D32E1801122F88589A4CA3 -:102BF000DC018C9180FF35C080919035881661F1A1 -:102C0000809190352DB73EB72A5030400FB6F894DA -:102C10003EBF0FBE2DBFEDB7FEB731962FE533E0B7 -:102C2000ADB7BEB712963C932E931197B382A28292 -:102C3000D582C48286821782808711860E94C2391B -:102C40004DB75EB7465F5F4F0FB6F8945EBF0FBEDD -:102C50004DBF8FE593E096DD5E2D583109F466C0D7 -:102C6000F12E1F5F812F90E0821593050CF45AC05E -:102C7000BE2DB83109F43EC080915403882361F41D -:102C800066C0EE2DF0E0E858FA4C80818E7F80839C -:102C900080818B7F8083E394FE1498F7EDB7FEB7B5 -:102CA00038970FB6F894FEBF0FBEEDBF31960FE513 -:102CB00013E0ADB7BEB712961C930E93119786E141 -:102CC00090E09383828381E492E09583848386827B -:102CD00017820E94C239EDB7FEB738960FB6F89446 -:102CE000FEBF0FBEEDBF80E065E024D7C80160E005 -:102CF00044E52CD760960FB6F894DEBF0FBECDBF6B -:102D0000CF91DF911F910F91FF90EF90DF90CF90C7 -:102D1000BF90AF909F908F907F905F904F903F902B -:102D20002F900895183109F4A3CF60CFF12EE12E32 -:102D300098CFE62FF0E0E45DFE4FE4914E2E55244F -:102D40008201000F111F01151105A1F240CFABD672 -:102D5000D6D66B877C878D879E87FE1408F461C169 -:102D6000482D50E05A8749871A01220C331CC101B3 -:102D7000880F991F880F991F880F991F820D931D27 -:102D80009C0140E050E029833A834B835C830E2D05 -:102D9000F101E457FF4F859194919C0140E050E090 -:102DA0002D833E834F8358871E2DAF2C42C08090C9 -:102DB00091352091580330E040E050E069817A81FC -:102DC0008B819C810E940A396B017C018091BB350B -:102DD0009091BC35A091BD35B091BE35C80ED91EBD -:102DE000EA1EFB1E282D30E0429EC001439E900D3E -:102DF000529E900D1124AA2797FDA095BA2FC80EB8 -:102E0000D91EEA1EFB1EC00ED11CE11CF11C2F8531 -:102E10003889322F2227330F2B583C4F892D972D7D -:102E2000B701A6010E947520882371F10F5FA016DB -:102E300088F1402F50E0588B4F87FA01E858FA4C40 -:102E4000808180FDF3CF80915503882309F0AFCFB7 -:102E5000C090BB35D090BC35E090BD35F090BE350C -:102E6000C00ED11CE11CF11C2091580330E040E061 -:102E700050E06D817E818F8198850E940A39C60E4F -:102E8000D71EE81EF91EC3CF86E592E07BDC0F5FFC -:102E9000A01678F6E12EFA2C80915503882309F0CC -:102EA0004FC0F101E457FF4F65917491A090BB357D -:102EB000B090BC35C090BD35D090BE35AE0CB11CC5 -:102EC000C11CD11C80E090E02091580330E040E02C -:102ED00050E00E940A39A60EB71EC81ED91E0F2D3B -:102EE00010E00F5F1F4F0E191109222717FD2095C3 -:102EF000322F892D972DB601A5010E94102288231B -:102F000059F487C0F801E858FA4C80818E7F80839D -:102F100080818B7F8083E394FE14D0F10E2D10E02E -:102F2000B801762F6627770F6B587C4F892D972D28 -:102F30000E949E21882331F789E792E023DCE2CFCB -:102F40008091913590E0489E5001499EB00C589E6A -:102F5000B00C1124CC24B7FCC094DC2C8091BB3580 -:102F60009091BC35A091BD35B091BE35A80EB91E6B -:102F7000CA1EDB1EAE0CB11CC11CD11CB101660FF8 -:102F8000771F660F771F660F771F620D731D9ACF2D -:102F9000892D972D0E945122882309F43EC089E192 -:102FA00080935D0384D5ABD5ADB7BEB71C970FB684 -:102FB000F894BEBF0FBEADBFEDB7FEB731960FE5BB -:102FC00013E012961C930E93119726E130E03383A1 -:102FD00022832AE932E03583248329853A853783A1 -:102FE00026832B853C854D855E85621B730B840B88 -:102FF000950B60877187828793870E94C2394DB78E -:103000005EB7445F5F4F0FB6F8945EBF0FBE4DBF13 -:103010006ACE86E692E0B6DB7FCF88E892E0B2DB4C -:10302000BECF282D30E03A8729871901220C331CA6 -:1030300033CF2F923F924F925F926F927F928F92F7 -:103040009F92AF92BF92CF92DF92EF92FF920F9337 -:103050001F93DF93CF93CDB7DEB7CD54D0400FB6DB -:10306000F894DEBF0FBECDBF18D526DBC1D89AD6E7 -:1030700078948FE79AE1A6E081509040A040E1F774 -:1030800000C0000010D58FE79AE1A6E08150904083 -:10309000A040E1F700C00000499B05C04A9903C069 -:1030A0004C9901C015D989E189831C821C8E1BA211 -:1030B0001EA28E010F5F1F4FC80160E00E94B62A5A -:1030C000882309F49FC42FE5822E23E0922EEFD4AB -:1030D000499905C04A9903C04C9B01C05ADCC801FC -:1030E0000E949B05C8010E94AE07222433248091D0 -:1030F0005203882309F078C0F894D0904C03C09014 -:103100004E0310925103789480915303882309F061 -:103110007EC080915103882351F74B9B04C00799CF -:103120006DC0F1010995499918C080911C039091D7 -:103130001D03009771F3019790931D0380931C0367 -:10314000C8010E94AE078FEF94E3ACE0815090403D -:10315000A040E1F700C00000DCCF4A9B49C04C9979 -:10316000D8CF80914A03813009F4A3C2823009F498 -:1031700038C2809168008860809368008091680000 -:103180008460809368008091680084608093680008 -:103190008091680081608093680010924C030ED685 -:1031A00001D671D9882309F4A2CF8091540391E00C -:1031B000892790915503992309F4826082B9459A31 -:1031C000A7E8B3E11197F1F700C000004598B2E419 -:1031D000BA95F1F700C04298E1E0E0935303809183 -:1031E0005203882309F488CF8FE593E0CBDA84CFAC -:1031F00080911C0390911D0301969ECF89B180FFA1 -:1032000090CF86B180FF8DCF31998DCF8ACFED2CB5 -:10321000FF242DB73EB7285030400FB6F8943EBF7C -:103220000FBE2DBFEDB7FEB73196ADB7BEB7129644 -:103230009C928E92119786E1482E512C53824282A5 -:10324000B6EC6B2EB2E07B2E75826482F782E6824A -:103250000E94C2392DB73EB7285F3F4F0FB6F89492 -:103260003EBF0FBE2DBF88E164E064D4C40160E0BE -:1032700044E56CD4AC2CBB248DB79EB708970FB631 -:10328000F8949EBF0FBE8DBFEDB7FEB73196ADB7B8 -:10329000BEB712969C928E92119753824282ABECEB -:1032A0004A2EA2E05A2E55824482B782A6820E94FC -:1032B000C2392DB73EB7285F3F4F0FB6F8943EBFD7 -:1032C0000FBE2DBF88E364E035D4C40160E044E55F -:1032D0003DD480914D038D1509F45CC160914D037F -:1032E000C8014FDCD0924D03C0924F0380E090E0C4 -:1032F000FC01E858FA4C20812D7F2083019688310B -:103300009105B1F780915103882309F0F0CE8091A7 -:103310005003882309F030C13D2D303598F7809156 -:103320005503882309F05BC1F701E45DFE4F24914A -:1033300080915903821710F01092590386B14B996E -:1033400008C3881F8827881F8EAF2C9D902D1124BD -:1033500023969FAF2397A701440F551FCA01880FDB -:10336000991F880F991F880F991F840F951F289602 -:103370008FAF289729969FAF299730E02A9DC001EB -:103380002B9D900D3A9D900D11242C01662457FC25 -:103390006094762C27964CAE5DAE6EAE7FAE2797CE -:1033A0000E2CEF2C000CEE1CFF08000CEE1CFF1C7A -:1033B000AA0CBB1CA294B29460EFB622BA24A62237 -:1033C000BA245E2C5A285FAE852D90E084589E4F1B -:1033D00044575F4FFA01659074902B967FAE6EAEA6 -:1033E0002B972D2D2F7321962FAF2197E22FF0E0F1 -:1033F000E458FE4F34912C963FAF2C97FC01F4918A -:103400002D96FFAF2D972296DFAE22972E96CFAE48 -:103410002E972401F6B0F094FF1CFF24FF1C09F442 -:1034200013C16EAC6F1461F080E464E083D3FF20BD -:1034300009F42FC182E494E060E009D421E02EAFCA -:1034400080915D03813009F42AC18091550388235E -:1034500009F4ABC0E0905903F8946E2C772458E738 -:10346000852E55E3952E860C971CD4018C9181FDF9 -:103470008FC08C9182FD8CC08C9184608C9381E094 -:103480007894882309F441C080915503882309F07A -:10349000F7C02B966EAD7FAD2B9780915903A0900E -:1034A000BB35B090BC35C090BD35D090BE35A80EB0 -:1034B000B11CC11CD11C27968CAD9DADAEADBFAD6E -:1034C0002797A80EB91ECA1EDB1E80E090E020914F -:1034D000580330E040E050E00E940A39A60EB71EC3 -:1034E000C81ED91EE0D280917535882309F4B7C073 -:1034F000C801B601A5012E2DFADAD9D2D4018C91DA -:1035000082608C938C918B7F8C938091590388235C -:1035100001F5FF2059F085B1B8E08B2785B980917E -:103520005D03823018F0815080935D0320915C032D -:10353000275E20935C032D3708F08CC030E080912B -:103540005A0390915B03821B930B909389008093A5 -:10355000880080915503882379F122E3F22E06C07A -:103560008EE40E94850FFA9409F4BCC08091510347 -:103570008823B1F34201BBCD80E464E0DBD288E470 -:1035800094E060E064D3809151038823E1F3BACEE4 -:1035900080E076CF80915503882309F4B3CE8091E3 -:1035A0004F038C1509F09ACEADCEE09059032396C7 -:1035B0003FAD2397E30E50CFB7E3EB2EF12C0AC0BB -:1035C0008FEF0E94510F0894E108F108E114F10413 -:1035D00009F4EFC080915103882391F3CBCF22E10E -:1035E000A7CE80914B03815080934B03C80161E0CB -:1035F0000E943C2A80914B03882389F0FF249F2D51 -:10360000ADE09A9FB00111246B587E4CC80141E097 -:103610000E945A2AF39480914B03F81680F310927B -:103620001D0310921C03BED3C8010E949B05C80154 -:103630000E94AE078FEF99E6A8E181509040A0402C -:10364000E1F700C0000053CDC80122966FAD22976C -:1036500098DAE7CE10925C0320E030E070CF93015F -:10366000322F2227330F2B583C4FC801B601A5013A -:103670003CD5882309F041CF87ED91E083D83DCF39 -:1036800028969FAD289729968FAD2997692F782F77 -:1036900004CF8CE394E060E0DAD22B9A1EAE109255 -:1036A0005D0380E065E046D286E294E060E0CFD240 -:1036B000CCCEF0904B03AF2DBDE0AB9FC0011124E9 -:1036C0008B589E4C6EE173E04DE050E00E94B339A0 -:1036D000F394F0924B03C8016EE173E041E00E9465 -:1036E0005A2A9DCF9CE0F92E80915103882309F03E -:1036F00041CF0E94850FFA94B9F7EFEFFFEFF093F7 -:103700005703E09356030E94600F0E94600F0E94CF -:10371000600F80915103882309F02CCF8EEF0E9417 -:10372000850F80915103882309F024CF22968FAD15 -:1037300022970E94850F80915103882309F01ACFA8 -:103740002E968FAD2E970E94850F8091510388236E -:1037500009F010CF809159038F5F0E94850F8091EF -:103760005103882309F006CF82E00E94850FF09074 -:1037700056038091570390915103992309F0FACE93 -:103780000E94850F80915103882309F0F3CE8F2D7D -:103790000E94850FFF2408C08EE40E94850FF394D9 -:1037A000FF2DF63109F4F1C0809151038823A1F374 -:1037B000E1CE80915803823009F4E4C0F2E0FF2E9C -:1037C000E090590380915103882309F0D3CE85ED11 -:1037D0000E94510F80915103882309F0CBCE8AEAD1 -:1037E0000E94510F80915103882309F0C3CE86E9CE -:1037F0000E94510F80915103882309F0BBCE2C9673 -:103800008FAD2C970E94510F80915103882309F0AE -:10381000B1CEE0915903F0E0E458FE4F84910E944C -:10382000510F80915103882309F0A4CE2D968FADBE -:103830002D970E94510F80915103882309F09ACE51 -:10384000EF2DF0E0E458FE4F84910E94510F8091DB -:103850005103882309F08ECE2196EFAD2197EE25F6 -:103860002FADE227EF25EF73F0E0E458FE4F84918F -:103870000E94510F80915103882309F07BCE8EED79 -:103880000E94510F80915103882309F073CE8AEA78 -:103890000E94510FEAE0FE2E80915103882309F027 -:1038A00069CE8FEF0E94510FFA94B1F780915103C6 -:1038B000882309F05FCE85ED0E94510F809151035E -:1038C000882309F057CE8AEA0E94510F8091510354 -:1038D000882309F04FCE8DEA0E94510F8091510349 -:1038E000882309F047CEE0915903F0E0E458FE4FF9 -:1038F00084910E94510FC301982F8827990F8B58EC -:103900009C4F0E94AC0F80915103882309F032CE66 -:103910008EED0E94510F80915103882309F02ACE29 -:103920008AEA0E94510F80915103882309F022CE28 -:103930008FEF0E94510F22968FAD2297609159030D -:10394000A1D8809359034B9B65CD2296DFAC22977B -:1039500042014598429A10925303C8016D2D11D926 -:103960008FE79AE1A6E081509040A040E1F700C0C7 -:1039700000000E945C13C8010E949B05C8010E94C0 -:10398000AE07B5CBA2E2FA2E1BCFFF2480915103E4 -:10399000882309F0EFCD0E94850FF3942F2D2C3052 -:1039A000A9F78FEF9FEF90935703809356030E94E0 -:1039B000600F0E94600F0E94600F80915103882366 -:1039C00009F0D8CD8BEF0E94850F6301DC2CCC244D -:1039D000DD0CA5E7B3E0CA0EDB1EEE24FF240AC00F -:1039E0000E94850F0894E11CF11CF0E0EF16F2E054 -:1039F000FF06B9F1F60181916F019091510399236E -:103A000079F3B8CDADB7BEB71A970FB6F894BEBF6D -:103A10000FBEADBFEDB7FEB731969FE5892E93E09F -:103A2000992E12969C928E92119786E190E0938344 -:103A3000828382EB92E095838483898186831782D7 -:103A40008B81808711860E94C239EDB7FEB73A9606 -:103A50000FB6F894FEBF0FBEEDBFC4010E94C213A3 -:103A600036CBF090560380915703909151039923E0 -:103A700009F080CD0E94850F80915103882309F0C1 -:103A800079CD8F2D0E94850F56CF81E090E00C9468 -:103A9000770980E090E00C94770914BC83E085BD41 -:103AA00081E085BB089581E080936E0008951092B7 -:103AB0006E0008951F920F920FB60F9211248F93EC -:103AC0009F93AF93BF938091C3359091C435A091DC -:103AD000C535B091C6350196A11DB11D8093C33582 -:103AE0009093C435A093C535B093C635BF91AF91BF -:103AF0009F918F910F900FBE0F901F9018952FB729 -:103B0000F8946091C3357091C4358091C53590911A -:103B1000C6352FBF089590E59CBD1DBC882341F09C -:103B20005E9A2A986EBD0DB407FEFDCF2A9A0895BD -:103B30005E98F7CF1F93162F682F606880E0EBDF49 -:103B4000612F606480E0E7DF1F910895AF92BF921C -:103B5000CF92DF92EF92FF920F931F93CF93DF9359 -:103B6000D62EC42EE82EF92EBB248FE7A82EF701FF -:103B700001917F01002359F4DF91CF911F910F91A3 -:103B8000FF90EF90DF90CF90BF90AF900895BC145E -:103B900098F70D3609F183E0089F80011124E801B0 -:103BA000CB52DA4F09521A4FFE016491660FD110C1 -:103BB0006A2581E0B0DFB394C017D10749F4BC1483 -:103BC000B0F6DD20C1F16FE781E0A5DFB394CFCF80 -:103BD0002196BC1460F6E8CFDD2079F163E481E042 -:103BE0009ADFB394BC1408F0C2CFDD2051F16BE72B -:103BF00081E091DFB394BC1408F0B9CFDD2029F146 -:103C000067E681E088DFB394BC1408F0B0CFDD2014 -:103C1000D1F06BE781E07FDFB394BC1408F0A7CF4D -:103C2000DD2069F067E481E076DFB394BC1408F02E -:103C30009ECFDD2041F660E0C7CF6CE3D0CF68E3D4 -:103C4000F2CF64E0D5CF64E0E5CF68E1DACFCF9280 -:103C5000DF92EF92FF920F931F93CF93DF93D62EB5 -:103C60008C010F5F1F4F2FE7C22EF8013197E491AF -:103C7000EE2331F1ED3679F183E0E89FF001112474 -:103C8000EF01CB52DA4F98EDE92E95E0F92EEE0ECA -:103C9000FF1EFE016491660FD1106C2581E03BDFB1 -:103CA0002196CE15DF05A9F7DD2099F06FE781E0B9 -:103CB00032DF0F5F1F4FF8013197E491EE23D1F609 -:103CC000DF91CF911F910F91FF90EF90DF90CF90F8 -:103CD000089560E0ECCFDD2089F081E063E41BDF34 -:103CE00081E06BE718DF81E067E615DF81E06BE7D5 -:103CF00012DF81E067E40FDF6FE7D9CF81E06CE38B -:103D00000ADF81E064E007DF81E068E104DF81E051 -:103D100064E001DF81E068E3FEDE60E0C8CFEF929F -:103D2000FF920F931F93CF93DF93E82EF92EF701A5 -:103D300001917F010023E1F00D3609F183E0089F36 -:103D400080011124E801CB52DA4F08521A4FFE01CC -:103D50006491606481E0DFDE2196C017D107B9F776 -:103D600081E060E4D8DEF70101917F01002321F7B3 -:103D7000DF91CF911F910F91FF90EF90089581E017 -:103D80006EE5C9DE81E062E4C6DE81E06CE4C3DE9C -:103D900081E062E4C0DE81E06CE5BDDE81E060E4EC -:103DA000BADEC5CFCF93DF93C8EFD1E081E060E00A -:103DB000B2DE2197D9F7DF91CF9108958FEB8093F1 -:103DC000C73584E18093C83584E08093C935569A1D -:103DD000279A259A229A209A2A98289A8FE798E378 -:103DE000A1E081509040A040E1F700C00000289879 -:103DF0008FE798E3A1E081509040A040E1F700C038 -:103E00000000289A8FE798E3A1E081509040A040FD -:103E1000E1F700C0000080E090E00E94023C813F9A -:103E2000E1F080E090E061EF0E940A3C6091C735CC -:103E300081E090E00E940A3C80E061E26CDE6091EB -:103E4000C73580E068DE6091C83580E064DE80E0E0 -:103E500060E261DE80E06CE05ECE81E090E00E9496 -:103E6000023C8093C735E8CFFC014181842F90E06C -:103E70009C013595279520652CBD40FD06C081E04D -:103E8000463019F08DBD2C98089580E08DBD2C989A -:103E90000895BF92CF92DF92EF92FF920F931F93FC -:103EA000CF93DF938C016B017A0129DEEB01BB24F8 -:103EB000BA94BEBC0DB407FEFDCF8EB5F801828367 -:103EC0008F3FB1F41CDE6C1B7D0B81E06D327807F7 -:103ED00080F381E1F80180832C9A80E0DF91CF911B -:103EE0001F910F91FF90EF90DF90CF90BF900895BA -:103EF0008E3F19F08FE08083EFCFE114F104F1F0F1 -:103F00000894E108F1088FEF8EBDE114F10471F01F -:103F1000F60180E090E03FEF0DB407FEFDCF2EB537 -:103F200021933EBD01968E159F05B0F30DB407FE9B -:103F3000FDCF8EB5F601EE0DFF1D80838FEF8EBD98 -:103F40000DB407FEFDCF8EB58FEF8EBD0DB407FE0D -:103F5000FDCF8EB52C9A81E0C1CF0F931F93CF93E5 -:103F6000DF93EC018B0180DFCE01B80140E052E02D -:103F700090DFDF91CF911F910F910895FF920F93E2 -:103F80001F93CF93DF93EB01BADD8B01FF24FA94EB -:103F9000FEBC0DB407FEFDCF8EB58F3F69F0AFDDDF -:103FA000601B710B6C177D0798F380E0DF91CF9158 -:103FB0001F910F91FF90089581E0DF91CF911F91A4 -:103FC0000F91FF900895DF92EF92FF920F931F934E -:103FD000CF93DF93EC01D62E79018A0145DFCE0124 -:103FE0006CE271E0CBDF8D2D80648EBD0DB407FED9 -:103FF000FDCF28E130E0D801C701022E04C0B695FC -:10400000A795979587950A94D2F78EBD0DB407FEB4 -:10401000FDCF285030408FEF283F380761F7DD2073 -:10402000E9F08D2D883001F587E88EBD0DB407FECF -:10403000FDCF8D2D8C30D1F02FEF9FEF9EBD0DB4B5 -:1040400007FEFDCF8EB58A8387FD0AC0DF91CF9131 -:104050001F910F91FF90EF90DF90089585E9E5CFD4 -:104060002223A1F32150EACF8FEFDFCF8FEF8EBD58 -:104070000DB407FEFDCF8EB5DFCFCF93DF93EC01FC -:10408000F3DECE016CE020E030E0A9019CDF882364 -:1040900039F083E088832C9A80E0DF91CF910895F6 -:1040A0002C9A81E0DF91CF910895CF93DF93EC01BB -:1040B0009A01AB018B81833039F069E0220F331F05 -:1040C000441F551F6A95D1F7CE0162E17CDF88233A -:1040D00039F085E088832C9A80E0DF91CF910895B4 -:1040E0002C9A81E0DF91CF910895CF92DF92EF92E9 -:1040F000FF920F931F93CF93DF93EC017A018B0113 -:1041000069018B81833039F0A9E0EE0CFF1C001FA0 -:10411000111FAA95D1F7CE0161E1A801970153DFE4 -:10412000882369F084E088832C9A80E0DF91CF9126 -:104130001F910F91FF90EF90DF90CF900895CE01E7 -:10414000B60140E052E0A5DEF1CF8F929F92BF9280 -:10415000CF92DF92EF92FF920F931F93DF93CF9353 -:104160000F92CDB7DEB74C01B62EFC011382108240 -:10417000C6DC8B01249A2C9A2698259A279A249A91 -:104180002C9A85E0F401818382E58CBD1DBC8AE018 -:104190009FEF9EBD0DB407FEFDCF8150D1F7C40146 -:1041A00060E020E030E0A9010EDF782FF401828387 -:1041B0008130C9F0A4DC601B710BF7E0613D7F0723 -:1041C00070F381E0F40180832C9A80E00F90CF910E -:1041D000DF911F910F91FF90EF90DF90CF90BF90F4 -:1041E0009F908F900895C40168E02AEA31E040E092 -:1041F00050E07983E8DE798182FF1FC0F401738388 -:10420000CC24DD247601C40167E320E030E0A9017D -:10421000DADEC40169E2A7019601D5DEF4018283EA -:104220008823D9F06CDC601B710BF7E0613D7F07E0 -:1042300050F38AE0F4018083C7CF84E02FEF2EBDD6 -:104240000DB407FEFDCF9EB5F40192838150B9F7FE -:104250009A3A79F082E08083B7CF83818230B1F0DF -:104260002C9AFB2DF73070F088E1F401808380E018 -:10427000ADCF82E0F4018383C12CD12CE12CB0E4DA -:10428000FB2EC1CFF401B18281E0A0CFC4016AE36B -:1042900020E030E0A90197DE882321F088E0F401D6 -:1042A000808392CF8FEF8EBD0DB407FEFDCF8EB50C -:1042B000807C803C19F483E0F401838383E09FEFEA -:1042C0009EBD0DB407FEFDCF2EB58150C9F7C8CFF6 -:1042D000FC016EBDA42FB52F80E090E00DB407FE69 -:1042E000FDCF2C912EBD0DB407FEFDCF11962C9164 -:1042F00011972EBD0296129622E08030920771F738 -:104300000DB407FEFDCF8FEF8EBD0DB407FEFDCFC0 -:104310008FEF8EBD0DB407FEFDCF8FEF8EBD0DB4B8 -:1043200007FEFDCF8EB582838F71853029F083E142 -:1043300080832C9A80E0089581E008950F931F9365 -:10434000CF93DF93EC018B018FDDCE0168E572E046 -:1043500015DE882349F485E188832C9A80E0DF917B -:10436000CF911F910F910895CE016CEFA801B0DF9E -:10437000882389F32C9A81E0DF91CF911F910F91CF -:104380000895CF92DF92EF92FF920F931F93CF93F6 -:10439000DF93EC017A018B0169018B81833039F065 -:1043A00089E0EE0CFF1C001F111F8A95D1F7CE018A -:1043B00068E1A801970107DE882369F086E0888319 -:1043C0002C9A80E0DF91CF911F910F91FF90EF9099 -:1043D000DF90CF900895CE016EEFA60179DF88239C -:1043E00079F3CE0168E572E0C9DD882319F487E12D -:1043F0008883E6CFCE016DE020E030E0A901E3DD67 -:10440000882319F086E18883DBCF8FEF8EBD0DB452 -:1044100007FEFDCF8EB58823A9F72C9A81E0D2CF75 -:10442000AF92BF92CF92DF92EF92FF920F931F93C2 -:10443000CF93DF93EC015A016B017801890167E3A7 -:1044400020E030E0A901BFDDCE0167E1A8019701BE -:10445000BADD882379F089E088832C9A80E0DF91A7 -:10446000CF911F910F91FF90EF90DF90CF90BF9071 -:10447000AF9008958B81833039F099E0AA0CBB1C72 -:10448000CC1CDD1C9A95D1F7CE0169E1A6019501FE -:104490009ADD882319F087E08883DFCF2C9A81E0AA -:1044A000DECFCF93DF93EC01DFDCCE0168E572E075 -:1044B00065DD882359F08DEF8EBD0DB407FEFDCF6D -:1044C000CE0168E572E05ADD882339F482E1888301 -:1044D0002C9A80E0DF91CF9108952C9A81E0DF91B2 -:1044E000CF910895CF93DF93EC019C012C5F3F4F58 -:1044F000898D9A8D41E050E060E070E00E94042DCB -:104500008823D9F08D899E89AF89B88D0097A10540 -:10451000B10579F48C819D81AE81BF818D8B9E8B9D -:10452000AF8BB88F89818068898381E0DF91CF91DB -:10453000089581E0DF91CF91089580E0DF91CF91E0 -:104540000895CF92DF92EF92FF921F93CF93DF9364 -:10455000EC0189899A89AB89BC89803E2FEF92074B -:104560002FE1A20720E0B20748F080E0DF91CF9171 -:104570001F91FF90EF90DF90CF900895CE01B2DFB2 -:10458000882399F30E94D82A882379F3E98DFA8D3C -:10459000CC80DD80EE80FF808EEF9FEFAFEFBFEF2E -:1045A000C80ED91EEA1EFB1E058404C0CC0CDD1CFF -:1045B000EE1CFF1C0A94D2F786859785A089B189E5 -:1045C000C80ED91EEA1EFB1E81E08093D637C0922A -:1045D000D035D092D135E092D235F092D33580E00B -:1045E00092E0E4EDF5E3DF019C011D9221503040A3 -:1045F000E1F7E98DFA8D84818230C0F011E006C0C8 -:104600001F5FE98DFA8D8481181780F4B701A60128 -:10461000410F511D611D711D8091D4379091D53787 -:1046200024ED35E3AEDE882359F79FCF20E032E05A -:1046300040E050E0058404C0220F331F441F551F83 -:104640000A94D2F789899A89AB89BC89820F931F12 -:10465000A41FB51F898B9A8BAB8BBC8B81E086CF57 -:10466000CF93DF93EC018C859D85AE85BF8541E0BE -:10467000662309F440E0BC01CD01DAD7882381F03C -:10468000288930E0220F331F22953295307F322760 -:10469000207F32272C523A4CC901DF91CF910895E7 -:1046A00020E030E0C901DF91CF9108956F927F92B1 -:1046B0008F929F92AF92BF92CF92DF92EF92FF9232 -:1046C0000F931F93DF93CF9300D000D0CDB7DEB709 -:1046D0006C014B013A01DC015596ED90FD900D9176 -:1046E0001C915897E114F10401051105F1F05E01E8 -:1046F0000894A11CB11C10C0D801C7010196A11DCE -:10470000B11D29813A814B815C8182179307A407EF -:10471000B507F9F47C018D01F601818D928DB80108 -:10472000A7019501CAD7882339F780E00F900F9031 -:104730000F900F90CF91DF911F910F91FF90EF900D -:10474000DF90CF90BF90AF909F908F907F906F90B1 -:104750000895D60159966D917C915A97FB018789EE -:10476000803109F44CC0283F8FEF38078FEF48079E -:104770008FE05807D0F2F60185899689A789B08D18 -:104780000297A109B109FB01058404C0880F991F94 -:10479000AA1FBB1F0A94D2F7268537854089518905 -:1047A000820F931FA41FB51FF40180839183A283FE -:1047B000B383FB0186859785A089B1890197A109FB -:1047C000B1092481820F911DA11DB11DA80197017E -:1047D0002250304040405040058404C0220F331F17 -:1047E000441F551F0A94D2F7820F931FA41FB51FB1 -:1047F000F30180839183A283B38381E097CF283F25 -:10480000FFEF3F07F0E04F07F0E05F0708F0B3CF9E -:104810008CCFE82FF92F80E090E03EE209C0DB0169 -:10482000A90FB11D2C939F5F8F5F31968B3061F084 -:1048300020812032C9F3883091F7DB01A90FB11D27 -:104840003C939F5F2081EBCF690F711DFB011082AC -:1048500008951F93FB012BE030E231932150E9F7DB -:10486000A82FB92F30E017E09A2F8B2F2D912223FC -:1048700051F4FA019083818381E0FB0190819032B1 -:1048800079F01F9108952F32A1F32E3261F082E565 -:1048900097E0FC010196E491EE2351F02E17C9F741 -:1048A00080E01F9108951A30D9F338E01AE0DCCF88 -:1048B0001317B0F32132A0F32F3790F7FB01E30F6A -:1048C000F11D822F81568A3108F4205220833F5FE8 -:1048D000CBCF0F931F93CF93DF93EC018B018B8191 -:1048E000882331F4FB018789803141F08032F1F176 -:1048F00080E0DF91CF911F910F91089582E08B832B -:104900001D8A1E8A1F8A188E808D918DA0E0B0E0CE -:10491000880F991FAA1FBB1F880F991FAA1FBB1FB3 -:10492000880F991FAA1FBB1F880F991FAA1FBB1FA3 -:10493000880F991FAA1FBB1F898B9A8BAB8BBC8BCF -:104940001A8F098F81E089831C821D821E821F823B -:10495000188619861A861B861C861D861E861F864B -:10496000188ADF91CF911F910F91089583E08B8377 -:10497000F801428D538D648D758D4D8B5E8B6F8BE1 -:10498000788F9E012F5E3F4FC80124D78823C1F640 -:10499000AFCF2F923F924F925F926F927F928F9202 -:1049A0009F92AF92BF92CF92DF92EF92FF920F93BE -:1049B0001F93CF93DF938C01362FE72F2A01DC0161 -:1049C00013962C911397222329F011968C9111970D -:1049D00080FD16C02FEF3FEFC901DF91CF911F91EE -:1049E0000F91FF90EF90DF90CF90BF90AF909F908E -:1049F0008F907F906F905F904F903F902F90089591 -:104A0000E801C988DA88EB88FC88488559856A8579 -:104A10007B854201AA24BB24D701C601841B950BC8 -:104A2000A60BB70B88169906AA06BB0608F093C01A -:104A30004114510409F4BEC0832E9E2E6201A4E0ED -:104A40002A2E312C200E311E612CF2E07F2E60C008 -:104A5000FF2009F07AC0411551056105710509F083 -:104A6000ABC0E8018D899E89AF89B88D8C839D8309 -:104A7000AE83BF8346855785608971894F0D511D6F -:104A8000611D711D0297A109B109058404C0880F39 -:104A9000991FAA1FBB1F0A94D2F7480F591F6A1FFC -:104AA0007B1FE301CA19DB09CC16DD0608F4E60119 -:104AB000E2E0C030DE0709F452C0CB01BA0140E0A9 -:104AC000B7D5882309F486CF95012C523A4CC401FE -:104AD000B901AE010E949C39AE0160E070E0F801BE -:104AE00080859185A285B385480F591F6A1F7B1F5A -:104AF000D80118964D935D936D937C931B97CC1AB8 -:104B0000DD0A09F457C08C0E9D1E13962C91139745 -:104B1000EFEFAE2EE1E0BE2EA422B5222230B9F195 -:104B2000D8015996ED91FC915A97DB01CA0129E011 -:104B3000B695A795979587952A95D1F7F480FA941D -:104B4000F822A114B10409F483CFE8018C819D817E -:104B5000AE81BF818FCF2601441A550A69CF80915B -:104B6000D0359091D135A091D235B091D335481739 -:104B700059076A077B0709F4A0CF8091D437909139 -:104B8000D5379401B2DA882309F0A6CF23CF39E0D4 -:104B900076956795579547953A95D1F7E801E98D50 -:104BA000FA8D828D938DA48DB58D480F591F6A1F84 -:104BB0007B1F77CF920110CFD80114964D915D9154 -:104BC0006D917C911797CF01910177D5882309F4D6 -:104BD00001CFE801E98DFA8D8C819D81AE81BF8185 -:104BE00049CFDF93CF930F92CDB7DEB7BE016F5F92 -:104BF0007F4F41E050E0CDDE8130910539F02FEF5D -:104C00003FEFC9010F90CF91DF910895298130E0E6 -:104C1000C9010F90CF91DF910895EF92FF920F930A -:104C20001F93CF93DF93EC018B81823050F420E00F -:104C300030E0C901DF91CF911F910F91FF90EF906C -:104C40000895E884F9840A851B85CE01CADF97FDA3 -:104C5000EECF88859985AA85BB854F96A11DB11D8C -:104C600088879987AA87BB87D801C70115E0B695C1 -:104C7000A795979587951A95D1F78F70282F30E0D3 -:104C8000220F331F22953295307F3227207F322723 -:104C90002C523A4CCECF8F929F92AF92BF92CF922E -:104CA000DF92EF92FF920F931F93CF93DF93EC016C -:104CB0004A015B012B81222309F465C089899A8905 -:104CC000AB89BC8984179507A607B70708F45BC0B2 -:104CD000223009F452C081149104A104B10409F4F2 -:104CE0006AC0488559856A857B85E98DFA8D258559 -:104CF00030E0275F3F4FDB01CA010197A109B109ED -:104D0000022E04C0B695A795979587950A94D2F779 -:104D1000850174010894E108F1080109110904C032 -:104D200016950795F794E7942A95D2F7E816F906B1 -:104D30000A071B07B0F58D899E89AF89B88D8C83D2 -:104D40009D83AE83BF8384E0C82ED12CCC0EDD1EA4 -:104D50000FC04C815D816E817F81898D9A8D960116 -:104D6000ACD40894E108F10801091109882359F02D -:104D7000E114F1040105110561F788869986AA8678 -:104D8000BB8681E001C080E0DF91CF911F910F9140 -:104D9000FF90EF90DF90CF90BF90AF909F908F905B -:104DA0000895411551056105710529F2E81AF90ABE -:104DB0000A0B1B0BC8CF1C821D821E821F82188605 -:104DC00019861A861B8681E0DFCF0F931F93CF933E -:104DD000DF93EC018B81882349F0898187FD0EC028 -:104DE000E7D3DF91CF911F910F91089581E08883E0 -:104DF00080E0DF91CF911F910F910895CE0161E086 -:104E00002FDC8C01009791F3FC018081853E71F3CA -:104E10008B818230F8F08D899E89AF89B88DF80139 -:104E2000938F828FB58BA48BE091CC35F091CD35EB -:104E3000309759F0B8016A5E7F4FC80148960995CE -:104E4000F801808D918D938B828B89818F778983F7 -:104E5000AFD3C7CF89899A89AB89BC89848F958F55 -:104E6000A68FB78FD8CFCF93DF93EC01AEDF1B8235 -:104E7000DF91CF9108956F927F928F929F92AF9220 -:104E8000BF92CF92DF92EF92FF920F931F93DF9327 -:104E9000CF9300D000D0CDB7DEB77C015A016B01B3 -:104EA000DC0113968C9113978130A1F080E00F9074 -:104EB0000F900F900F90CF91DF911F910F91FF9066 -:104EC000EF90DF90CF90BF90AF909F908F907F90AA -:104ED0006F90089511968C91119781FFE7CFF7019C -:104EE00081899289A389B48984179507A607B70792 -:104EF000E8F20097A105B10529F1F70160847184FA -:104F000082849384C701B601A501C5DE882371F2AE -:104F1000A114B104C104D104B9F4D70155964D913F -:104F20005D916D917C91589759968D919C915A976E -:104F3000A3D6882309F4BACFF701158A168A178AEF -:104F4000108E40C081E0B3CFD70114964D915D9192 -:104F50006D917C91179759968D919C915A979E01CE -:104F60002F5F3F4FAAD3882309F4A0CFD7015996CA -:104F7000ED91FC915A9749815A816B817C81878997 -:104F80008031C9F1483F8FEF58078FEF68078FE0F6 -:104F90007807C0F4CF0170D6882309F487CFD701F2 -:104FA00014964D915D916D917C91179759968D91C5 -:104FB0009C915A970FEF1FEF2FEF3FE086D4882385 -:104FC00009F474CFF701A18AB28AC38AD48A818195 -:104FD00080688183C701F9DE882309F467CFB601B1 -:104FE000A5016A147B048C049D0410F4B401A30190 -:104FF000C70151DE5CCF483FBFEF5B07B0E06B07F6 -:10500000B0E07B07F8F6C6CF1F93CF93DF93EC0198 -:10501000142FE62FF0E0EE0FFF1FE295F295F07FE0 -:10502000FE27E07FFE27DF01AC52BA4C1B968C9125 -:105030001B97817149F0842F827131F01B8280E0CF -:10504000DF91CF911F9108958091D0359091D13506 -:10505000A091D235B091D3358C879D87AE87BF871D -:10506000688BEC52FA4C84899589A0E0B0E0DC01B1 -:10507000992788278D8B9E8BAF8BB88F428D538D50 -:1050800060E070E0482B592B6A2B7B2B4D8B5E8B9D -:105090006F8B788F838590E0887190700097F1F422 -:1050A000848D958DA68DB78D898B9A8BAB8BBC8BA0 -:1050B00081E08B83812F8F7089831C821D821E82E9 -:1050C0001F82188619861A861B8614FD17C015FDC7 -:1050D0001EC081E0DF91CF911F910895803191052D -:1050E00009F0ACCF9E012F5E3F4F898D9A8D72D310 -:1050F000882309F4A3CF84E08B83DCCFCE0140E08A -:1051000050E0BA01B8DE882311F780E099CF4989D1 -:105110005A896B897C89CE01BEDD92CF8F929F9296 -:10512000AF92BF92CF92DF92EF92FF920F931F93B5 -:10513000CF93DF935C01EB01C42E952E822E898DD7 -:105140009A8DD5015A969C938E935997CB0140E046 -:1051500050E0BA01A0DDDD24E884F9840A851B85CE -:1051600089899A89AB89BC89E816F9060A071B0761 -:1051700008F040C0CE0151DDFC01009709F476C073 -:10518000D801C70115E0B695A795979587951A950B -:10519000D1F7182F1F708081882391F0853E81F010 -:1051A0008C2D992DBF014BE050E00E948F39009764 -:1051B00099F687FC5BC0C501612F482D25DF57C0DC -:1051C000DD20A9F42091D0353091D1354091D235F0 -:1051D0005091D335D5011C962D933D934D935C93FF -:1051E0001F9750961C9350978081DD24D394882379 -:1051F00009F0B2CF86FE3AC081FE38C0DD2009F04A -:1052000043C08B81823091F1CE019BD9882371F10B -:10521000C4EDD5E310E07E01EC2FFF2D80E2DF012D -:105220001D928A95E9F7DE018C2D992DFC018BE00A -:1052300001900D928150E1F7E091CC35F091CD35A0 -:10524000309761F1BE01625F7F4FCE0140960995B4 -:10525000888999892E853F859B8B8A8B998F888F2A -:105260003F8B2E8BA5D1882309F0A5CF80E0DF915D -:10527000CF911F910F91FF90EF90DF90CF90BF9053 -:10528000AF909F908F900895F5011089C50161E05E -:10529000E7D9EC01009709F0BECFE8CF81E298E2B0 -:1052A000998B888B80E098E09F878E8720E038E09C -:1052B00081E298E2D1CF2F923F924F925F926F920C -:1052C0007F928F929F92AF92BF92CF92DF92EF9296 -:1052D000FF920F931F93DF93CF93CDB7DEB7C454E4 -:1052E000D0400FB6F894DEBF0FBECDBF2C013B01FE -:1052F0008E010E5B1F4FD80111965C934E9325963D -:105300002FAF25971C861F861FA21AA6611571054F -:1053100009F45FC0FC018381882309F05AC0CA01E7 -:10532000DA012C912F3209F470C073013CE0832E16 -:10533000912C8C0E9D1E64015E010894A11CB11C71 -:1053400027E2222E312C2C0E3D1EB501A80181DA58 -:10535000882369F1D801ED91FC91119780818F32FA -:1053600041F43196D8011196FC93EE9381918F32DE -:10537000C9F3882309F46FC0C601B701A50121E074 -:10538000CDDE8823A1F0E614F70421F0C7011DDD6E -:10539000F7011382C814D904C9F076016401D80159 -:1053A0008D919C91B501A80154DA882399F600E00B -:1053B0008AA5882321F0CE01879607DD1AA68F855E -:1053C000882341F0CE010C9600DD04C06101740118 -:1053D000E6CF00E0802FCC5BDF4F0FB6F894DEBF46 -:1053E0000FBECDBFCF91DF911F910F91FF90EF9036 -:1053F000DF90CF90BF90AF909F908F907F906F90F5 -:105400005F904F903F902F9008959A012F5F3F4FEC -:10541000C901F80131832083D9014C912F5F3F4F9F -:105420004F32B1F3F30123812250223008F47DCFB3 -:1054300087E2E82EF12CEC0EFD1ED30159966D91FA -:105440007C915A97C70145DA882309F4B0CFF80157 -:10545000808191816BCFC201B701A50125962FAD47 -:1054600025975CDE082FA4CFFB01242F6091CA355D -:105470007091CB35AF011FCF0F931F93CF93DF9365 -:10548000EC01662399F08C010E5D1F4F1093CB3514 -:105490000093CA35C801E7DCBE016C5F7F4FC801CD -:1054A00018DADF91CF911F910F9108958C010E5D55 -:1054B0001F4FF0CFDF92EF92FF920F931F93DF9376 -:1054C000CF93CDB7DEB76C970FB6F894DEBF0FBEA3 -:1054D000CDBFFB01D42E19821C8220812F3229F1ED -:1054E00022E2E22EF12CE80EF91E8E010F5F1F4F13 -:1054F000C801B701AF0121E0DEDE8823F1F08C8125 -:10550000823070F1D701F8018BE101900D9281504A -:10551000E1F7DD2021F0F092CB35E092CA3521E0B1 -:10552000C8012C8FA0DC2C8D0CC021812223C1F658 -:10553000642FA2DF282F8C8102C08C8120E0882379 -:1055400089F4822F6C960FB6F894DEBF0FBECDBFE4 -:10555000CF91DF911F910F91FF90EF90DF90089511 -:1055600020E0EDCF8E010F5F1F4FDACF0F931F9317 -:10557000CF93DF938C010E94A520882331F480E033 -:10558000DF91CF911F910F910895E8012496CE01EC -:10559000B80141E0CDD3882321F0C80161E06CDF80 -:1055A000EFCFCE01B80140E0C3D3882341F3F5CF5C -:1055B0008091D637882311F481E008954091D03549 -:1055C0005091D1356091D2357091D3358091D437D7 -:1055D0009091D53724ED35E30E94C121882321F134 -:1055E0004091D7375091D8376091D9377091DA37D9 -:1055F000411551056105710521F41092D63781E0FE -:1056000008958091D4379091D53724ED35E30E94E9 -:10561000C121882359F01092D7371092D8371092B1 -:10562000D9371092DA37E9CF80E0089580E0089505 -:10563000DF92EF92FF920F931F937B018C01D42E88 -:105640008091D0359091D135A091D235B091D3359C -:105650008E159F05A007B107F1F0AADF882339F462 -:1056600080E01F910F91FF90EF90DF90089580915F -:10567000D4379091D537B801A70124ED35E30E94C6 -:105680007520882369F3E092D035F092D1350093EC -:10569000D2351093D335DD2049F081E08093D637A1 -:1056A0001F910F91FF90EF90DF90089581E01F917F -:1056B0000F91FF90EF90DF900895CF92DF92EF92DD -:1056C000FF920F931F93CF93DF93EC017A018B012D -:1056D000690189859A85AB85BC850196A11DB11D9F -:1056E00084179507A607B70730F0EF89E03169F016 -:1056F000E03209F445C080E0DF91CF911F910F9116 -:10570000FF90EF90DF90CF9008959927872F762F05 -:10571000652F2B893C894D895E89620F731F841F19 -:10572000951F2091D0353091D1354091D23550918F -:10573000D335621773078407950729F040E078DFB7 -:105740008823C9F2EF89E03169F18FE790E0A0E0AA -:10575000B0E0E822F9220A231B23F701EE0FFF1F16 -:10576000EE0FFF1FEC52FA4C80819181A281B38130 -:10577000BF70F60180839183A283B38381E0BCCFA5 -:10578000CB01BA0127E096958795779567952A957D -:10579000D1F72B893C894D895E89620F731F841F65 -:1057A000951FBFCF8FEF90E0A0E0B0E0E822F92294 -:1057B0000A231B23F701EE0FFF1FEC52FA4C8081E6 -:1057C0009181A0E0B0E0F60180839183A283B3834E -:1057D00081E092CF4F925F926F927F928F929F92D1 -:1057E000AF92BF92CF92DF92EF92FF920F931F93EF -:1057F000DF93CF9300D000D0CDB7DEB78C014983C3 -:105800005A836B837C832901842F952FA62FB72F72 -:10581000AC01BD01CC24DD2476015E010894A11CFD -:10582000B11C612CE2E07E2E812C912CC8019501E7 -:1058300044DF882309F447C0D401C301F80105847B -:1058400004C0880F991FAA1FBB1F0A94D2F7C80E65 -:10585000D91EEA1EFB1E49815A816B817C81878992 -:10586000803119F1483F8FEF58078FEF68078FE0BD -:105870007807E0F2F201C082D182E282F38281E015 -:105880000F900F900F900F90CF91DF911F910F917C -:10589000FF90EF90DF90CF90BF90AF909F908F9050 -:1058A0007F906F905F904F900895483FFFEF5F07A4 -:1058B000F0E06F07F0E07F07E8F6C8019501FDDE34 -:1058C000882309F0B9CF80E0DBCF4F925F926F92CF -:1058D0007F928F929F92AF92BF92CF92DF92EF9280 -:1058E000FF920F931F93CF93DF93EC016A017B012B -:1058F00028013901423051056105710590F0898513 -:105900009A85AB85BC850196A11DB11D84179507AD -:10591000A607B70730F08F89803109F456C080326E -:1059200091F080E0DF91CF911F910F91FF90EF9068 -:10593000DF90CF90BF90AF909F908F907F906F90AF -:105940005F904F9008954A015B0117E0B694A794C9 -:10595000979487941A95D1F78B899C89AD89BE89D4 -:10596000880E991EAA1EBB1EC501B40141E060DE6F -:105970008823B9F28F898031A9F18FE790E0A0E008 -:10598000B0E0C822D922EA22FB22F601EE0FFF1F67 -:10599000EE0FFF1FEC52FA4C4082518262827382FA -:1059A0008A89823078F18D819E81AF81B885880D9A -:1059B000991DAA1DBB1D8093D7379093D837A0930C -:1059C000D937B093DA3781E0ADCF852E962EA72E4A -:1059D000BB248B899C89AD89BE89880E991EAA1E1D -:1059E000BB1EC2CF8FEF90E0A0E0B0E0C822D9226A -:1059F000EA22FB22F601EE0FFF1FEC52FA4C518215 -:105A00004082CECF81E08ECF2F923F924F925F9215 -:105A10006F927F928F929F92AF92BF92CF92DF92BE -:105A2000EF92FF920F931F93DF93CF93CDB7DEB723 -:105A300067970FB6F894DEBF0FBECDBF1C01498734 -:105A40005A876B877C873E872D87FC0181859285ED -:105A5000A385B4859C01AD012F5F3F4F4F4F5F4F32 -:105A60002D833E834F835887ED85FE85408051808E -:105A700062807380411451046104710409F4BEC052 -:105A80000894411C511C611C711C1F860097A105C4 -:105A9000B10509F454C0D301C201CC24DD24760140 -:105AA0008E010F5F1F4F4C8A5D8A6E8A7F8A2EC0DF -:105AB0004C015D01C101B501A4019801FEDD8823FF -:105AC00009F43DC089819A81AB81BC810097A10511 -:105AD000B10509F44EC0A50194012F5F3F4F4F4F10 -:105AE0005F4F2C8B3D8B4E8B5F8BDA01C901089485 -:105AF000C11CD11CE11CF11CF101218532854385BB -:105B00005485C216D306E406F506C8F44D805E80BF -:105B10006F807884481659066A067B0648F682E04C -:105B2000882E912CA12CB12C8C8A9D8AAE8ABF8A9A -:105B3000C101B501A4019801C0DD882319F680E0F8 -:105B400067960FB6F894DEBF0FBECDBFCF91DF9141 -:105B50001F910F91FF90EF90DF90CF90BF90AF908B -:105B60009F908F907F906F905F904F903F902F907D -:105B70000895D501C4010196A11DB11D2C013D015F -:105B80002C893D894E895F89421A530A640A750A35 -:105B900029853A854B855C85421653066406750651 -:105BA00009F0A5CF4C885D886E887F88C101B5015A -:105BB000A4010FEF1FEF2FEF3FE087DE882309F4EA -:105BC000BECF481459046A047B0458F5950184013A -:105BD00007C0970186014C145D046E047F0408F52C -:105BE000680179010894C108D108E108F108C101F0 -:105BF000B701A6016ADE882361F7A1CFF1014080D9 -:105C0000518062807380F1E0FF8729853A854B855A -:105C10005C85213031054105510509F437CF1F86D8 -:105C200035CFAD85BE854D915D916D917C9113977A -:105C30004115510561057105C1F4ED85FE85408270 -:105C4000518262827382FF85FF2369F00894411CB0 -:105C5000511C611C711CD1014D925D926D927C9220 -:105C6000139781E06DCF81E06BCFC1019301820179 -:105C70002CDE882311F763CFAF92BF92CF92DF92D1 -:105C8000EF92FF920F931F93DF93CF9300D000D03A -:105C9000CDB7DEB76C017A018B0182E090E0A0E025 -:105CA000B0E0F60180839183A283B3835E01089400 -:105CB000A11CB11CC601B801A7019501FEDC882317 -:105CC00039F1C601B801A70100E010E09801FDDD3F -:105CD0008823F1F0E980FA800B811C81F601878925 -:105CE000803159F088EFE8168FEFF8068FEF08073C -:105CF0008FE01807F8F281E00CC0F8EFEF16FFEF25 -:105D0000FF06F0E00F07F0E01F07A0F281E001C0FE -:105D100080E00F900F900F900F90CF91DF911F9127 -:105D20000F91FF90EF90DF90CF90BF90AF900895CC -:105D30006F927F928F929F92AF92BF92DF92EF927B -:105D4000FF920F931F93CF93DF93EC01142F709367 -:105D5000D5376093D4371F8A82E090E0A0E0B0E0AE -:105D600088839983AA83BB831092D6371092D73742 -:105D70001092D8371092D9371092DA378FEF9FEF01 -:105D8000DC018093D0359093D135A093D235B09378 -:105D9000D335442309F444C0453078F080E0DF91E6 -:105DA000CF911F910F91FF90EF90DF90BF90AF9038 -:105DB0009F908F907F906F90089560E070E0CB018E -:105DC00040E036DC882351F3212F30E022953295D4 -:105DD000307F3227207F32272C533A4CF901E2548E -:105DE000FE4F808190E08F7790700097B9F6F901AF -:105DF000E653FE4F80819181A281B3818436910563 -:105E0000A105B10558F22A533E4FF901E080F18017 -:105E100002811381E114F1040105110521F4BECFC3 -:105E2000EE24FF248701C801B70140E001DC88238C -:105E300009F4B4CF8091DF359091E035F2E0803005 -:105E40009F0709F0ABCF2091E435222309F4A6CFB8 -:105E50008091E2359091E335009709F49FCF6091EE -:105E6000E135662309F49ACF2A8B6C831D8670E096 -:105E700080E090E041E050E008C0282F2F5F2D87A0 -:105E800001968930910509F489CFD82E9A01082E00 -:105E900002C0220F331F0A94E2F72617370769F76B -:105EA0006091EA357091EB356115710509F47FC099 -:105EB00080E090E06D837E838F8398878090E235C9 -:105EC0009090E335AA24BB248E0C9F1CA01EB11E0B -:105ED0008B8A9C8AAD8ABE8A6090E5357090E635E3 -:105EE000798E688E2091E43530E040E050E00E94E9 -:105EF0000A39680D791D8A1D9B1D6A8F7B8F8C8FD7 -:105F00009D8F9301220F331F22953295307F3227C8 -:105F1000207F322721503E4F232F3327269540E004 -:105F200050E0260F371F481F591F2E873F87488B89 -:105F3000598B8091E7359091E835009709F440C07E -:105F4000A0E0B0E0E21AF30A040B150BE80EF91E0C -:105F50000A1F1B1F04C016950795F794E794DA945F -:105F6000D2F7E986FA860B871C8725EFE2162FE029 -:105F7000F20620E0020720E0120758F185EFE8164C -:105F80008FEFF80680E0080780E0180730F1809175 -:105F9000003690910136A0910236B09103368A8F77 -:105FA0009B8FAC8FBD8F80E28F8B81E0F8CE6091AC -:105FB000F8357091F9358091FA359091FB357ACFAB -:105FC0008091F4359091F535A091F635B091F73583 -:105FD000B9CF8CE08F8B80E0E2CE80E18F8B81E0C7 -:105FE000DECECF93DF93DC01CD91DC9111971C16AF -:105FF0001D06DCF41296E0E0F0E020E030E0A901BC -:10600000542F432F322F22276D9170E080E090E0D3 -:10601000262B372B482B592B3196EC17FD0781F790 -:10602000B901CA01DF91CF91089520E030E0A901C4 -:10603000F7CFCF93DF93FB01DC012D913C91B901A8 -:106040006E5F7F4FEC01C60FD71FE60FF71FD90118 -:106050001196A40FB51F2115310599F0215030403C -:106060008A9192914115510519F06C9186239623DE -:106070001197891781F320E030E0C901DF91CF91BA -:10608000089521E030E0C901DF91CF910895CF93C9 -:10609000DF93FB0120813181DC012D933C93A081B2 -:1060A000B181109701F1BD01615070401296EA0F65 -:1060B000FB1FEA01CA0FDB1FA80FB91F80E09A91EE -:1060C000229130E0290F311D280F311D81E02F3F33 -:1060D000310509F008F480E02E93615070409FEF85 -:1060E0006F3F790761F7DF91CF910895EF92FF92AB -:1060F0000F931F93CF93DF938B01FC017183608318 -:106100006115710581F022E0E22EF12CE80EF91EF6 -:10611000C0E0D0E0C7018C0F9D1F0E94CE382196B1 -:10612000C017D107B9F7DF91CF911F910F91FF9061 -:10613000EF90089524E030E0FC013783268384E06B -:1061400090E0089521E0FC01208380E090E0089534 -:10615000EF92FF920F931F93DF93CF930F92CDB7E0 -:10616000DEB77C018E010F5F1F4FC8010E94CE3841 -:1061700089818823D1F7F7011782168280E090E0A9 -:106180000F90CF91DF911F910F91FF90EF900895A5 -:106190000F931F93DF93CF930F92CDB7DEB78C0190 -:1061A000CE010196FBD78981823070F085E090E0C6 -:1061B000F8019783868325E030E0C9010F90CF91E5 -:1061C000DF911F910F910895F8019181933141F072 -:1061D000882369F481E0F801828720E030E0EDCF88 -:1061E000882359F481E0818720E030E0E6CF86E023 -:1061F000F801828720E030E0E0CF8DE0F801818770 -:1062000020E030E0DACF0B96C9D780E090E0089527 -:10621000CF93DF93EC016C897D898E559F4F66DFAC -:106220006C897D89CE018B539F4F60DF80E090E0C9 -:10623000DF91CF910895FC016489758981589F4F42 -:1062400055DF80E090E008950F931F93CF93DF9385 -:106250008C01EC016696CE0164E070E047DFCE0170 -:10626000C0DEF801648775878687978780E090E0B5 -:10627000DF91CF911F910F9108950F931F93CF93AB -:10628000DF938C01EC016696CE0164E070E02EDFB6 -:10629000CE01A7DEF801608B718B828B938B695FD7 -:1062A0007F4F8F4F9F4F28E030E040E050E00E944A -:1062B0005F39F801358B248B2132310564F086E09B -:1062C00090E09783868326E030E0C901DF91CF918B -:1062D0001F910F91089520E030E0C901DF91CF9127 -:1062E0001F910F910895BC0181E090E02BD780E0D1 -:1062F00090E060E070E026D780E090E061E070E040 -:1063000021C74F925F926F927F928F929F92AF922E -:10631000BF92CF92DF92EF92FF920F931F93CF9392 -:10632000DF93EC01F62E662309F4A4C0888186175A -:1063300009F4EEC06730C1F06E30C1F48D30B1F0B9 -:1063400005E010E0C801DF91CF911F910F91FF9000 -:10635000EF90DF90CF90BF90AF909F908F907F9005 -:106360006F905F904F900895863051F700E010E0F5 -:10637000A8E0AA2EFCE0CF2EEEE06E2E7FE0B72E36 -:1063800062E0E62E992493945AE0752E45E0D42ECF -:1063900037E0832E23E0422E99E0592EF81691F231 -:1063A000873009F495C08830A8F4833009F453C0CD -:1063B000843008F03CC08130A1F1823008F454C030 -:1063C0008F2D893008F49EC081E090E08CDF5882E8 -:1063D0008881E4CF8B3059F08C3078F4893009F41F -:1063E00067C08A3008F47DC09F2D9B3089F081E022 -:1063F00090E079DFC8828881D1CF8D3009F452C016 -:106400008D3000F18E3009F075C09F2D9B30E9F47E -:1064100080E090E068DFF8828881C0CF8F2D8130E6 -:1064200019F181E090E05FDFE8828881B7CF8530A5 -:1064300009F444C0863090F081E090E054DF888217 -:106440008881ACCF8F2D8D3019F381E090E04BDF48 -:10645000B8828881A3CF9F2D9430D1F281E090E063 -:1064600042DFD88288819ACF80E090E03CDF98823A -:10647000888194CF81E090E036DF00E010E080E09A -:1064800090E060E070E05ED680E090E061E070E077 -:1064900059D60F5F1F4F0530110589F7188200E0AC -:1064A00010E050CF81E090E01EDF6882888176CFD7 -:1064B00080E090E018DF7882888170CF8F2D863061 -:1064C00009F4A6CF81E090E00EDFA882888166CF34 -:1064D0009F2D943009F49CCF81E090E004DFA882E6 -:1064E000F5CF8F2D813009F493CF81E090E0FBDE72 -:1064F000E8829BCF8F3009F491CFF88205E010E05D -:1065000088814CCF80E090E0EEDE4882888146CFE3 -:10651000863049F08D3009F029CF81E090E0E3DE4C -:106520008EE0888323CF81E090E0DDDE87E0888302 -:106530001DCFCF92DF92EF92FF920F931F93CF93D5 -:10654000DF93EC018C010A5E1F4FC80161E070E02F -:10655000CDDDC88CC80161E070E0C8DDD88CC80111 -:1065600064E070E0C3DDC8013CDD7B018C018885FF -:106570008C1521F0CE0108966C2DC3DEC801B70141 -:1065800023D688858D1521F0CE0108966D2DB9DEB4 -:1065900080E090E0DF91CF911F910F91FF90EF90FD -:1065A000DF90CF9008950F931F93DF93CF930F92B7 -:1065B000CDB7DEB78C01CE010196F0D5C8010896A3 -:1065C00069819FDE9C01009719F0F801978386830B -:1065D000C9010F90CF91DF911F910F9108954F92B4 -:1065E0005F926F927F928F929F92AF92BF92CF9263 -:1065F000DF92EF92FF920F931F93CF93DF935B0194 -:106600006C01FA0138012115310509F481C080813E -:106610009181D90111969C938E93808191818C01F7 -:106620000E5F1F4F020F131FA114B104C104D10448 -:1066300009F45DC022E0422E512C480E591E4E0E28 -:106640005F1E0CC00115110519F0D8019E928D0135 -:10665000A114B104C104D10409F449C0F20182902B -:106660002F01EE24FF2499240894A108B108C10841 -:10667000D1086114710429F0A114B104C104D1043A -:1066800081F1C82DD0E0BE016170707082E090E0B1 -:1066900059D580E090E060E070E054D50115110517 -:1066A00049F08ED590E00E2C02C0880F991F0A94F5 -:1066B000E2F7982A80E090E061E070E043D5A11411 -:1066C000B104C104D10409F4BDCF0894E11CF11C4C -:1066D000F8E0EF16F10409F4B5CFD595C7958C2EE7 -:1066E000C3CF81E090E061E070E02CD5CACFDF91AC -:1066F000CF911F910F91FF90EF90DF90CF90BF90BF -:10670000AF909F908F907F906F905F904F90089583 -:106710008081918100E010E087CF2F923F924F92CD -:106720005F926F927F928F929F92AF92BF92CF9221 -:10673000DF92EF92FF920F931F93DF93CF93CDB72A -:10674000DEB728970FB6F894DEBF0FBECDBF3C0171 -:10675000962E29833A834B835C831E830D83170116 -:106760002601B886AF82A9A051E0C52ED12C6815AC -:1067700009F487C029813A814B815C81211531055B -:106780004105510529F58D8D9E8DAF8DB8A10097DE -:10679000A105B10509F097C020E030E0C9012896B5 -:1067A0000FB6F894DEBF0FBECDBFCF91DF911F9122 -:1067B0000F91FF90EF90DF90CF90BF90AF909F90A0 -:1067C0008F907F906F905F904F903F902F900895A3 -:1067D000BB24EE24FF24C301692D93DD69817A81F6 -:1067E0008B819C814D815E8191018601F8DE41148F -:1067F000510461F0C201B1014F8158851ADC41E0BA -:10680000E42EF12C009711F0EE24FF24C114D104E2 -:10681000E9F0D3018C918F5F8C93E114F10459F06E -:106820002D8D3E8D4F8D58A1211531054105510506 -:1068300011F0BA1448F1C301682D63DD8D8D9E8D72 -:10684000AF8DB8A10097A105B10591F4E114F10451 -:1068500009F4A2CFB3948B2D81508A1508F4BBCFD5 -:10686000AA2019F0AB1408F439C022E030E096CF2A -:10687000C30161E046DD6D8D7E8D8F8D98A1A4D41E -:10688000E5CFCC24DD2476CFC30166E03ADDC30139 -:1068900064E037DD8D8D9E8DAF8DB8A1B595A79540 -:1068A00097958795B595A795979587952D8D3E8D4D -:1068B0004F8D58A1280F391F4A1F5B1F2D8F3E8F08 -:1068C0004F8F58A3BBCFC30161E01BDD6D8D7E8D63 -:1068D0008F8D98A179D420E030E060CF23E030E0C4 -:1068E0005DCF8F92AF92BF92CF92DF92EF92FF92E5 -:1068F0000F931F93CF93DF93EC018C010A5E1F4F20 -:106900006C897D89C801F2DB00D000D00F92288904 -:1069100039894A895B89ECE5EE2EF12CEC0EFD1EDF -:1069200079E3C72ED12CCC0EDD1E6FE7A62EB12C3D -:10693000AC0EBD1E8C859D85AE85BF85EDB7FEB7BF -:1069400081839283A383B4838B858583CE0108964C -:1069500064E08A84E2DE9C010F900F900F900F900C -:106960000F90009711F09F838E83C901DF91CF9123 -:106970001F910F91FF90EF90DF90CF90BF90AF905D -:106980008F9008958F92AF92BF92CF92DF92EF9245 -:10699000FF920F931F93CF93DF93EC018C010A5E5C -:1069A0001F4FC80162E070E0A1DBC8011ADB6B0178 -:1069B0007C01695F7F4F8F4F9F4F28E030E040E0C0 -:1069C00050E07DD4213231058CF026E030E03F8369 -:1069D0002E83C901DF91CF911F910F91FF90EF900E -:1069E000DF90CF90BF90AF908F900895C801B9010C -:1069F0007DDB00D000D00F928C859D85AE85BF8554 -:106A0000EDB7FEB781839283A383B4831582CE0151 -:106A100008966BE0A7019601EE24FF24CC24DD2428 -:106A2000AA24BB24898479DE9C010F900F900F90DB -:106A30000F900F90009769F2CACF6F927F928F925A -:106A4000AF92BF92CF92DF92EF92FF920F931F937C -:106A5000DF93CF930F92CDB7DEB73C01CE01019605 -:106A60009DD383010A5E1F4F298130E040E050E052 -:106A7000295F3F4F4F4F5F4FF3E05595479537954F -:106A80002795FA95D1F7C801B90130DB00D000D0C5 -:106A90000F92298130E040E050E0F3018485958534 -:106AA000A685B785EDB7FEB781839283A383B483B0 -:106AB0001582C30108966BE0EE24FF24CC24DD246C -:106AC000AA24BB24F301818428DE9C010F900F903F -:106AD0000F900F900F90009719F0F3019783868322 -:106AE000C9010F90CF91DF911F910F91FF90EF900F -:106AF000DF90CF90BF90AF908F907F906F90089570 -:106B00002F923F924F925F926F927F928F92AF92AD -:106B1000BF92CF92DF92EF92FF920F931F93DF937A -:106B2000CF9300D0CDB7DEB79A8389831A012B01AA -:106B30003901C801B901DADAC114D10419F0C6016A -:106B4000B301D4DA00D000D00F928E899F89A88D2E -:106B5000B98DEDB7FEB781839283A383B4838A8D09 -:106B6000858389819A8164E0A2019101D6DD0F902D -:106B70000F900F900F900F900F900F90CF91DF918B -:106B80001F910F91FF90EF90DF90CF90BF90AF904B -:106B90008F907F906F905F904F903F902F900895CF -:106BA0008F92AF92BF92CF92DF92EF92FF920F93AC -:106BB0001F93CF93DF93EC0189818131D9F114E0E8 -:106BC000812E00D000D00F92488959896A897B892B -:106BD0002C893D898E010A5E1F4FBCE5EB2EF12CFE -:106BE000EC0EFD1EA9E3CA2ED12CCC0EDD1EEDB796 -:106BF000FEB711821282138214821582CE0108968A -:106C0000AA24BB247DDF9C010F900F900F900F9062 -:106C10000F90009711F09F838E83C901DF91CF9170 -:106C20001F910F91FF90EF90DF90CF90BF90AF90AA -:106C30008F9008958A84C5CF8F92AF92BF92CF92E2 -:106C4000DF92EF92FF920F931F93CF93DF93EC01AC -:106C500089818E30A9F104E0802E00D000D00F92FF -:106C6000488959896A897B892C893D898E010A5E08 -:106C70001F4FEDB7FEB71182128213821482158264 -:106C8000CE010896EE24FF24CC24DD24AA24BB24C4 -:106C900037DF9C010F900F900F900F900F9000978F -:106CA00011F09F838E83C901DF91CF911F910F91C6 -:106CB000FF90EF90DF90CF90BF90AF908F900895AE -:106CC0008A84CBCF8F92AF92BF92CF92DF92EF9216 -:106CD000FF920F931F93CF93DF93EC0100D000D06E -:106CE0000F92488959896A897B892C893D898C0151 -:106CF0000A5E1F4FECE5EE2EF12CE80EF91E99E32B -:106D0000C92ED12CCC0EDD1E8FE7A82EB12CAC0ED7 -:106D1000BD1E8C859D85AE85BF85EDB7FEB7818391 -:106D20009283A383B4838B858583CE0108968A845E -:106D3000E7DE9C010F900F900F900F900F9000973F -:106D400011F09F838E83C901DF91CF911F910F9125 -:106D5000FF90EF90DF90CF90BF90AF908F9008950D -:106D6000CF92DF92EF92FF920F931F93CF93DF9317 -:106D70008C016B017901B8018AD9E601288139813A -:106D8000F701A081B181AD014150504057FD38C09D -:106D9000FD013296EE0DFF1D1196A00FB11F60E0B0 -:106DA00010E08291882329F1EC9001E00AC0762F4F -:106DB000660F7123B1F0E02A959587958823C1F07D -:106DC000000F90E080FFF8CF662389F72150304014 -:106DD000B601620F731FEB011A8162E071E071234B -:106DE00051F7702F7095E72295958795882341F785 -:106DF000EC924150504011978FEF4F3F580789F662 -:106E0000DF91CF911F910F91FF90EF90DF90CF9086 -:106E100008952F923F924F925F926F927F928F923E -:106E20009F92AF92BF92CF92DF92EF92FF920F9319 -:106E30001F93DF93CF93CDB7DEB761970FB6F8946A -:106E4000DEBF0FBECDBF3C01B6E14B2E512C480E2C -:106E5000591EFC0164897589C20148D9C30108968D -:106E60009D838C83F301E45AFF4FFF83EE83C301BC -:106E7000C99699878887AFE72A2E312C260C371CB4 -:106E800000D000D00F92F3012089318942895389C3 -:106E900084859585A685B785EDB7FEB781839283F6 -:106EA000A383B483F3018385EDB7FEB785838C811B -:106EB0009D8164E08201EE80FF80C884D984510105 -:106EC000F30182842ADC9B838A830F900F900F90BA -:106ED0000F900F90009709F087C0C3018B539F4F0D -:106EE0009D878C87FC0140815181141615060CF09A -:106EF0009DC0E0E0F0E060E000E010E0E60DF71D8E -:106F0000E953FF4F8081882351F090E09C0121706C -:106F10003070020F131F959587958823B1F76F5F27 -:106F2000E62FF0E0E417F5074CF3CE01019636D1D9 -:106F3000222717FD2095322F095F1F4F2F4F3F4FFC -:106F4000E3E03595279517950795EA95D1F71F87C3 -:106F50000E879924C30188519F4F9B878A87F3012D -:106F6000EE55FF4FF98BE88B8981981608F043C0E6 -:106F70008A859B856E857F85B9D8C2016A857B85A8 -:106F8000488959892C853D85EBDE00D000D00F92D1 -:106F9000F301208931894289538984859585A685A5 -:106FA000B785EDB7FEB781839283A383B483F301E2 -:106FB0008385EDB7FEB785838C819D8164E0820176 -:106FC000EE80FF80C884D9845101F3018284A5DB5F -:106FD0000F900F900F900F900F90009739F49394AB -:106FE0008981981640F4C4CF8A819B81F3019783ED -:106FF00086839B838A838A819B8161960FB6F894EE -:10700000DEBF0FBECDBFCF91DF911F910F91FF90DB -:10701000EF90DF90CF90BF90AF909F908F907F9038 -:107020006F905F904F903F902F90089500E010E098 -:107030007CCFCF93DF93EC01188219821A821B82D6 -:107040001C821D821F821E821B86188681E0898712 -:107050008A87188A198A1A8A1B8A1D8A1C8A1C86A2 -:107060001D861E861F86CE01089660E04AD98E8353 -:107070009F83DF91CF910895CF93DF93EC012E8111 -:107080003F812115310519F48881882321F0C90138 -:10709000DF91CF910895CE01019680D08A819B81A6 -:1070A000AC81BD810196A11DB11D8A839B83AC83F8 -:1070B000BD83E981E83150F084E090E09F838E83C6 -:1070C00024E030E0C901DF91CF910895F0E0EE0FA8 -:1070D000FF1FE851FD4F0190F081E02DCE01099591 -:1070E0002E813F81D4CF0F931F93DF93CF93CDB7E2 -:1070F000DEB7CB50D1400FB6F894DEBF0FBECDBF88 -:107100008E010F5F1F4FC80194DF2F813885211535 -:10711000310569F0C901C55FDE4F0FB6F894DEBFD7 -:107120000FBECDBFCF91DF911F910F91089589813F -:10713000882381F7C801A0DF2F813885211531050B -:10714000B1F3E8CF8130910551F08230910561F0C3 -:10715000009721F46115710571F442980895611545 -:10716000710539F0439A08956115710531F0459A1A -:10717000089543980895429A08954598089580E0A7 -:1071800090E060E070E0DEDF80E090E061E070E0E1 -:10719000D9CF9093DC378093DB370895CF93DF937B -:1071A000EC01E091DB37F091DC37309729F009955D -:1071B0008883DF91CF9108951882DF91CF91089550 -:1071C00081E0349B80E00895AF92BF92CF92DF922E -:1071D000EF92FF920F931F935B016C011616170637 -:1071E0001806190674F4EE24FF248701C8DF0894FA -:1071F000E11CF11C011D111DEA14FB040C051D0509 -:10720000ACF31F910F91FF90EF90DF90CF90BF9064 -:10721000AF900895629FD001739FF001829FE00DAF -:10722000F11D649FE00DF11D929FF00D839FF00D05 -:10723000749FF00D659FF00D9927729FB00DE11DB1 -:10724000F91F639FB00DE11DF91FBD01CF0111248E -:107250000895AA1BBB1B51E107C0AA1FBB1FA6179D -:10726000B70710F0A61BB70B881F991F5A95A9F7EF -:1072700080959095BC01CD010895A1E21A2EAA1B1C -:10728000BB1BFD010DC0AA1FBB1FEE1FFF1FA217D6 -:10729000B307E407F50720F0A21BB30BE40BF50BD3 -:1072A000661F771F881F991F1A9469F7609570955C -:1072B000809590959B01AC01BD01CF01089597FB8E -:1072C000092E05260ED057FD04D0D7DF0AD0001CAA -:1072D00038F450954095309521953F4F4F4F5F4F73 -:1072E0000895F6F790958095709561957F4F8F4F33 -:1072F0009F4F08950790F691E02D099491110895FC -:1073000081568A5108F4805285580895FC010590F1 -:107310000020E9F7809590958E0F9F1F0895FB013F -:10732000DC0104C08D910190801921F4415050403E -:10733000C8F7881B990B0895FB01DC0102C001907E -:107340000D9241505040D8F70895FB01DC014150A7 -:10735000504030F08D910190801919F40020B9F758 -:10736000881B990B0895FB01DC014150504048F007 -:1073700001900D920020C9F701C01D92415050406C -:10738000E0F708950F931F93DF93CF93CDB7DEB748 -:107390002E970FB6F894DEBF0FBECDBF0D891E89A4 -:1073A0008F89988D26E02C831A83098397FF02C06A -:1073B00080E090E801979E838D839E01255E3F4F7C -:1073C000CE010196698D7A8DA90119D04D815E811A -:1073D00057FD0AC02F813885421753070CF49A01D4 -:1073E000020F131FF80110822E960FB6F894DEBF1D -:1073F0000FBECDBFCF91DF911F910F9108952F92B6 -:107400003F924F925F926F927F928F929F92AF9234 -:10741000BF92CF92DF92EF92FF920F931F93DF9371 -:10742000CF93CDB7DEB72C970FB6F894DEBF0FBE63 -:10743000CDBF6C011B018A01FC011782168283817A -:1074400081FFC4C12E010894411C511CF601938197 -:10745000F10193FD859193FF81911F01882309F428 -:10746000B1C1853239F493FD859193FF81911F015C -:10747000853221F490E0B601F5D1E8CFEE24FF2467 -:1074800020E02032B0F48B3269F08C3228F4803264 -:1074900051F0833271F40BC08D3239F0803349F4EE -:1074A00021602CC02260246029C0286027C0206190 -:1074B00025C027FD2CC0382F30533A3098F426FFD2 -:1074C00008C08E2D880FE82EEE0CEE0CE80EE30EB1 -:1074D00015C08F2D880FF82EFF0CFF0CF80EF30E41 -:1074E00020620CC08E3221F426FD6CC1206406C0DF -:1074F0008C3611F4206802C0883649F4F10193FDFE -:10750000859193FF81911F01882309F0BACF982FAD -:107510009554933018F09052933028F40C5F1F4F1D -:10752000FFE3F9830DC0833631F0833771F0833583 -:1075300009F05CC021C0F801808189830E5F1F4F74 -:10754000420171E0A72EB12C15C062E0662E712CAD -:10755000600E711EF8018080918026FF03C06E2DA1 -:1075600070E002C06FEF7FEFC4012C8770D15C0127 -:1075700083012C852F7716C052E0652E712C600E8A -:10758000711EF8018080918026FF03C06E2D70E08F -:1075900002C06FEF7FEFC4012C874ED15C012C85B8 -:1075A0002068830123FD1EC007C080E290E0B60181 -:1075B0002C8758D1FA942C858F2D90E0A816B90607 -:1075C000A0F310C0F40127FD859127FF81914F01A1 -:1075D00090E0B6012C8746D12C85F110FA940894DE -:1075E000A108B108A114B10469F7E9C0843611F00B -:1075F000893641F527FF08C0F801608171818281D9 -:1076000093810C5F1F4F09C0F80160817181882749 -:1076100077FD8095982F0E5F1F4F4FE6B42EB22254 -:1076200097FF09C090958095709561957F4F8F4F1A -:107630009F4FF0E8BF2AA2012AE030E03FD1782E28 -:10764000741844C0853731F43FEEB32EB2222AE0DD -:1076500030E025C099EFB92EB2228F36C1F08037C5 -:1076600020F4883509F0AEC00DC0803721F088378E -:1076700009F0A8C002C020E1B22AB4FE0BC084E029 -:10768000B82A08C0B4FE09C0E6E0BE2A06C028E059 -:1076900030E005C020E130E002C020E132E0B7FE7A -:1076A00008C0F80160817181828193810C5F1F4F56 -:1076B00007C0F8016081718180E090E00E5F1F4F8C -:1076C000A201FCD0782E7418FFE7BF22B6FE0BC0D3 -:1076D0002EEFB2227E1438F4B4FE07C0B2FC05C00F -:1076E0008FEEB82202C0A72C01C0AE2C8B2D90E0EB -:1076F000B4FE0DC0FE01E70DF11D2081203319F409 -:10770000E9EEBE2209C0A394B2FE06C004C086788A -:107710009070009709F0A3948B2C9924B3FC13C0AC -:10772000B0FE0EC0AF1428F4E72CEF0CEA18AF2C13 -:1077300007C0E72C05C080E290E0B60193D0A39487 -:10774000AF14C8F304C0AF1410F4FA1801C0FF243A -:1077500084FE0EC080E390E0B60184D082FE1DC09E -:1077600081FE03C088E590E010C088E790E00DC07E -:10777000C40186789070009781F081FC02C080E29D -:1077800001C08BE2B7FC8DE290E0B6016BD005C082 -:1077900080E390E0B60166D0EA947E14C8F37A9450 -:1077A000F201E70DF11D808190E0B6015BD07720FA -:1077B000B1F705C080E290E0B60154D0FA94FF2002 -:1077C000C9F744CEF6012681378102C02FEF3FEF83 -:1077D000C9012C960FB6F894DEBF0FBECDBFCF9176 -:1077E000DF911F910F91FF90EF90DF90CF90BF90AE -:1077F000AF909F908F907F906F905F904F903F9051 -:107800002F900895F999FECF92BD81BDF89A9927DE -:1078100080B50895262FF999FECF92BD81BDF89AC3 -:10782000019700B4021639F01FBA20BD0FB6F894C4 -:10783000FA9AF99A0FBE0895FC01059061507040C4 -:107840000110D8F7809590958E0F9F1F0895FC0129 -:107850006150704001900110D8F7809590958E0F7F -:107860009F1F08950F931F93CF93DF938C01EB011C -:107870008B8181FF1BC082FF0DC02E813F818C81D7 -:107880009D812817390764F4E881F9810193F98310 -:10789000E88306C0E885F985802F0995009731F4C3 -:1078A0008E819F8101969F838E8302C00FEF1FEF11 -:1078B000C801DF91CF911F910F910895FA01AA2776 -:1078C000283051F1203181F1E8946F936E7F6E5F23 -:1078D0007F4F8F4F9F4FAF4FB1E03ED0B4E03CD0D1 -:1078E000670F781F891F9A1FA11D680F791F8A1FB4 -:1078F000911DA11D6A0F711D811D911DA11D20D01B -:1079000009F468943F912AE0269F11243019305DD4 -:107910003193DEF6CF010895462F4770405D4193C5 -:10792000B3E00FD0C9F7F6CF462F4F70405D4A3312 -:1079300018F0495D31FD4052419302D0A9F7EACFDA -:10794000B4E0A6959795879577956795BA95C9F709 -:1079500000976105710508959B01AC010A2E0694FC -:107960005795479537952795BA95C9F7620F731FB5 -:10797000841F951FA01D089517E000E0C4E6D7E01E -:1079800040E005C022974109FE014BBFB3DCC6367B -:0A799000D1074007B9F7F894FFCFC4 -:10799A002E2E0053656C656374204469736B006E08 -:1079AA006F20696D6167652066696C657320666F13 -:1079BA00756E640001030507090E10121416181CCF -:1079CA001E696E636F6D706C657465207772697479 -:1079DA00650062616420736563746F722025642098 -:1079EA00666F722074256400627566206C6F636B23 -:1079FA0065642025642F25643A25640063686563FD -:107A0A006B73756D206661696C75726520300063F1 -:107A1A006865636B73756D206661696C7572652044 -:107A2A003100636865636B73756D206661696C7597 -:107A3A007265203200636865636B73756D206661D9 -:107A4A00696C0043504C44204669726D77617265D7 -:107A5A00202564002564002575006669726D7761CA -:107A6A0072652E78766600534420726561642065DB -:107A7A0072726F72205200526573756C743A207379 -:107A8A0075636365737300526573756C743A206528 -:107A9A0072726F72202564005344207265616420FB -:107AAA007374617274206572726F7200534420722B -:107ABA00656164206572726F722044007772207764 -:107ACA00726F6E6720747261636B2025642F256460 -:107ADA000052657665727465642074726B20253075 -:107AEA00326420202000534420726561642065724C -:107AFA00726F722057005344207772697465537409 -:107B0A00617274206661696C0053442077726974EB -:107B1A0065206572726F72005344207772697465CA -:107B2A0053746F70206661696C00536176656420D6 -:107B3A0074726B202530326420696E20256C7520A2 -:107B4A00200053442063617264206572726F722050 -:107B5A0025643A256400253032640025642000D566 -:107B6A00AAAD0000000000000000000000008A0129 -:107B7A00AD01D8010D024E02A2301B311D35713400 -:107B8A0024319A309A3003313D316236083109374F -:107B9A001C361C361C36D035D035D035D332C830D9 -:087BAA00C830C234A830993242 -:020000021000EC -:08EFF800DDDDDDDD000100009C -:00000001FF diff --git a/arduino/floppyemu/Release/merged.hex b/arduino/floppyemu/Release/merged.hex deleted file mode 100755 index 307ebb6..0000000 --- a/arduino/floppyemu/Release/merged.hex +++ /dev/null @@ -1,1123 +0,0 @@ -:020000040000FA -:20000000B2C30000DFC30000DDC30000DBC300000C941F0ED7C300000C94AB0A0C94F7092F -:20002000D1C30000CFC30000CDC30000CBC30000C9C30000C7C30000C5C30000C3C3000058 -:20004000C1C30000BFC300000C945A1DBBC30000B9C30000B7C30000B5C30000B3C3000021 -:20006000B1C30000AFC30000ADC30000ABC30000A9C30000A7C30000A5C30000A3C3000018 -:20008000A1C300009FC300009DC3000000000C001800240030003C004800540060006C001E -:2000A0007800840090009C00A800B400C000CB00D600E100EC00F70002010D011801230149 -:2000C0002E01390144014F015A01650170017A0184018E019801A201AC01B601C001CA0135 -:2000E000D401DE01E801F201FC0106021002190222022B0234023D0246024F025802610222 -:200100006A0273027C0285028E029702A002A802B002B802C002C802D002D802E002E80214 -:20012000F002F80200030803100318030C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0C0B0B0B0BAB -:200140000B0B0B0B0B0B0B0B0B0B0B0B0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0909090957 -:200160000909090909090909090909090808080808080808080808080808080896979A9B31 -:200180009D9E9FA6A7ABACADAEAFB2B3B4B5B6B7B9BABBBCBDBEBFCBCDCECFD3D6D7D9DA10 -:2001A000DBDCDDDEDFE5E6E7E9EAEBECEDEEEFF2F3F4F5F6F7F9FAFBFCFDFEFF0001FFFF2A -:2001C0000203FF040506FFFFFFFFFFFF0708FFFFFF090A0B0C0DFFFF0E0F10111213FF145B -:2001E00015161718191AFFFFFFFFFFFFFFFFFFFFFF1BFF1C1D1EFFFFFF1FFFFF2021FF2290 -:20020000232425262728FFFFFFFFFF292A2BFF2C2D2E2F303132FFFF333435363738FF39C5 -:200220003A3B3C3D3E3F00002110422063308440A550C660E770088129914AA16BB18CC160 -:20024000ADD1CEE1EFF13112100273325222B5529442F772D662399318837BB35AA3BDD383 -:200260009CC3FFF3DEE36224433420040114E664C774A44485546AA54BB528850995EEE5C3 -:20028000CFF5ACC58DD55336722611163006D776F6669556B4465BB77AA719973887DFF743 -:2002A000FEE79DD7BCC7C448E5588668A7784008611802282338CCC9EDD98EE9AFF948897B -:2002C00069990AA92BB9F55AD44AB77A966A711A500A333A122AFDDBDCCBBFFB9EEB799B83 -:2002E000588B3BBB1AABA66C877CE44CC55C222C033C600C411CAEED8FFDECCDCDDD2AAD43 -:200300000BBD688D499D977EB66ED55EF44E133E322E511E700E9FFFBEEFDDDFFCCF1BBF42 -:200320003AAF599F788F8891A981CAB1EBA10CD12DC14EF16FE18010A100C230E3200450B7 -:20034000254046706760B9839893FBA3DAB33DC31CD37FE35EF3B1029012F322D2323542A2 -:20036000145277625672EAB5CBA5A89589856EF54FE52CD50DC5E234C324A01481046674A2 -:20038000476424540544DBA7FAB79987B8975FE77EF71DC73CD7D326F2369106B016576662 -:2003A0007676154634564CD96DC90EF92FE9C899E9898AB9ABA94458654806782768C0185A -:2003C000E1088238A3287DCB5CDB3FEB1EFBF98BD89BBBAB9ABB754A545A376A167AF10AA2 -:2003E000D01AB32A923A2EFD0FED6CDD4DCDAABD8BADE89DC98D267C076C645C454CA23C22 -:20040000832CE01CC10C1FEF3EFF5DCF7CDF9BAFBABFD98FF89F176E367E554E745E932E61 -:20042000B23ED10EF01E202020202020202020202020202020202020202020002049646C06 -:200440006500205265616400577269746500547261636B20202020536964650031343430CD -:200460004B204469736B436F707920696D616765003830304B204469736B436F7079206916 -:200480006D616765003430304B204469736B436F707920696D61676500313434304B2072D4 -:2004A000617720696D616765003830304B2072617720696D616765003430304B2072617788 -:2004C00020696D61676500696D616765206E6F7420636F6E746967756F7573006572726F5D -:2004E00072206F70656E696E6720696D61676500505245563A2043616E63656C004E45588F -:20050000543A204C6F6164206669726D7761726500626567696E0052656C656173652062E8 -:200520007574746F6E7320746F0043504C44204649524D5741524520555044415445004345 -:200540006F6E74726173743A200053454C4543543A2053617665004E4558543A20446172DD -:200560006B657200505245563A204C69676874657200626567696E0052656C6561736520ED -:20058000627574746F6E7320746F00434F4E54524153542041444A5553544D454E5400417B -:2005A00070702056657273696F6E20312E30204C002020202020464C4F50505920454D55B9 -:2005C00020202020202000507265737320616E7920627574746F6E006669726D77617265CD -:2005E0002E78766600436F756C64206E6F74206F70656E005570646174696E6720666972A2 -:200600006D776172652E2E2E00464154414C204552524F522020202020202020202000578B -:2006200052495445204552524F5220202020202020202020000000000017000300031F0A56 -:200640001F0A1F050904120F171C000303000E11110E00050205040E041008000404040062 -:2006600010001804031E110F021F0019151215150A07041F1715091E151D1905031A150B6E -:2006800017150F000A00040C04040E1F0A0A0A1F0E040115030E15161E051E1F150A0E1191 -:2006A000111F110E1F15151F05050E151D1F041F111F1108100F1F041B1F10101F061F1FAF -:2006C0000E1F0E110E1F05020E191E1F0D16121509011F010F101F0718071F0C1F1B041BDA -:2006E000031C031915131F101002040810101F0406041010100003031A161C1F120C0C1220 -:20070000120C121F0C1A16041E050C2A1E1F021C001D0010201D1F0C12111F101E0E1E1E47 -:20072000021C0C120C3E120C0C123E1C0202141E0A021F120E101E0E180E1E1C1E120C1232 -:2007400006281E1A1F16041B11001F00111B04080C047C3C3E5E2B3D3F2F5B5D3B2C2A22D2 -:200760005C00451D491D11241FBECFEFD0E4DEBFCDBF13E0A0E0B1E0EAE9F9E700E00BBF47 -:2007800002C007900D92A831B107D9F717E3A8E1B3E001C01D92AD3DB107E1F717E000E029 -:2007A000C4E6D7E040E006C022974109FE014BBF0E947A39C236D1074007B1F70E941918FF -:2007C0000C94BC3C1DCC2F923F924F925F926F927F928F929F92AF92BF92CF92DF92EF92EB -:2007E000FF920F931F93DF93CF93CDB7DEB72D970FB6F894DEBF0FBECDBF8B014A013E0106 -:200800000894611C711CD301E4E2F1E02DE001900D922150E1F7BB244424AA2452E8552E6F -:2008200042E2E42EF12CE80EF91E3EE0C32ED12CCC0EDD1E22E8222E312C280C391CC7016F -:20084000B80140E250E00E94C92480329105A1F4D8011B968C911B9790E09C012F73307079 -:200860002F30310559F183FD23C0F8018081853E19F1882309F05AC0D4011C9280E02D960B -:200880000FB6F894DEBF0FBECDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF909F9058 -:2008A0008F907F906F905F904F903F902F900895F8018081882301F3BB24C1CFBB2021F519 -:2008C0008C91982F907E903409F0B9CF9FE1A92EA8221D964C90F1011082A5E7B0E085E725 -:2008E000582EF301AD01480D591D81919801280F311DD9018C91DA018D93AD01EC15FD0532 -:20090000A1F7BB24B3949BCFD8018C91AA948A1599F61D968C911D97841571F6552009F457 -:200920008ECFB3EF5B0EA52DB0E0DBCF8E3221F2BB2081F031962BE090E001C08191392FA7 -:200940003795332737959695932B980F2150B1F7941531F0C801B4010E94092481E08FCF26 -:20096000FA2DF130B9F7452D50E043385105B4F79A0160E080E090E0880D991D280D391DE0 -:20098000D9012C91FC0120836F5F862F90E09C01240F351F233831057CF381E070CFEF92E8 -:2009A000FF920F931F93DF93CF93CDB7DEB7A9970FB6F894DEBF0FBECDBFFC01DB018C91E8 -:2009C0008E32A9F1838590E0887190708031910509F466C0009759F5848D958DA68DB78D53 -:2009E000803020E4920726E0A20720E0B20709F459C0803020E892072CE0A20720E0B2076D -:200A000009F454C0803020E8920726E1A20720E0B20709F449C081509044A640B0408F3FBC -:200A20002FE2920721E1A20720E0B20778F020E0822FA9960FB6F894DEBF0FBECDBFCF91A9 -:200A4000DF911F910F91FF90EF900895CF017E010894E11CF11CB7010E9409241E86198A68 -:200A60008E01025F1F4FC801B70141E00E94342A882371F0C80165E773E340E052E00E940B -:200A8000C924C8010E9433278091C733813081F08989882361F2C8010E94332720E0C8CF0B -:200AA00021E0C6CF23E0C4CF25E0C2CF24E0C0CF8091C833882361F78091B63390E0A0E0E8 -:200AC000B0E0BA2FA92F982F88272091B733820F911DA11DB11DB695A79597958795B695CF -:200AE000A79597958795803921E0920720E0A20720E0B207F1F0803223E0920720E0A207E5 -:200B000020E0B207A1F0803A25E0920720E0A20720E0B20709F0BCCF28E08989882309F48B -:200B200087CFC80129A70E94332729A581CF27E0F4CF26E0F2CF2F923F924F925F926F92B6 -:200B40007F928F929F92AF92BF92CF92DF92EF92FF920F931F93DF93CF93CDB7DEB7C05F5C -:200B6000D0400FB6F894DEBF0FBECDBF7C011092190310921803829640E050E0BA010E9461 -:200B80004B2603E4C02ED12CCC0EDD1E13E6A12EB12CAC0EBD1EB4E26B2E712CC701B601B8 -:200BA000A50111DE8823E1F1809118039091190321E08734920708F0A7C1C601B501EFDEBB -:200BC000882E882359F38091180390911903869D8001879D100D969D100D11240B581C4FC7 -:200BE000C801B50146E150E00E94B339B8016A5E7F4FC6010E940924809118039091190343 -:200C0000869DF001879DF00D969DF00D1124EB58FC4F83A201969093190380931803BECFF6 -:200C20002091180330911903C751DF4F39832883C95ED040F70185A182508230A8F184E286 -:200C400090E0C751DF4FE881F981C95ED040E89F8001E99F100DF89F100D11240B581C4F60 -:200C6000C80160E071E046E150E00E94B339C801469660E071E04DE050E00E94B33982E0B2 -:200C8000F80183A3C751DF4F28813981C95ED0402F5F3F4FC751DF4F39832883C95ED04055 -:200CA0003093190320931803A8E92A2EA3E03A2E80E090E07E010894E11CF11CF7E1CF2EE9 -:200CC000D12CCC0EDD1EC751DF4FE881F981C95ED0408E179F0708F01EC1FC013196C351E8 -:200CE000DF4FF983E883CD5ED040C751DF4F28813981C95ED040E217F30708F026C1C10130 -:200D00008397F101B496C151DF4FF983E883CF5ED0405F01C351DF4F48805980CD5ED0409B -:200D2000CA51DF4F8883C65ED04091012D503040C551DF4F39832883CB5ED040C951DF4F80 -:200D400039822882C75ED040392EC701CA51DF4F6881C65ED040732D46E150E00E94B339DF -:200D600088240AC00E0D1F1DF801808190E00E947E39F80180838394F70101900020E9F747 -:200D80003197EE19FF09082D10E00E171F0750F3EDED8E2EEFEF9E2E8A0C9B1C682C292C53 -:200DA000C601B40146E150E00E94B33977240AC00C0D1D1DF801808190E00E947E39F8015E -:200DC00080837394F60101900020E9F73197EC19FD09072D10E00E171F0750F3C701B6017D -:200DE00046E150E00E94A539282F392FC951DF4FE881F981C75ED04080818150823008F47D -:200E000080C0F50180818150823008F477C0121613060CF055C0CE018D96CA51DF4F68816F -:200E2000C65ED040732D46E150E00E94B339CA51DF4F8881C65ED040932D662D722D46E15A -:200E400050E00E94B339862D922DBE01635D7F4F46E150E00E94B339CE018D96C551DF4FFA -:200E600068817981CB5ED0404DE050E00E94B33984010A5E1F4FC551DF4F88819981CB5E80 -:200E8000D040B8014DE050E00E94B339C801BE01635D7F4F4DE050E00E94B339C951DF4F55 -:200EA000E881F981C75ED0408081F5019081C951DF4FE881F981C75ED0409083F5018083A6 -:200EC0000894411C511C24E230E0A20EB31EC751DF4F88819981C95ED0404816590608F4BC -:200EE00034CFC151DF4F28803980CF5ED040C351DF4F88819981CD5ED040E5CE28513C4FBA -:200F000086CF285E33407DCFC751DF4F99838883C95ED0408FCEC051DF4F0FB6F894DEBF09 -:200F20000FBECDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF909F908F907F906F9072 -:200F40005F904F903F902F900895C1018496C151DF4F99838883CF5ED040C3CF8F929F9234 -:200F6000AF92BF92CF92DF92EF92FF920F931F93CF93DF9380911A0390911B0320911C0396 -:200F800030911D032817390728F430931B0320931A03C90104968217930730F42450304085 -:200FA00030931B0320931A0380E060E00E949A1D81E06FE70E948B1DC3E1D0E081E060E48D -:200FC0000E948B1D2197D1F783E091E00E948F1EC3E1D0E081E060E40E948B1D2197D1F761 -:200FE00081E06FE70E948B1D20911803309119032115310509F464C140911A0350911B03CC -:20100000CA0105964817590708F033C14217530708F02FC164E270E0469F7001479FF00C56 -:20102000569FF00C112488E993E0E80EF91EEA0191E0C92ED12CBB24B39480911C039091D2 -:201040001D03C817D90709F0BB24AC2C80E06C2D0E949A1D04E510E007C060E081E00E94CC -:201060008B1D0150104049F0BB20B9F36FE781E00E948B1D01501040B9F781E06A2D0E947B -:201080009A1D870103521040902E812EC8016B2D43E50E94A61DF70180818150823008F499 -:2010A000BDC0BB2009F0A4C08601219640911A0350911B03CA010596C817D907E0F12091A9 -:2010C0001803309119032630310508F047C0EE24E39482E56E2D0E949A1D81E060E00E9466 -:2010E0008B1D81E060E00E948B1DE3947E2D763081F780911A0390911B039801280F391F88 -:2011000040911C0350911D034217530708F4E2C02150304030931D0320931C0304301105AD -:2011200009F02CCF009709F429CF019790931B0380931A0323CF20911803309119030894EF -:20114000C11CD11C64E270E0E60EF71EC217D30708F471CF2630310508F4B9CFE7E2F0E08E -:201160004E9FC0014F9F900D5E9F900D11248D539F4FB9010E94293988E0E82EE60E83ECFA -:2011800090E0B9010E942939CE2CC61AC8E0D0E0BB24B39482E56B2D0E949A1D81E060E0D0 -:2011A0000E948B1D4C2F9E01295F3F4F2C173D070CF484C060E00AC0E41650F066956068E3 -:2011C0004F5F842F90E0281739074CF04C15A0F766954F5F842F90E028173907BCF781E02C -:2011E0000E948B1DB39428967B2D763099F681CF84E393E0692D782D46E150E00E94B33979 -:20120000B8016A5E7F4F8EE193E04DE050E00E94B339F701808180934A0346CF89E46A2D40 -:201220000E949A1DBB2041F181E06FE70E948B1D81E063E40E948B1D81E06DE50E948B1D58 -:2012400081E06DE50E948B1D81E06DE50E948B1D81E06BE50E948B1D81E06BE50E948B1D9E -:2012600081E063E40E948B1D6FE781E00E948B1D18CF00E010E027CF81E060E00E948B1DE3 -:2012800081E06CE30E948B1D81E062E20E948B1D81E062E20E948B1D81E062E20E948B1D87 -:2012A00081E064E20E948B1D81E064E20E948B1D81E06CE30E948B1D60E0D7CF60E08FCFCE -:2012C00080E061E00E949A1D8FE091E060E044E50E94A61DDF91CF911F910F91FF90EF9038 -:2012E000DF90CF90BF90AF909F908F9008958130910559F0009721F48091A135882309F4DC -:2013000008958EE995E30C94332710929E351092A13508958FE781B9559A209A3A9A3D9AB9 -:201320003E9A3B9A239A5C9A599A5A9A5F9A5B9A179A589A409A419A289A429A45984698C7 -:20134000439A2B9AE3E7F0E0808181608083EDE6F0E0808182608083808181608083089561 -:201360001F93DF93CF93CDB7DEB72A970FB6F894DEBF0FBECDBFCE010196DC01EEEDF2E0D6 -:201380002AE001900D922150E1F7E0914C03F0E0F595E795F595E795F595E795F595E79522 -:2013A0001FB7F894E53008F0E4E0F0E0EE0FFF1FE80FF91F20813181220F331F40E050E0DA -:2013C00060E07DE281E391E00E945F3930935B0320935A031FBF82E086BB2A960FB6F8949C -:2013E000DEBF0FBECDBFCF91DF911F9108951F920F920FB60F920BB60F9211242F933F93F7 -:201400004F935F936F937F938F939F93AF93BF93CF93DF93EF93FF93489B2FC0E0914C0382 -:2014200080915503882309F03DC0F0E0E45DFE4F249130E0220F331F21153105A9F5379922 -:201440005DC080914C038F5F80934C0380914C03882309F064C04598429A4899FECF429856 -:20146000459A7EDFC0919435D0919535C330D10508F057C081E080935103FF91EF91DF91CB -:20148000CF91BF91AF919F918F917F916F915F914F913F912F910F900BBE0F900FBE0F9029 -:2014A0001F90189524E230E080E090E040E050E068E188589A4CFC01808180FF03C06831B2 -:2014C00059F1542F4F5F842F90E0821793070CF1561708F4B4CF862FE82FF0E0E858FA4C30 -:2014E000908191FF03C09081916090839081946090838F5F581780F7379BA3CF80914C03E3 -:20150000882309F4A3CF80914C03815080934C039DCF4831E9F2CDCF542F642FD3CF459A2B -:201520009BCF8FE593E061E371E046E150E00E94B339C851DC4FD0937735C09376351092ED -:20154000500381E0809351038093520310929535109294358FCF1F920F920FB60F920BB65A -:201560000F9211241F932F933F934F935F936F937F938F939F93AF93BF93CF93DF93EF9329 -:20158000FF9386B190E095958795817090914E03891791F090915803923009F46DC010923E -:2015A0004E0311E010935103C0919435D0919535C330D10508F047C086B1817011E0812724 -:2015C000909150038917C9F08093500380915003882349F58FE781B9469880916B008F777B -:2015E00080936B00C0919435D0919535C330D10508F045C081E080935103FF91EF91DF911A -:20160000CF91BF91AF919F918F917F916F915F914F913F912F911F910F900BBE0F900FBE96 -:201620000F901F90189511B8469A80916B00806880936B0080B180788093933510929535B4 -:2016400010929435D7CF8FE593E061E371E046E150E00E94B339C053D84FD0937735C0937C -:2016600076351092500310935103109352031092953510929435A0CF80934E0392CF8FE55C -:2016800093E061E371E046E150E00E94B339C854D44FD0937735C093763510925003109379 -:2016A0005103109352031092953510929435A2CF1F93E0B1E0688091943590919535843092 -:2016C000910588F48330910509F487C0DC01A153BD4F2C912E1709F404C1109295351092BC -:2016E00094351F910895F0E0EA5DFE4FE49132E08F3B930748F59C012370307022303105F0 -:2017000009F4BBC02330310509F449C12130310509F418C1EE0FEE0FE093963540919A358C -:2017200050E09A01220F232F221F330B20939B35440F551F422B40939A35019690939535FF -:20174000809394351F910895F2E08F3B9F0709F4C1C022E0803C920709F4CEC032E0813CEF -:20176000930709F4E2C1F2E0823C9F0709F0B5CF80919635982F990F990F90939635E82B88 -:2017800090919A35E917C9F08FE593E062E971E046E150E00E94B33980E490E09093773595 -:2017A000809376351092500381E080935103809352031092953510929435E0919735F0E062 -:2017C000E858FA4C80818260808380818160808380818B7F80832B9A80CFF0E0EA5DFE4F32 -:2017E0001491E0914C0380915503882309F082C0F0E0E45DFE4FE4911E1708F04DC1E091B6 -:201800004C03882309F074C0F0E0E45DFE4FE49180914E03E89F802D1124810F8093973594 -:2018200090E0DC01A858BA4C2C9122FDE0C0982F8827990F8B589C4F90939D3580939C3514 -:201840008C9184608C938C918D7F8C9380914C038093903580914E03809391351093923543 -:201860002B9810929A3510929935109298358091943590919535019661CF50919635452FA9 -:20188000407C4E2B2091983542278431910578F0E0919C35F0919D354193F0939D35E09348 -:2018A0009C3550919635809194359091953560919B352091993530E0260F311D240F311D92 -:2018C0002093993530939B35550F550F50939635019634CFEE0FEE0FE093963580EC92E0CE -:2018E0002DCF20915403222309F0F7CE019626CFE2E18ECFE2E180CF80919635982F990FD8 -:20190000990F90939635807C8E2B90919835891709F46AC08FE593E06CE671E046E150E0E6 -:201920000E94B3398EE390E090937735809376351092500381E0809351038093520381E025 -:2019400090E0FCCE50919635452F407C4E2B20919A3542278431910578F0E0919C35F09199 -:201960009D354193F0939D35E0939C3550919635809194359091953560919B352091983578 -:2019800030E0260F311D240F311D2093983530939B35550F550F509396350196CFCE4091A5 -:2019A00096354E2B2091993542278431910568F0E0919C35F0919D354193F0939D35E09327 -:2019C0009C35809194359091953550919B3520919A3530E0250F311D240F311D20939A35AB -:2019E00030939B350196AACE81EC92E0A7CE30914C0320914E038DB79EB70C970FB6F89452 -:201A00009EBF0FBE8DBFADB7BEB711968FE593E0EDB7FEB79283818386E190E013969C93C8 -:201A20008E93129788E591E015969C938E93149716963C93169717961C92179718962C93BA -:201A4000189719961C9219971A961C931A971B961C920E94C2398DE390E0909377358093FC -:201A600076351092500381E0809351038093520310929535109294358091973590E02DB78E -:201A80003EB7245F3F4F0FB6F8943EBF0FBE2DBFDC01A858BA4CCBCE20914C038DB79EB724 -:201AA0000A970FB6F8949EBF0FBE8DBFADB7BEB711968FE593E0EDB7FEB79283818386E17E -:201AC00090E013969C938E93129782E491E015969C938E93149716961C93169717961C9214 -:201AE000179718962C93189719961C920E94C2398CE390E0909377358093763510925003C1 -:201B000081E080935103809352031092953510929435809155032DB73EB7265F3F4F0FB6A4 -:201B2000F8943EBF0FBE2DBF6ACE80919635982F990F990F90939635807C8E2B90919935A6 -:201B4000891759F08FE593E06FE771E046E150E00E94B3398FE390E0E7CE82EC92E0EECDF7 -:201B60004091560350915703E2EEF2E02591349160E07FEF2627372791EA692F632770E09D -:201B8000660F771F6A5D7D4FFB0165917491322F2227262737279327E92FF0E0EE0FFF1F9E -:201BA000EA5DFD4F65917491322F222726273727EBEFE327F0E0EE0FFF1FEA5DFD4F6591EA -:201BC0007491322F222726273727B82FBB0FA0E0AB58BC4F80E090E0722F6627ED91E327E6 -:201BE000F0E0EE0FFF1FEA5DFD4F2591349126273727019662E08030960771F73093570396 -:201C00002093560342175307C9F08FE593E065EA71E046E150E00E94B33986E490E09093E3 -:201C20007735809376351092500381E08093510380935203109295351092943508951F92F0 -:201C40000F920FB60F920BB60F9211242F933F934F935F936F937F938F939F93AF93BF9382 -:201C6000EF93FF9390B180915003882309F456C0892F807890919335891709F44FC0809395 -:201C8000933590915503992309F46FC0882309F461C020B12F7080919635282B2093963535 -:201CA00080919435909195358230910509F45FC0009709F446C08130910509F46DC032E0DE -:201CC0008330930708F458C0A2E083309A0709F49AC0B2E084309B0709F530E08091560316 -:201CE00090915703822B932B90935703809356038091973535DFE0919735F0E0E858FA4C91 -:201D000080818260808380818160808380818B7F80832B9A1092953510929435FF91EF913E -:201D2000BF91AF919F918F917F916F915F914F913F912F910F900BBE0F900FBE0F901F9031 -:201D40001895213A59F781E090E09093953580939435E4CF80B190E082959295907F982731 -:201D6000807F982780939635D9CFA2DCD7CF2B3FE9F0213A79F6D2CF30919735F32FFF0F90 -:201D8000E0E0E80FF91FEE58FC4F208301969093953580939435C2CF213A09F0BBCF82E00F -:201DA00090E09093953580939435B8CF83E090E0909395358093943520915903209397353B -:201DC000822F90E0FC01E858FA4C308132FD26C0982F8827990F8B589C4F90939D358093A5 -:201DE0009C3580818460808380818D7F808380914C038093903580914E03809391352093F4 -:201E000092352B988BCF109256032093570384E092E0909395358093943580CF50914C03B8 -:201E200040914E032DB73EB72C5030400FB6F8943EBF0FBE2DBFEDB7FEB731962FE533E06D -:201E4000ADB7BEB712963C932E93119726E130E03383228328E531E0358324835683178268 -:201E600040871186938782870E94C23987E490E090937735809376351092500381E0809373 -:201E800051038093520310929535109294352DB73EB7245F3F4F0FB6F8943EBF0FBE2DBFBE -:201EA0003DCFF89490915003992341F48F7782B9459A079BFECF0799FECF459878940895A3 -:201EC0008AE082B9459A079BFECF0799FECF4598E091570381EAE827F0E0EE0FFF1FEA5D4E -:201EE000FD4F859194913091560320E082279327909357038093560381E182B9459A079BD7 -:201F0000FECF0799FECF45980895982F92959F7092B9459A079BFECF0799FECF4598482FB6 -:201F20004F70E0915703E827F0E0EE0FFF1FEA5DFD4F859194913091560320E082279327D2 -:201F4000909357038093560342B9459A079BFECF0799FECF459808952F923F924F925F9204 -:201F60006F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93DF93CF9300D00F92EE -:201F8000CDB7DEB78983692EA2EDCA2EA2E0DA2E992422243324EE24FF2400E010E088C0CD -:201FA0001070C801880F991F2801440C452C441C55085194482A592AF6010191852D99270D -:201FC000820D931D800F911DAFEF4A225524D6011196AC906F010894C11CD11CA7014A0D73 -:201FE000511D9C0120703170232F3327420F531F3FEF232E312C2822392271802FEFE22E96 -:20200000F12CE422F522872C8E24042510E0A224BB24F501E07CF070F595E795F595E795A5 -:20202000F595E795F595E7959801207C30703595279535952795E22BF32B882D82958695A1 -:202040008695837090E0E82BF92BE458FE4F84914A835B8326DF0F73107004581E4FF801B9 -:2020600084911FDF809151034A815B81882309F0A9C00894C11CD11C8201070D111D407059 -:202080005170452F5527040F151FF501EF73F070E458FE4F849105DFE82DF0E0EF73F07067 -:2020A000E458FE4F8491FDDE9394F92DFE3A41F0292D243009F074CF9981C92ED62C70CFB9 -:2020C0001070C801880F991F5801AA0CAB2CAA1CBB08B194A82AB92AD6010C91200E311C10 -:2020E0008B2D9927280E391E1196CC90EC0CF11CC10180709170892F9927E80EF91E0A256C -:2021000010E0C224DD24F601E07CF070F595E795F595E795F595E795F595E795C801807C58 -:2021200090709595879595958795E82BF92BE458FE4F8491B6DEF801EF73F070E458FE4F66 -:202140008491AFDEF601EF73F070E458FE4F8491A8DEF101E07CF070F695E795F695E79544 -:20216000C501807C90700024880F991F001C880F991F001C892F902DE82BF92BC701807C33 -:202180009070929582958F7089279F708927E82BF92BE458FE4F849184DEF101EF73F070A8 -:2021A000E458FE4F84917DDEF701EF73F070E458FE4F849176DEF501EF73F070E458FE4F39 -:2021C00084916FDE0F900F900F90CF91DF911F910F91FF90EF90DF90CF90BF90AF909F9007 -:2021E0008F907F906F905F904F903F902F900895CF93DF9380E060E00E949A1D81EB95E00B -:2022000061E00E94271E8FE995E00E9486398195880F865D62E00E949A1D8FE995E060E0F0 -:202220000E94271E4DB75EB7485050400FB6F8945EBF0FBE4DBFEDB7FEB73196CFE5D3E0A8 -:20224000ADB7BEB71296DC93CE93119786E190E09383828383EB91E09583848380915E0323 -:20226000868317820E94C239FE0101900020E9F73197EC1BFD0B4DB75EB7485F5F4F0FB685 -:20228000F8945EBF0FBE4DBF8E2F8195880F865D63E00E949A1DCE0160E044E50E94A61D36 -:2022A0002B980E94531D95E028E04FEF53ED60E3415050406040E1F700C0000085B18227D3 -:2022C00085B9915091F70E94571DDF91CF910895CF92DF92EF92FF920F931F93DF93CF93C8 -:2022E00000D000D0CDB7DEB780E060E00E949A1D0E94D21E80E060E00E949A1D8BE895E0B9 -:2023000060E00E94271E80E062E00E949A1D88E795E060E00E94271E80E063E00E949A1D94 -:2023200082E795E060E00E94271E499BFECF4A9BFCCF4C9BFACF80E060E00E949A1D0E94EC -:20234000D21E80E062E00E949A1D84E695E060E00E94271E80E063E00E949A1D87E595E0AF -:2023600060E00E94271E80E064E00E949A1D8AE495E060E00E94271E8E010F5F1F4F84EC54 -:20238000E82E81E0F82EB4E0CB2ED12C16C08091C7358F3F29F08091C7358F5F8093C73542 -:2023A00080E061E20E948B1D6091C73580E00E948B1D80E060E20E948B1D80E060E00E946B -:2023C0009A1D8FE395E060E00E94271E8091C7352DB73EB7285030400FB6F8943EBF0FBE4F -:2023E0002DBFEDB7FEB73196ADB7BEB712961C930E931197D382C282F582E4828683178240 -:202400000E94C2392DB73EB7285F3F4F0FB6F8943EBF0FBE2DBFC80160E044E50E94A61D93 -:202420008FEF99E6A8E181509040A040E1F700C00000499B04C04A9B02C04C99FACF4A9B1B -:20244000A6CF49990BC08091C735813808F4A8CF8091C73581508093C735A2CF4C99A0CF6F -:202460006091C73581E090E00E940A3C0F900F900F900F90CF91DF911F910F91FF90EF900C -:20248000DF90CF9008951F930E94D21E80E060E00E949A1D84E393E060E044E50E94A61DEC -:2024A00080E061E00E949A1D8EE995E36EE173E043E00E94342A882309F48AC080914A031E -:2024C000833029F1863019F182E0809358038EE995E36BEB75E34FEB55E30E9456238823CA -:2024E000D1F487EC94E060E00E94271E8FEF93E2A4EF81509040A040E1F700C0000010E07A -:202500008EE995E30E943327812F1F91089581E080935803DCCF80E061E00E949A1D80914E -:202520004A03853009F4BFC0863008F05FC0833009F4A1C0843039F489EA94E060E00E9495 -:20254000271E80914A0391E0863008F490E0909375354F998CC0992309F45CC081E08093FB -:20256000540348E754E060E070E08EE995E30E944B268EE995E365E773E040E052E00E948D -:20258000C924E0917503F0E0EA58FC4F108210928B0380E062E00E949A1D86E793E060E02B -:2025A00044E50E94A61D80E064E00E949A1D8EE494E060E00E94271E80915403882379F502 -:2025C00011E08EE995E30E943327812F1F9108958EE995E36EE173E041E00E94342A8823C5 -:2025E00009F464C081E08093540371CF873009F452C0873008F447C0883009F0A4CF8CE59A -:2026000094E060E00E94271E81E08093550380914A0399CF44E254E060E070E0A6CF8DE4BD -:2026200060E00E949A1D81E060E00E948B1D81E068E70E948B1D81E06EE70E948B1D81E0BB -:2026400069E70E948B1D81E069E70E948B1D81E06EE70E948B1D81E068E70E948B1D11E0FA -:202660008EE995E30E943327812F1F91089581E08093540370CF88EB94E060E00E94271E5A -:2026800080914A0360CF85E894E060E00E94271E80914A0358CF81E794E060E00E94271E1D -:2026A00080914A0350CF89E994E0ABCF8CED94E060E00E94271E1ACF1F931FB7F894E091BB -:2026C0004C03F0E0EE0FFF1FE850F041808180934C030E948A0910924C0310924D0310923A -:2026E000510310924E0310924F03109250031092530382E0809358031092590310925403EB -:20270000109255031092520310925D0310925C031092773510927635109295351092943553 -:2027200080E090E0FC01E858FA4C1082019688319105C1F711B8469A28988FE798E3A1E03B -:2027400081509040A040E1F700C0000080B18F7780935E0346988FE781B9289A80916400F0 -:20276000877F8093640083E48093800089E1809381000E94B0090E94DE1E0E94D21E1FBF7B -:202780001F910895FF920F931F93CF93DF938C01F0905203C0917635D09177358DDF0E94BA -:2027A000D21E80E060E00E949A1DFF2009F43FC08FE196E061E00E94271E80E061E00E94C4 -:2027C0009A1DC80160E044E50E94A61D8DB79EB708970FB6F8949EBF0FBE8DBFEDB7FEB753 -:2027E00031960FE513E0ADB7BEB712961C930E93119786E190E09383828387EC91E09583C4 -:202800008483D783C6830E94C2398DB79EB708960FB6F8949EBF0FBE8DBF80E065E00E942C -:202820009A1DC80160E044E50E94A61DFFCF89E096E061E00E94271E80E061E00E949A1D7B -:20284000C80160E044E50E94A61DF0CF1F93CF93DF930E94D21E80E060E00E949A1D84EF9E -:2028600095E060E00E94271E4A9BFECF8FEF99E6A8E181509040A040E1F700C000008EE9F4 -:2028800095E36AEC71E041E00E94342A882331F562E00E949A1D85EE95E060E00E94271E7D -:2028A00080E063E00E949A1D88ED95E060E00E94271E80E065E00E949A1D87EC95E060E0E5 -:2028C0000E94271E499B04C04A9B02C04C99FACF0E94D21EDF91CF911F9108958EE995E376 -:2028E00065E773E040E052E00E94C92497FD4DC01092BA351092B93586E195E10E94C93816 -:202900001FB7F8940E947338EC011FBF8EE995E30E94332780E062E00E949A1D209761F14E -:20292000ADB7BEB718970FB6F894BEBF0FBEADBFEDB7FEB731968FE593E012969C938E9309 -:20294000119786E190E09383828387EF91E095838483D783C6830E94C2398DB79EB7089660 -:202960000FB6F8949EBF0FBE8DBF8FE593E060E044E50E94A61D9DCF8FE593E067EE71E0E2 -:2029800046E150E00E94B339F0CF87ED91E0FADEAFCF80E060E00E949A1D0E94D21E80E06D -:2029A00060E00E949A1D8AE295E060E00E94271E80E062E00E949A1D87E195E060E00E94BC -:2029C000271E80E063E00E949A1D81E195E060E00E94271E499BFECF4A9BFCCF4C9BFACFA7 -:2029E00080E062E00E949A1D8DEF94E060E00E94271E80E063E00E949A1D80EF94E060E0A6 -:202A00000E94271E8FEF99E6A8E181509040A040E1F700C00000499B04C04A9B02C04C99FC -:202A2000FACF4A9B02C00C94D21E10CF2091B9353091BA3582E02030380759F0F901EB58F1 -:202A4000FC4F80812F5F3F4F3093BA352093B93508958EE995E365E773E040E052E00E949C -:202A6000C92497FD0BC01092BA351092B93585B198E0892785B920E030E0E0CF87ED91E0A9 -:202A800081DEF1CF909155039923E1F4E82FF0E0E45DFE4FE491F0E0262F30E02E173F0763 -:202AA000B4F4AF014F5F5F4F55954795E0FD14C031972E173F0759F06417B0F0862F8F5F91 -:202AC000841B0895262F30E02131310514F080E00895862F8F5F0895E42FF0E031972E179C -:202AE0003F0751F780E00895842F860F0895FF920F931F938C01F22E0E945520882379F1A8 -:202B0000C80165E773E30E94AD1F882391F1E9ECF3E3BF2DBB0FA0E0AB58BC4F81918D938E -:202B200085E3E537F807D1F7C80165E773E30E94AD1F882311F1E5E7F3E3BF2DBB0FA0E0EC -:202B4000AF5DBA4F81918D9383E3E93CF807D1F7C8010E943D201F910F91FF90089588E030 -:202B600092E010DEC80165E773E30E94AD1F882371F68CE192E006DECACF8CE192E002DEEF -:202B8000DACF2F923F924F925F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93FB -:202BA000DF93CF93CDB7DEB760970FB6F894DEBF0FBECDBF982E792E862E809155038823B5 -:202BC00009F4B7C004E210E062E1462E512C80E090E020E0FF2458E1E52E46E1A42EB12C62 -:202BE0003CE2C32E32E0D32E1801122F88589A4CDC018C9180FF35C080919035881661F15F -:202C0000809190352DB73EB72A5030400FB6F8943EBF0FBE2DBFEDB7FEB731962FE533E0CD -:202C2000ADB7BEB712963C932E931197B382A282D582C48286821782808711860E94C23909 -:202C40004DB75EB7465F5F4F0FB6F8945EBF0FBE4DBF8FE593E096DD5E2D583109F466C030 -:202C6000F12E1F5F812F90E0821593050CF45AC0BE2DB83109F43EC080915403882361F417 -:202C800066C0EE2DF0E0E858FA4C80818E7F808380818B7F8083E394FE1498F7EDB7FEB70D -:202CA00038970FB6F894FEBF0FBEEDBF31960FE513E0ADB7BEB712961C930E93119786E130 -:202CC00090E09383828381E492E095838483868217820E94C239EDB7FEB738960FB6F894BD -:202CE000FEBF0FBEEDBF80E065E024D7C80160E044E52CD760960FB6F894DEBF0FBECDBF8C -:202D0000CF91DF911F910F91FF90EF90DF90CF90BF90AF909F908F907F905F904F903F902F -:202D20002F900895183109F4A3CF60CFF12EE12E98CFE62FF0E0E45DFE4FE4914E2E5524DE -:202D40008201000F111F01151105A1F240CFABD6D6D66B877C878D879E87FE1408F461C158 -:202D6000482D50E05A8749871A01220C331CC101880F991F880F991F880F991F820D931D77 -:202D80009C0140E050E029833A834B835C830E2DF101E457FF4F859194919C0140E050E052 -:202DA0002D833E834F8358871E2DAF2C42C0809091352091580330E040E050E069817A81A2 -:202DC0008B819C810E940A396B017C018091BB359091BC35A091BD35B091BE35C80ED91EC5 -:202DE000EA1EFB1E282D30E0429EC001439E900D529E900D1124AA2797FDA095BA2FC80E13 -:202E0000D91EEA1EFB1EC00ED11CE11CF11C2F853889322F2227330F2B583C4F892D972DEC -:202E2000B701A6010E947520882371F10F5FA01688F1402F50E0588B4F87FA01E858FA4C79 -:202E4000808180FDF3CF80915503882309F0AFCFC090BB35D090BC35E090BD35F090BE3541 -:202E6000C00ED11CE11CF11C2091580330E040E050E06D817E818F8198850E940A39C60E4E -:202E8000D71EE81EF91EC3CF86E592E07BDC0F5FA01678F6E12EFA2C80915503882309F086 -:202EA0004FC0F101E457FF4F65917491A090BB35B090BC35C090BD35D090BE35AE0CB11C20 -:202EC000C11CD11C80E090E02091580330E040E050E00E940A39A60EB71EC81ED91E0F2D65 -:202EE00010E00F5F1F4F0E191109222717FD2095322F892D972DB601A5010E9410228823FC -:202F000059F487C0F801E858FA4C80818E7F808380818B7F8083E394FE14D0F10E2D10E00A -:202F2000B801762F6627770F6B587C4F892D972D0E949E21882331F789E792E023DCE2CF52 -:202F40008091913590E0489E5001499EB00C589EB00C1124CC24B7FCC094DC2C8091BB3569 -:202F60009091BC35A091BD35B091BE35A80EB91ECA1EDB1EAE0CB11CC11CD11CB101660F02 -:202F8000771F660F771F660F771F620D731D9ACF892D972D0E945122882309F43EC089E17E -:202FA00080935D0384D5ABD5ADB7BEB71C970FB6F894BEBF0FBEADBFEDB7FEB731960FE51E -:202FC00013E012961C930E93119726E130E0338322832AE932E03583248329853A85378341 -:202FE00026832B853C854D855E85621B730B840B950B60877187828793870E94C2394DB735 -:203000005EB7445F5F4F0FB6F8945EBF0FBE4DBF6ACE86E692E0B6DB7FCF88E892E0B2DB9F -:20302000BECF282D30E03A8729871901220C331C33CF2F923F924F925F926F927F928F92FD -:203040009F92AF92BF92CF92DF92EF92FF920F931F93DF93CF93CDB7DEB7CD54D0400FB692 -:20306000F894DEBF0FBECDBF18D526DBC1D89AD678948FE79AE1A6E081509040A040E1F7FB -:2030800000C0000010D58FE79AE1A6E081509040A040E1F700C00000499B05C04A9903C0AC -:2030A0004C9901C015D989E189831C821C8E1BA21EA28E010F5F1F4FC80160E00E94B62A4B -:2030C000882309F49FC42FE5822E23E0922EEFD4499905C04A9903C04C9B01C05ADCC801A7 -:2030E0000E949B05C8010E94AE072224332480915203882309F078C0F894D0904C03C09004 -:203100004E0310925103789480915303882309F07EC080915103882351F74B9B04C0079971 -:203120006DC0F1010995499918C080911C0390911D03009771F3019790931D0380931C039F -:20314000C8010E94AE078FEF94E3ACE081509040A040E1F700C00000DCCF4A9B49C04C9937 -:20316000D8CF80914A03813009F4A3C2823009F438C2809168008860809368008091680039 -:20318000846080936800809168008460809368008091680081608093680010924C030ED64E -:2031A00001D671D9882309F4A2CF8091540391E0892790915503992309F4826082B9459A1E -:2031C000A7E8B3E11197F1F700C000004598B2E4BA95F1F700C04298E1E0E093530380919D -:2031E0005203882309F488CF8FE593E0CBDA84CF80911C0390911D0301969ECF89B180FF6E -:2032000090CF86B180FF8DCF31998DCF8ACFED2CFF242DB73EB7285030400FB6F8943EBF73 -:203220000FBE2DBFEDB7FEB73196ADB7BEB712969C928E92119786E1482E512C538242824B -:20324000B6EC6B2EB2E07B2E75826482F782E6820E94C2392DB73EB7285F3F4F0FB6F8945E -:203260003EBF0FBE2DBF88E164E064D4C40160E044E56CD4AC2CBB248DB79EB708970FB691 -:20328000F8949EBF0FBE8DBFEDB7FEB73196ADB7BEB712969C928E92119753824282ABEC65 -:2032A0004A2EA2E05A2E55824482B782A6820E94C2392DB73EB7285F3F4F0FB6F8943EBFB5 -:2032C0000FBE2DBF88E364E035D4C40160E044E53DD480914D038D1509F45CC160914D03E0 -:2032E000C8014FDCD0924D03C0924F0380E090E0FC01E858FA4C20812D7F208301968831F1 -:203300009105B1F780915103882309F0F0CE80915003882309F030C13D2D303598F7809140 -:203320005503882309F05BC1F701E45DFE4F249180915903821710F01092590386B14B991B -:2033400008C3881F8827881F8EAF2C9D902D112423969FAF2397A701440F551FCA01880F1B -:20336000991F880F991F880F991F840F951F28968FAF289729969FAF299730E02A9DC00190 -:203380002B9D900D3A9D900D11242C01662457FC6094762C27964CAE5DAE6EAE7FAE2797B6 -:2033A0000E2CEF2C000CEE1CFF08000CEE1CFF1CAA0CBB1CA294B29460EFB622BA24A62294 -:2033C000BA245E2C5A285FAE852D90E084589E4F44575F4FFA01659074902B967FAE6EAEC4 -:2033E0002B972D2D2F7321962FAF2197E22FF0E0E458FE4F34912C963FAF2C97FC01F4919E -:203400002D96FFAF2D972296DFAE22972E96CFAE2E972401F6B0F094FF1CFF24FF1C09F4CE -:2034200013C16EAC6F1461F080E464E083D3FF2009F42FC182E494E060E009D421E02EAFEB -:2034400080915D03813009F42AC180915503882309F4ABC0E0905903F8946E2C772458E71A -:20346000852E55E3952E860C971CD4018C9181FD8FC08C9182FD8CC08C9184608C9381E031 -:203480007894882309F441C080915503882309F0F7C02B966EAD7FAD2B9780915903A0904C -:2034A000BB35B090BC35C090BD35D090BE35A80EB11CC11CD11C27968CAD9DADAEADBFAD02 -:2034C0002797A80EB91ECA1EDB1E80E090E02091580330E040E050E00E940A39A60EB71E16 -:2034E000C81ED91EE0D280917535882309F4B7C0C801B601A5012E2DFADAD9D2D4018C9171 -:2035000082608C938C918B7F8C9380915903882301F5FF2059F085B1B8E08B2785B980911F -:203520005D03823018F0815080935D0320915C03275E20935C032D3708F08CC030E08091BD -:203540005A0390915B03821B930B909389008093880080915503882379F122E3F22E06C0A4 -:203560008EE40E94850FFA9409F4BCC0809151038823B1F34201BBCD80E464E0DBD288E45C -:2035800094E060E064D3809151038823E1F3BACE80E076CF80915503882309F4B3CE80918C -:2035A0004F038C1509F09ACEADCEE090590323963FAD2397E30E50CFB7E3EB2EF12C0AC067 -:2035C0008FEF0E94510F0894E108F108E114F10409F4EFC080915103882391F3CBCF22E126 -:2035E000A7CE80914B03815080934B03C80161E00E943C2A80914B03882389F0FF249F2D41 -:20360000ADE09A9FB00111246B587E4CC80141E00E945A2AF39480914B03F81680F3109258 -:203620001D0310921C03BED3C8010E949B05C8010E94AE078FEF99E6A8E181509040A040E6 -:20364000E1F700C0000053CDC80122966FAD229798DAE7CE10925C0320E030E070CF930151 -:20366000322F2227330F2B583C4FC801B601A5013CD5882309F041CF87ED91E083D83DCF19 -:2036800028969FAD289729968FAD2997692F782F04CF8CE394E060E0DAD22B9A1EAE109292 -:2036A0005D0380E065E046D286E294E060E0CFD2CCCEF0904B03AF2DBDE0AB9FC00111240F -:2036C0008B589E4C6EE173E04DE050E00E94B339F394F0924B03C8016EE173E041E00E940B -:2036E0005A2A9DCF9CE0F92E80915103882309F041CF0E94850FFA94B9F7EFEFFFEFF0935B -:203700005703E09356030E94600F0E94600F0E94600F80915103882309F02CCF8EEF0E942D -:20372000850F80915103882309F024CF22968FAD22970E94850F80915103882309F01ACF24 -:203740002E968FAD2E970E94850F80915103882309F010CF809159038F5F0E94850F8091E4 -:203760005103882309F006CF82E00E94850FF09056038091570390915103992309F0FACEAE -:203780000E94850F80915103882309F0F3CE8F2D0E94850FFF2408C08EE40E94850FF3941D -:2037A000FF2DF63109F4F1C0809151038823A1F3E1CE80915803823009F4E4C0F2E0FF2EF7 -:2037C000E090590380915103882309F0D3CE85ED0E94510F80915103882309F0CBCE8AEAE9 -:2037E0000E94510F80915103882309F0C3CE86E90E94510F80915103882309F0BBCE2C9668 -:203800008FAD2C970E94510F80915103882309F0B1CEE0915903F0E0E458FE4F84910E9442 -:20382000510F80915103882309F0A4CE2D968FAD2D970E94510F80915103882309F09ACE77 -:20384000EF2DF0E0E458FE4F84910E94510F80915103882309F08ECE2196EFAD2197EE2559 -:203860002FADE227EF25EF73F0E0E458FE4F84910E94510F80915103882309F07BCE8EEDB0 -:203880000E94510F80915103882309F073CE8AEA0E94510FEAE0FE2E80915103882309F067 -:2038A00069CE8FEF0E94510FFA94B1F780915103882309F05FCE85ED0E94510F809151030C -:2038C000882309F057CE8AEA0E94510F80915103882309F04FCE8DEA0E94510F80915103A5 -:2038E000882309F047CEE0915903F0E0E458FE4F84910E94510FC301982F8827990F8B580D -:203900009C4F0E94AC0F80915103882309F032CE8EED0E94510F80915103882309F02ACED8 -:203920008AEA0E94510F80915103882309F022CE8FEF0E94510F22968FAD2297609159039E -:20394000A1D8809359034B9B65CD2296DFAC229742014598429A10925303C8016D2D11D92A -:203960008FE79AE1A6E081509040A040E1F700C000000E945C13C8010E949B05C8010E9430 -:20398000AE07B5CBA2E2FA2E1BCFFF2480915103882309F0EFCD0E94850FF3942F2D2C30FF -:2039A000A9F78FEF9FEF90935703809356030E94600F0E94600F0E94600F8091510388232F -:2039C00009F0D8CD8BEF0E94850F6301DC2CCC24DD0CA5E7B3E0CA0EDB1EEE24FF240AC065 -:2039E0000E94850F0894E11CF11CF0E0EF16F2E0FF06B9F1F60181916F01909151039923EB -:203A000079F3B8CDADB7BEB71A970FB6F894BEBF0FBEADBFEDB7FEB731969FE5892E93E056 -:203A2000992E12969C928E92119786E190E09383828382EB92E09583848389818683178285 -:203A40008B81808711860E94C239EDB7FEB73A960FB6F894FEBF0FBEEDBFC4010E94C21333 -:203A600036CBF09056038091570390915103992309F080CD0E94850F80915103882309F04B -:203A800079CD8F2D0E94850F56CF81E090E00C94770980E090E00C94770914BC83E085BD73 -:203AA00081E085BB089581E080936E00089510926E0008951F920F920FB60F9211248F938D -:203AC0009F93AF93BF938091C3359091C435A091C535B091C6350196A11DB11D8093C33568 -:203AE0009093C435A093C535B093C635BF91AF919F918F910F900FBE0F901F9018952FB712 -:203B0000F8946091C3357091C4358091C5359091C6352FBF089590E59CBD1DBC882341F001 -:203B20005E9A2A986EBD0DB407FEFDCF2A9A08955E98F7CF1F93162F682F606880E0EBDF71 -:203B4000612F606480E0E7DF1F910895AF92BF92CF92DF92EF92FF920F931F93CF93DF9300 -:203B6000D62EC42EE82EF92EBB248FE7A82EF70101917F01002359F4DF91CF911F910F914D -:203B8000FF90EF90DF90CF90BF90AF900895BC1498F70D3609F183E0089F80011124E801D9 -:203BA000CB52DA4F09521A4FFE016491660FD1106A2581E0B0DFB394C017D10749F4BC142F -:203BC000B0F6DD20C1F16FE781E0A5DFB394CFCF2196BC1460F6E8CFDD2079F163E481E0CD -:203BE0009ADFB394BC1408F0C2CFDD2051F16BE781E091DFB394BC1408F0B9CFDD2029F19C -:203C000067E681E088DFB394BC1408F0B0CFDD20D1F06BE781E07FDFB394BC1408F0A7CFAD -:203C2000DD2069F067E481E076DFB394BC1408F09ECFDD2041F660E0C7CF6CE3D0CF68E36E -:203C4000F2CF64E0D5CF64E0E5CF68E1DACFCF92DF92EF92FF920F931F93CF93DF93D62EC1 -:203C60008C010F5F1F4F2FE7C22EF8013197E491EE2331F1ED3679F183E0E89FF0011124CF -:203C8000EF01CB52DA4F98EDE92E95E0F92EEE0EFF1EFE016491660FD1106C2581E03BDF47 -:203CA0002196CE15DF05A9F7DD2099F06FE781E032DF0F5F1F4FF8013197E491EE23D1F6AE -:203CC000DF91CF911F910F91FF90EF90DF90CF90089560E0ECCFDD2089F081E063E41BDF38 -:203CE00081E06BE718DF81E067E615DF81E06BE712DF81E067E40FDF6FE7D9CF81E06CE38C -:203D00000ADF81E064E007DF81E068E104DF81E064E001DF81E068E3FEDE60E0C8CFEF923D -:203D2000FF920F931F93CF93DF93E82EF92EF70101917F010023E1F00D3609F183E0089F48 -:203D400080011124E801CB52DA4F08521A4FFE016491606481E0DFDE2196C017D107B9F7CF -:203D600081E060E4D8DEF70101917F01002321F7DF91CF911F910F91FF90EF90089581E077 -:203D80006EE5C9DE81E062E4C6DE81E06CE4C3DE81E062E4C0DE81E06CE5BDDE81E060E455 -:203DA000BADEC5CFCF93DF93C8EFD1E081E060E0B2DE2197D9F7DF91CF9108958FEB8093E8 -:203DC000C73584E18093C83584E08093C935569A279A259A229A209A2A98289A8FE798E3A2 -:203DE000A1E081509040A040E1F700C0000028988FE798E3A1E081509040A040E1F700C0DE -:203E00000000289A8FE798E3A1E081509040A040E1F700C0000080E090E00E94023C813FE5 -:203E2000E1F080E090E061EF0E940A3C6091C73581E090E00E940A3C80E061E26CDE609125 -:203E4000C73580E068DE6091C83580E064DE80E060E261DE80E06CE05ECE81E090E00E9404 -:203E6000023C8093C735E8CFFC014181842F90E09C013595279520652CBD40FD06C081E067 -:203E8000463019F08DBD2C98089580E08DBD2C980895BF92CF92DF92EF92FF920F931F9364 -:203EA000CF93DF938C016B017A0129DEEB01BB24BA94BEBC0DB407FEFDCF8EB5F80182834D -:203EC0008F3FB1F41CDE6C1B7D0B81E06D32780780F381E1F80180832C9A80E0DF91CF9120 -:203EE0001F910F91FF90EF90DF90CF90BF9008958E3F19F08FE08083EFCFE114F104F1F0D9 -:203F00000894E108F1088FEF8EBDE114F10471F0F60180E090E03FEF0DB407FEFDCF2EB5A5 -:203F200021933EBD01968E159F05B0F30DB407FEFDCF8EB5F601EE0DFF1D80838FEF8EBDA2 -:203F40000DB407FEFDCF8EB58FEF8EBD0DB407FEFDCF8EB52C9A81E0C1CF0F931F93CF9381 -:203F6000DF93EC018B0180DFCE01B80140E052E090DFDF91CF911F910F910895FF920F93BE -:203F80001F93CF93DF93EB01BADD8B01FF24FA94FEBC0DB407FEFDCF8EB58F3F69F0AFDD99 -:203FA000601B710B6C177D0798F380E0DF91CF911F910F91FF90089581E0DF91CF911F91EB -:203FC0000F91FF900895DF92EF92FF920F931F93CF93DF93EC01D62E79018A0145DFCE0181 -:203FE0006CE271E0CBDF8D2D80648EBD0DB407FEFDCF28E130E0D801C701022E04C0B69504 -:20400000A795979587950A94D2F78EBD0DB407FEFDCF285030408FEF283F380761F7DD2077 -:20402000E9F08D2D883001F587E88EBD0DB407FEFDCF8D2D8C30D1F02FEF9FEF9EBD0DB4F4 -:2040400007FEFDCF8EB58A8387FD0AC0DF91CF911F910F91FF90EF90DF90089585E9E5CF95 -:204060002223A1F32150EACF8FEFDFCF8FEF8EBD0DB407FEFDCF8EB5DFCFCF93DF93EC0104 -:20408000F3DECE016CE020E030E0A9019CDF882339F083E088832C9A80E0DF91CF9108952A -:2040A0002C9A81E0DF91CF910895CF93DF93EC019A01AB018B81833039F069E0220F331FB0 -:2040C000441F551F6A95D1F7CE0162E17CDF882339F085E088832C9A80E0DF91CF910895FE -:2040E0002C9A81E0DF91CF910895CF92DF92EF92FF920F931F93CF93DF93EC017A018B012C -:2041000069018B81833039F0A9E0EE0CFF1C001F111FAA95D1F7CE0161E1A801970153DFD5 -:20412000882369F084E088832C9A80E0DF91CF911F910F91FF90EF90DF90CF900895CE017E -:20414000B60140E052E0A5DEF1CF8F929F92BF92CF92DF92EF92FF920F931F93DF93CF9364 -:204160000F92CDB7DEB74C01B62EFC0113821082C6DC8B01249A2C9A2698259A279A249A82 -:204180002C9A85E0F401818382E58CBD1DBC8AE09FEF9EBD0DB407FEFDCF8150D1F7C4012F -:2041A00060E020E030E0A9010EDF782FF40182838130C9F0A4DC601B710BF7E0613D7F079B -:2041C00070F381E0F40180832C9A80E00F90CF91DF911F910F91FF90EF90DF90CF90BF9013 -:2041E0009F908F900895C40168E02AEA31E040E050E07983E8DE798182FF1FC0F40173834B -:20420000CC24DD247601C40167E320E030E0A901DADEC40169E2A7019601D5DEF4018283B9 -:204220008823D9F06CDC601B710BF7E0613D7F0750F38AE0F4018083C7CF84E02FEF2EBD28 -:204240000DB407FEFDCF9EB5F40192838150B9F79A3A79F082E08083B7CF83818230B1F06F -:204260002C9AFB2DF73070F088E1F401808380E0ADCF82E0F4018383C12CD12CE12CB0E4A4 -:20428000FB2EC1CFF401B18281E0A0CFC4016AE320E030E0A90197DE882321F088E0F40113 -:2042A000808392CF8FEF8EBD0DB407FEFDCF8EB5807C803C19F483E0F401838383E09FEFE8 -:2042C0009EBD0DB407FEFDCF2EB58150C9F7C8CFFC016EBDA42FB52F80E090E00DB407FE71 -:2042E000FDCF2C912EBD0DB407FEFDCF11962C9111972EBD0296129622E08030920771F7CE -:204300000DB407FEFDCF8FEF8EBD0DB407FEFDCF8FEF8EBD0DB407FEFDCF8FEF8EBD0DB4CB -:2043200007FEFDCF8EB582838F71853029F083E180832C9A80E0089581E008950F931F931A -:20434000CF93DF93EC018B018FDDCE0168E572E015DE882349F485E188832C9A80E0DF9154 -:20436000CF911F910F910895CE016CEFA801B0DF882389F32C9A81E0DF91CF911F910F9120 -:204380000895CF92DF92EF92FF920F931F93CF93DF93EC017A018B0169018B81833039F02E -:2043A00089E0EE0CFF1C001F111F8A95D1F7CE0168E1A801970107DE882369F086E0888396 -:2043C0002C9A80E0DF91CF911F910F91FF90EF90DF90CF900895CE016EEFA60179DF882348 -:2043E00079F3CE0168E572E0C9DD882319F487E18883E6CFCE016DE020E030E0A901E3DDC7 -:20440000882319F086E18883DBCF8FEF8EBD0DB407FEFDCF8EB58823A9F72C9A81E0D2CF1B -:20442000AF92BF92CF92DF92EF92FF920F931F93CF93DF93EC015A016B017801890167E3DD -:2044400020E030E0A901BFDDCE0167E1A8019701BADD882379F089E088832C9A80E0DF91F9 -:20446000CF911F910F91FF90EF90DF90CF90BF90AF9008958B81833039F099E0AA0CBB1C97 -:20448000CC1CDD1C9A95D1F7CE0169E1A60195019ADD882319F087E08883DFCF2C9A81E07C -:2044A000DECFCF93DF93EC01DFDCCE0168E572E065DD882359F08DEF8EBD0DB407FEFDCFD6 -:2044C000CE0168E572E05ADD882339F482E188832C9A80E0DF91CF9108952C9A81E0DF91C7 -:2044E000CF910895CF93DF93EC019C012C5F3F4F898D9A8D41E050E060E070E00E94042D57 -:204500008823D9F08D899E89AF89B88D0097A105B10579F48C819D81AE81BF818D8B9E8B32 -:20452000AF8BB88F89818068898381E0DF91CF91089581E0DF91CF91089580E0DF91CF9130 -:204540000895CF92DF92EF92FF921F93CF93DF93EC0189899A89AB89BC89803E2FEF920744 -:204560002FE1A20720E0B20748F080E0DF91CF911F91FF90EF90DF90CF900895CE01B2DFD8 -:20458000882399F30E94D82A882379F3E98DFA8DCC80DD80EE80FF808EEF9FEFAFEFBFEF3F -:2045A000C80ED91EEA1EFB1E058404C0CC0CDD1CEE1CFF1C0A94D2F786859785A089B189D9 -:2045C000C80ED91EEA1EFB1E81E08093D637C092D035D092D135E092D235F092D33580E04A -:2045E00092E0E4EDF5E3DF019C011D9221503040E1F7E98DFA8D84818230C0F011E006C0A0 -:204600001F5FE98DFA8D8481181780F4B701A601410F511D611D711D8091D4379091D53705 -:2046200024ED35E3AEDE882359F79FCF20E032E040E050E0058404C0220F331F441F551F53 -:204640000A94D2F789899A89AB89BC89820F931FA41FB51F898B9A8BAB8BBC8B81E086CFFF -:20466000CF93DF93EC018C859D85AE85BF8541E0662309F440E0BC01CD01DAD7882381F0B0 -:20468000288930E0220F331F22953295307F3227207F32272C523A4CC901DF91CF9108951D -:2046A00020E030E0C901DF91CF9108956F927F928F929F92AF92BF92CF92DF92EF92FF92D9 -:2046C0000F931F93DF93CF9300D000D0CDB7DEB76C014B013A01DC015596ED90FD900D9195 -:2046E0001C915897E114F10401051105F1F05E010894A11CB11C10C0D801C7010196A11DEC -:20470000B11D29813A814B815C8182179307A407B507F9F47C018D01F601818D928DB8014E -:20472000A7019501CAD7882339F780E00F900F900F900F90CF91DF911F910F91FF90EF90B5 -:20474000DF90CF90BF90AF909F908F907F906F900895D60159966D917C915A97FB01878936 -:20476000803109F44CC0283F8FEF38078FEF48078FE05807D0F2F60185899689A789B08D6D -:204780000297A109B109FB01058404C0880F991FAA1FBB1F0A94D2F7268537854089518970 -:2047A000820F931FA41FB51FF40180839183A283B383FB0186859785A089B1890197A109F0 -:2047C000B1092481820F911DA11DB11DA80197012250304040405040058404C0220F331FAC -:2047E000441F551F0A94D2F7820F931FA41FB51FF30180839183A283B38381E097CF283F0D -:20480000FFEF3F07F0E04F07F0E05F0708F0B3CF8CCFE82FF92F80E090E03EE209C0DB015F -:20482000A90FB11D2C939F5F8F5F31968B3061F020812032C9F3883091F7DB01A90FB11D23 -:204840003C939F5F2081EBCF690F711DFB01108208951F93FB012BE030E231932150E9F71F -:20486000A82FB92F30E017E09A2F8B2F2D91222351F4FA019083818381E0FB019081903265 -:2048800079F01F9108952F32A1F32E3261F082E597E0FC010196E491EE2351F02E17C9F77E -:2048A00080E01F9108951A30D9F338E01AE0DCCF1317B0F32132A0F32F3790F7FB01E30FEA -:2048C000F11D822F81568A3108F4205220833F5FCBCF0F931F93CF93DF93EC018B018B8191 -:2048E000882331F4FB018789803141F08032F1F180E0DF91CF911F910F91089582E08B83D9 -:204900001D8A1E8A1F8A188E808D918DA0E0B0E0880F991FAA1FBB1F880F991FAA1FBB1FDA -:20492000880F991FAA1FBB1F880F991FAA1FBB1F880F991FAA1FBB1F898B9A8BAB8BBC8BEB -:204940001A8F098F81E089831C821D821E821F82188619861A861B861C861D861E861F861F -:20496000188ADF91CF911F910F91089583E08B83F801428D538D648D758D4D8B5E8B6F8B11 -:20498000788F9E012F5E3F4FC80124D78823C1F6AFCF2F923F924F925F926F927F928F921B -:2049A0009F92AF92BF92CF92DF92EF92FF920F931F93CF93DF938C01362FE72F2A01DC0118 -:2049C00013962C911397222329F011968C91119780FD16C02FEF3FEFC901DF91CF911F9114 -:2049E0000F91FF90EF90DF90CF90BF90AF909F908F907F906F905F904F903F902F90089558 -:204A0000E801C988DA88EB88FC88488559856A857B854201AA24BB24D701C601841B950B9B -:204A2000A60BB70B88169906AA06BB0608F093C04114510409F4BEC0832E9E2E6201A4E081 -:204A40002A2E312C200E311E612CF2E07F2E60C0FF2009F07AC0411551056105710509F025 -:204A6000ABC0E8018D899E89AF89B88D8C839D83AE83BF8346855785608971894F0D511D32 -:204A8000611D711D0297A109B109058404C0880F991FAA1FBB1F0A94D2F7480F591F6A1F0F -:204AA0007B1FE301CA19DB09CC16DD0608F4E601E2E0C030DE0709F452C0CB01BA0140E0BC -:204AC000B7D5882309F486CF95012C523A4CC401B901AE010E949C39AE0160E070E0F801D6 -:204AE00080859185A285B385480F591F6A1F7B1FD80118964D935D936D937C931B97CC1A4C -:204B0000DD0A09F457C08C0E9D1E13962C911397EFEFAE2EE1E0BE2EA422B5222230B9F135 -:204B2000D8015996ED91FC915A97DB01CA0129E0B695A795979587952A95D1F7F480FA94A9 -:204B4000F822A114B10409F483CFE8018C819D81AE81BF818FCF2601441A550A69CF809174 -:204B6000D0359091D135A091D235B091D335481759076A077B0709F4A0CF8091D43790912D -:204B8000D5379401B2DA882309F0A6CF23CF39E076956795579547953A95D1F7E801E98DFF -:204BA000FA8D828D938DA48DB58D480F591F6A1F7B1F77CF920110CFD80114964D915D91D3 -:204BC0006D917C911797CF01910177D5882309F401CFE801E98DFA8D8C819D81AE81BF8176 -:204BE00049CFDF93CF930F92CDB7DEB7BE016F5F7F4F41E050E0CDDE8130910539F02FEF2A -:204C00003FEFC9010F90CF91DF910895298130E0C9010F90CF91DF910895EF92FF920F934C -:204C20001F93CF93DF93EC018B81823050F420E030E0C901DF91CF911F910F91FF90EF90F7 -:204C40000895E884F9840A851B85CE01CADF97FDEECF88859985AA85BB854F96A11DB11DCB -:204C600088879987AA87BB87D801C70115E0B695A795979587951A95D1F78F70282F30E050 -:204C8000220F331F22953295307F3227207F32272C523A4CCECF8F929F92AF92BF92CF922D -:204CA000DF92EF92FF920F931F93CF93DF93EC014A015B012B81222309F465C089899A896D -:204CC000AB89BC8984179507A607B70708F45BC0223009F452C081149104A104B10409F4C0 -:204CE0006AC0488559856A857B85E98DFA8D258530E0275F3F4FDB01CA010197A109B10982 -:204D0000022E04C0B695A795979587950A94D2F7850174010894E108F1080109110904C008 -:204D200016950795F794E7942A95D2F7E816F9060A071B07B0F58D899E89AF89B88D8C8300 -:204D40009D83AE83BF8384E0C82ED12CCC0EDD1E0FC04C815D816E817F81898D9A8D960157 -:204D6000ACD40894E108F10801091109882359F0E114F1040105110561F788869986AA8662 -:204D8000BB8681E001C080E0DF91CF911F910F91FF90EF90DF90CF90BF90AF909F908F9078 -:204DA0000895411551056105710529F2E81AF90A0A0B1B0BC8CF1C821D821E821F821886C0 -:204DC00019861A861B8681E0DFCF0F931F93CF93DF93EC018B81882349F0898187FD0EC083 -:204DE000E7D3DF91CF911F910F91089581E0888380E0DF91CF911F910F910895CE0161E0A3 -:204E00002FDC8C01009791F3FC018081853E71F38B818230F8F08D899E89AF89B88DF80161 -:204E2000938F828FB58BA48BE091CC35F091CD35309759F0B8016A5E7F4FC8014896099537 -:204E4000F801808D918D938B828B89818F778983AFD3C7CF89899A89AB89BC89848F958FEA -:204E6000A68FB78FD8CFCF93DF93EC01AEDF1B82DF91CF9108956F927F928F929F92AF9213 -:204E8000BF92CF92DF92EF92FF920F931F93DF93CF9300D000D0CDB7DEB77C015A016B01B8 -:204EA000DC0113968C9113978130A1F080E00F900F900F900F90CF91DF911F910F91FF90D8 -:204EC000EF90DF90CF90BF90AF909F908F907F906F90089511968C91119781FFE7CFF70164 -:204EE00081899289A389B48984179507A607B707E8F20097A105B10529F1F70160847184CA -:204F000082849384C701B601A501C5DE882371F2A114B104C104D104B9F4D70155964D914C -:204F20005D916D917C91589759968D919C915A97A3D6882309F4BACFF701158A168A178ADC -:204F4000108E40C081E0B3CFD70114964D915D916D917C91179759968D919C915A979E01FF -:204F60002F5F3F4FAAD3882309F4A0CFD7015996ED91FC915A9749815A816B817C81878920 -:204F80008031C9F1483F8FEF58078FEF68078FE07807C0F4CF0170D6882309F487CFD701C7 -:204FA00014964D915D916D917C91179759968D919C915A970FEF1FEF2FEF3FE086D4882349 -:204FC00009F474CFF701A18AB28AC38AD48A818180688183C701F9DE882309F467CFB60165 -:204FE000A5016A147B048C049D0410F4B401A301C70151DE5CCF483FBFEF5B07B0E06B07C5 -:20500000B0E07B07F8F6C6CF1F93CF93DF93EC01142FE62FF0E0EE0FFF1FE295F295F07FD8 -:20502000FE27E07FFE27DF01AC52BA4C1B968C911B97817149F0842F827131F01B8280E074 -:20504000DF91CF911F9108958091D0359091D135A091D235B091D3358C879D87AE87BF87C3 -:20506000688BEC52FA4C84899589A0E0B0E0DC01992788278D8B9E8BAF8BB88F428D538DC1 -:2050800060E070E0482B592B6A2B7B2B4D8B5E8B6F8B788F838590E0887190700097F1F49F -:2050A000848D958DA68DB78D898B9A8BAB8BBC8B81E08B83812F8F7089831C821D821E8289 -:2050C0001F82188619861A861B8614FD17C015FD1EC081E0DF91CF911F9108958031910514 -:2050E00009F0ACCF9E012F5E3F4F898D9A8D72D3882309F4A3CF84E08B83DCCFCE0140E0DA -:2051000050E0BA01B8DE882311F780E099CF49895A896B897C89CE01BEDD92CF8F929F92C8 -:20512000AF92BF92CF92DF92EF92FF920F931F93CF93DF935C01EB01C42E952E822E898D0D -:205140009A8DD5015A969C938E935997CB0140E050E0BA01A0DDDD24E884F9840A851B85B5 -:2051600089899A89AB89BC89E816F9060A071B0708F040C0CE0151DDFC01009709F476C095 -:20518000D801C70115E0B695A795979587951A95D1F7182F1F708081882391F0853E81F0FC -:2051A0008C2D992DBF014BE050E00E948F39009799F687FC5BC0C501612F482D25DF57C041 -:2051C000DD20A9F42091D0353091D1354091D2355091D335D5011C962D933D934D935C9310 -:2051E0001F9750961C9350978081DD24D394882309F0B2CF86FE3AC081FE38C0DD2009F004 -:2052000043C08B81823091F1CE019BD9882371F1C4EDD5E310E07E01EC2FFF2D80E2DF019A -:205220001D928A95E9F7DE018C2D992DFC018BE001900D928150E1F7E091CC35F091CD352C -:20524000309761F1BE01625F7F4FCE0140960995888999892E853F859B8B8A8B998F888F80 -:205260003F8B2E8BA5D1882309F0A5CF80E0DF91CF911F910F91FF90EF90DF90CF90BF9072 -:20528000AF909F908F900895F5011089C50161E0E7D9EC01009709F0BECFE8CF81E298E2F0 -:2052A000998B888B80E098E09F878E8720E038E081E298E2D1CF2F923F924F925F926F92AA -:2052C0007F928F929F92AF92BF92CF92DF92EF92FF920F931F93DF93CF93CDB7DEB7C4549C -:2052E000D0400FB6F894DEBF0FBECDBF2C013B018E010E5B1F4FD80111965C934E9325967D -:205300002FAF25971C861F861FA21AA66115710509F45FC0FC018381882309F05AC0CA0199 -:20532000DA012C912F3209F470C073013CE0832E912C8C0E9D1E64015E010894A11CB11C0A -:2053400027E2222E312C2C0E3D1EB501A80181DA882369F1D801ED91FC91119780818F32F5 -:2053600041F43196D8011196FC93EE9381918F32C9F3882309F46FC0C601B701A50121E015 -:20538000CDDE8823A1F0E614F70421F0C7011DDDF7011382C814D904C9F076016401D801AA -:2053A0008D919C91B501A80154DA882399F600E08AA5882321F0CE01879607DD1AA68F856C -:2053C000882341F0CE010C9600DD04C061017401E6CF00E0802FCC5BDF4F0FB6F894DEBF81 -:2053E0000FBECDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF909F908F907F906F906E -:205400005F904F903F902F9008959A012F5F3F4FC901F80131832083D9014C912F5F3F4FEF -:205420004F32B1F3F30123812250223008F47DCF87E2E82EF12CEC0EFD1ED30159966D9131 -:205440007C915A97C70145DA882309F4B0CFF801808191816BCFC201B701A50125962FAD42 -:2054600025975CDE082FA4CFFB01242F6091CA357091CB35AF011FCF0F931F93CF93DF9386 -:20548000EC01662399F08C010E5D1F4F1093CB350093CA35C801E7DCBE016C5F7F4FC801C5 -:2054A00018DADF91CF911F910F9108958C010E5D1F4FF0CFDF92EF92FF920F931F93DF93CF -:2054C000CF93CDB7DEB76C970FB6F894DEBF0FBECDBFFB01D42E19821C8220812F3229F1B4 -:2054E00022E2E22EF12CE80EF91E8E010F5F1F4FC801B701AF0121E0DEDE8823F1F08C817C -:20550000823070F1D701F8018BE101900D928150E1F7DD2021F0F092CB35E092CA3521E060 -:20552000C8012C8FA0DC2C8D0CC021812223C1F6642FA2DF282F8C8102C08C8120E0882356 -:2055400089F4822F6C960FB6F894DEBF0FBECDBFCF91DF911F910F91FF90EF90DF9008959A -:2055600020E0EDCF8E010F5F1F4FDACF0F931F93CF93DF938C010E94A520882331F480E00F -:20558000DF91CF911F910F910895E8012496CE01B80141E0CDD3882321F0C80161E06CDF51 -:2055A000EFCFCE01B80140E0C3D3882341F3F5CF8091D637882311F481E008954091D035AA -:2055C0005091D1356091D2357091D3358091D4379091D53724ED35E30E94C121882321F130 -:2055E0004091D7375091D8376091D9377091DA37411551056105710521F41092D63781E01C -:2056000008958091D4379091D53724ED35E30E94C121882359F01092D7371092D837109200 -:20562000D9371092DA37E9CF80E0089580E00895DF92EF92FF920F931F937B018C01D42E13 -:205640008091D0359091D135A091D235B091D3358E159F05A007B107F1F0AADF882339F4A4 -:2056600080E01F910F91FF90EF90DF9008958091D4379091D537B801A70124ED35E30E94EB -:205680007520882369F3E092D035F092D1350093D2351093D335DD2049F081E08093D63773 -:2056A0001F910F91FF90EF90DF90089581E01F910F91FF90EF90DF900895CF92DF92EF9262 -:2056C000FF920F931F93CF93DF93EC017A018B01690189859A85AB85BC850196A11DB11DF2 -:2056E00084179507A607B70730F0EF89E03169F0E03209F445C080E0DF91CF911F910F9172 -:20570000FF90EF90DF90CF9008959927872F762F652F2B893C894D895E89620F731F841F85 -:20572000951F2091D0353091D1354091D2355091D335621773078407950729F040E078DFCD -:205740008823C9F2EF89E03169F18FE790E0A0E0B0E0E822F9220A231B23F701EE0FFF1F67 -:20576000EE0FFF1FEC52FA4C80819181A281B381BF70F60180839183A283B38381E0BCCF9C -:20578000CB01BA0127E096958795779567952A95D1F72B893C894D895E89620F731F841FC9 -:2057A000951FBFCF8FEF90E0A0E0B0E0E822F9220A231B23F701EE0FFF1FEC52FA4C808181 -:2057C0009181A0E0B0E0F60180839183A283B38381E092CF4F925F926F927F928F929F9246 -:2057E000AF92BF92CF92DF92EF92FF920F931F93DF93CF9300D000D0CDB7DEB78C014983F9 -:205800005A836B837C832901842F952FA62FB72FAC01BD01CC24DD2476015E010894A11CD7 -:20582000B11C612CE2E07E2E812C912CC801950144DF882309F447C0D401C301F8010584EA -:2058400004C0880F991FAA1FBB1F0A94D2F7C80ED91EEA1EFB1E49815A816B817C8187899F -:20586000803119F1483F8FEF58078FEF68078FE07807E0F2F201C082D182E282F38281E09A -:205880000F900F900F900F90CF91DF911F910F91FF90EF90DF90CF90BF90AF909F908F90B4 -:2058A0007F906F905F904F900895483FFFEF5F07F0E06F07F0E07F07E8F6C8019501FDDEE0 -:2058C000882309F0B9CF80E0DBCF4F925F926F927F928F929F92AF92BF92CF92DF92EF9277 -:2058E000FF920F931F93CF93DF93EC016A017B0128013901423051056105710590F0898586 -:205900009A85AB85BC850196A11DB11D84179507A607B70730F08F89803109F456C0803284 -:2059200091F080E0DF91CF911F910F91FF90EF90DF90CF90BF90AF909F908F907F906F90A0 -:205940005F904F9008954A015B0117E0B694A794979487941A95D1F78B899C89AD89BE8946 -:20596000880E991EAA1EBB1EC501B40141E060DE8823B9F28F898031A9F18FE790E0A0E040 -:20598000B0E0C822D922EA22FB22F601EE0FFF1FEE0FFF1FEC52FA4C40825182628273824A -:2059A0008A89823078F18D819E81AF81B885880D991DAA1DBB1D8093D7379093D837A093AF -:2059C000D937B093DA3781E0ADCF852E962EA72EBB248B899C89AD89BE89880E991EAA1E90 -:2059E000BB1EC2CF8FEF90E0A0E0B0E0C822D922EA22FB22F601EE0FFF1FEC52FA4C5182C8 -:205A00004082CECF81E08ECF2F923F924F925F926F927F928F929F92AF92BF92CF92DF923D -:205A2000EF92FF920F931F93DF93CF93CDB7DEB767970FB6F894DEBF0FBECDBF1C014987E1 -:205A40005A876B877C873E872D87FC0181859285A385B4859C01AD012F5F3F4F4F4F5F4FC9 -:205A60002D833E834F835887ED85FE854080518062807380411451046104710409F4BEC0AA -:205A80000894411C511C611C711C1F860097A105B10509F454C0D301C201CC24DD247601EE -:205AA0008E010F5F1F4F4C8A5D8A6E8A7F8A2EC04C015D01C101B501A4019801FEDD8823E8 -:205AC00009F43DC089819A81AB81BC810097A105B10509F44EC0A50194012F5F3F4F4F4F4B -:205AE0005F4F2C8B3D8B4E8B5F8BDA01C9010894C11CD11CE11CF11CF1012185328543858A -:205B00005485C216D306E406F506C8F44D805E806F807884481659066A067B0648F682E076 -:205B2000882E912CA12CB12C8C8A9D8AAE8ABF8AC101B501A4019801C0DD882319F680E01D -:205B400067960FB6F894DEBF0FBECDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF9077 -:205B60009F908F907F906F905F904F903F902F900895D501C4010196A11DB11D2C013D01A7 -:205B80002C893D894E895F89421A530A640A750A29853A854B855C85421653066406750671 -:205BA00009F0A5CF4C885D886E887F88C101B501A4010FEF1FEF2FEF3FE087DE882309F44F -:205BC000BECF481459046A047B0458F59501840107C0970186014C145D046E047F0408F591 -:205BE000680179010894C108D108E108F108C101B701A6016ADE882361F7A1CFF101408014 -:205C0000518062807380F1E0FF8729853A854B855C85213031054105510509F437CF1F869E -:205C200035CFAD85BE854D915D916D917C9113974115510561057105C1F4ED85FE85408276 -:205C4000518262827382FF85FF2369F00894411C511C611C711CD1014D925D926D927C927C -:205C6000139781E06DCF81E06BCFC101930182012CDE882311F763CFAF92BF92CF92DF9216 -:205C8000EF92FF920F931F93DF93CF9300D000D0CDB7DEB76C017A018B0182E090E0A0E04B -:205CA000B0E0F60180839183A283B3835E010894A11CB11CC601B801A7019501FEDC882323 -:205CC00039F1C601B801A70100E010E09801FDDD8823F1F0E980FA800B811C81F601878990 -:205CE000803159F088EFE8168FEFF8068FEF08078FE01807F8F281E00CC0F8EFEF16FFEFAD -:205D0000FF06F0E00F07F0E01F07A0F281E001C080E00F900F900F900F90CF91DF911F9192 -:205D20000F91FF90EF90DF90CF90BF90AF9008956F927F928F929F92AF92BF92DF92EF92D4 -:205D4000FF920F931F93CF93DF93EC01142F7093D5376093D4371F8A82E090E0A0E0B0E0C2 -:205D600088839983AA83BB831092D6371092D7371092D8371092D9371092DA378FEF9FEF10 -:205D8000DC018093D0359093D135A093D235B093D335442309F444C0453078F080E0DF914B -:205DA000CF911F910F91FF90EF90DF90BF90AF909F908F907F906F90089560E070E0CB01D3 -:205DC00040E036DC882351F3212F30E022953295307F3227207F32272C533A4CF901E2548F -:205DE000FE4F808190E08F7790700097B9F6F901E653FE4F80819181A281B381843691055F -:205E0000A105B10558F22A533E4FF901E080F18002811381E114F1040105110521F4BECF48 -:205E2000EE24FF248701C801B70140E001DC882309F4B4CF8091DF359091E035F2E080301F -:205E40009F0709F0ABCF2091E435222309F4A6CF8091E2359091E335009709F49FCF609154 -:205E6000E135662309F49ACF2A8B6C831D8670E080E090E041E050E008C0282F2F5F2D8704 -:205E800001968930910509F489CFD82E9A01082E02C0220F331F0A94E2F72617370769F759 -:205EA0006091EA357091EB356115710509F47FC080E090E06D837E838F8398878090E23570 -:205EC0009090E335AA24BB248E0C9F1CA01EB11E8B8A9C8AAD8ABE8A6090E5357090E6351C -:205EE000798E688E2091E43530E040E050E00E940A39680D791D8A1D9B1D6A8F7B8F8C8F0E -:205F00009D8F9301220F331F22953295307F3227207F322721503E4F232F3327269540E03B -:205F200050E0260F371F481F591F2E873F87488B598B8091E7359091E835009709F440C096 -:205F4000A0E0B0E0E21AF30A040B150BE80EF91E0A1F1B1F04C016950795F794E794DA941A -:205F6000D2F7E986FA860B871C8725EFE2162FE0F20620E0020720E0120758F185EFE81644 -:205F80008FEFF80680E0080780E0180730F18091003690910136A0910236B09103368A8FDB -:205FA0009B8FAC8FBD8F80E28F8B81E0F8CE6091F8357091F9358091FA359091FB357ACF66 -:205FC0008091F4359091F535A091F635B091F735B9CF8CE08F8B80E0E2CE80E18F8B81E079 -:205FE000DECECF93DF93DC01CD91DC9111971C161D06DCF41296E0E0F0E020E030E0A901BA -:20600000542F432F322F22276D9170E080E090E0262B372B482B592B3196EC17FD0781F7D3 -:20602000B901CA01DF91CF91089520E030E0A901F7CFCF93DF93FB01DC012D913C91B901FC -:206040006E5F7F4FEC01C60FD71FE60FF71FD9011196A40FB51F2115310599F02150304004 -:206060008A9192914115510519F06C91862396231197891781F320E030E0C901DF91CF9168 -:20608000089521E030E0C901DF91CF910895CF93DF93FB0120813181DC012D933C93A0816B -:2060A000B181109701F1BD01615070401296EA0FFB1FEA01CA0FDB1FA80FB91F80E09A9163 -:2060C000229130E0290F311D280F311D81E02F3F310509F008F480E02E93615070409FEFE8 -:2060E0006F3F790761F7DF91CF910895EF92FF920F931F93CF93DF938B01FC017183608313 -:206100006115710581F022E0E22EF12CE80EF91EC0E0D0E0C7018C0F9D1F0E94CE38219618 -:20612000C017D107B9F7DF91CF911F910F91FF90EF90089524E030E0FC013783268384E05D -:2061400090E0089521E0FC01208380E090E00895EF92FF920F931F93DF93CF930F92CDB7C5 -:20616000DEB77C018E010F5F1F4FC8010E94CE3889818823D1F7F7011782168280E090E0BB -:206180000F90CF91DF911F910F91FF90EF9008950F931F93DF93CF930F92CDB7DEB78C0126 -:2061A000CE010196FBD78981823070F085E090E0F8019783868325E030E0C9010F90CF91BC -:2061C000DF911F910F910895F8019181933141F0882369F481E0F801828720E030E0EDCF2B -:2061E000882359F481E0818720E030E0E6CF86E0F801828720E030E0E0CF8DE0F8018187E4 -:2062000020E030E0DACF0B96C9D780E090E00895CF93DF93EC016C897D898E559F4F66DF45 -:206220006C897D89CE018B539F4F60DF80E090E0DF91CF910895FC016489758981589F4F9D -:2062400055DF80E090E008950F931F93CF93DF938C01EC016696CE0164E070E047DFCE01A7 -:20626000C0DEF801648775878687978780E090E0DF91CF911F910F9108950F931F93CF9332 -:20628000DF938C01EC016696CE0164E070E02EDFCE01A7DEF801608B718B828B938B695F7F -:2062A0007F4F8F4F9F4F28E030E040E050E00E945F39F801358B248B2132310564F086E0F7 -:2062C00090E09783868326E030E0C901DF91CF911F910F91089520E030E0C901DF91CF91E4 -:2062E0001F910F910895BC0181E090E02BD780E090E060E070E026D780E090E061E070E063 -:2063000021C74F925F926F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93CF9333 -:20632000DF93EC01F62E662309F4A4C08881861709F4EEC06730C1F06E30C1F48D30B1F0A6 -:2063400005E010E0C801DF91CF911F910F91FF90EF90DF90CF90BF90AF909F908F907F90B8 -:206360006F905F904F900895863051F700E010E0A8E0AA2EFCE0CF2EEEE06E2E7FE0B72EFE -:2063800062E0E62E992493945AE0752E45E0D42E37E0832E23E0422E99E0592EF81691F2F3 -:2063A000873009F495C08830A8F4833009F453C0843008F03CC08130A1F1823008F454C010 -:2063C0008F2D893008F49EC081E090E08CDF58828881E4CF8B3059F08C3078F4893009F43A -:2063E00067C08A3008F47DC09F2D9B3089F081E090E079DFC8828881D1CF8D3009F452C08B -:206400008D3000F18E3009F075C09F2D9B30E9F480E090E068DFF8828881C0CF8F2D8130D8 -:2064200019F181E090E05FDFE8828881B7CF853009F444C0863090F081E090E054DF888250 -:206440008881ACCF8F2D8D3019F381E090E04BDFB8828881A3CF9F2D9430D1F281E090E05F -:2064600042DFD88288819ACF80E090E03CDF9882888194CF81E090E036DF00E010E080E0A8 -:2064800090E060E070E05ED680E090E061E070E059D60F5F1F4F0530110589F7188200E017 -:2064A00010E050CF81E090E01EDF6882888176CF80E090E018DF7882888170CF8F2D86304C -:2064C00009F4A6CF81E090E00EDFA882888166CF9F2D943009F49CCF81E090E004DFA8824E -:2064E000F5CF8F2D813009F493CF81E090E0FBDEE8829BCF8F3009F491CFF88205E010E023 -:2065000088814CCF80E090E0EEDE4882888146CF863049F08D3009F029CF81E090E0E3DEA4 -:206520008EE0888323CF81E090E0DDDE87E088831DCFCF92DF92EF92FF920F931F93CF936C -:20654000DF93EC018C010A5E1F4FC80161E070E0CDDDC88CC80161E070E0C8DDD88CC801F5 -:2065600064E070E0C3DDC8013CDD7B018C0188858C1521F0CE0108966C2DC3DEC801B70115 -:2065800023D688858D1521F0CE0108966D2DB9DE80E090E0DF91CF911F910F91FF90EF90A6 -:2065A000DF90CF9008950F931F93DF93CF930F92CDB7DEB78C01CE010196F0D5C80108966F -:2065C00069819FDE9C01009719F0F80197838683C9010F90CF91DF911F910F9108954F92F4 -:2065E0005F926F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93CF93DF935B014C -:206600006C01FA0138012115310509F481C080819181D90111969C938E93808191818C01AB -:206620000E5F1F4F020F131FA114B104C104D10409F45DC022E0422E512C480E591E4E0E06 -:206640005F1E0CC00115110519F0D8019E928D01A114B104C104D10409F449C0F201829016 -:206660002F01EE24FF2499240894A108B108C108D1086114710429F0A114B104C104D10451 -:2066800081F1C82DD0E0BE016170707082E090E059D580E090E060E070E054D501151105BE -:2066A00049F08ED590E00E2C02C0880F991F0A94E2F7982A80E090E061E070E043D5A1141C -:2066C000B104C104D10409F4BDCF0894E11CF11CF8E0EF16F10409F4B5CFD595C7958C2E69 -:2066E000C3CF81E090E061E070E02CD5CACFDF91CF911F910F91FF90EF90DF90CF90BF90C1 -:20670000AF909F908F907F906F905F904F9008958081918100E010E087CF2F923F924F92C7 -:206720005F926F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93DF93CF93CDB7E2 -:20674000DEB728970FB6F894DEBF0FBECDBF3C01962E29833A834B835C831E830D8317013E -:206760002601B886AF82A9A051E0C52ED12C681509F487C029813A814B815C8121153105DE -:206780004105510529F58D8D9E8DAF8DB8A10097A105B10509F097C020E030E0C90128968A -:2067A0000FB6F894DEBF0FBECDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF909F90D9 -:2067C0008F907F906F905F904F903F902F900895BB24EE24FF24C301692D93DD69817A81D0 -:2067E0008B819C814D815E8191018601F8DE4114510461F0C201B1014F8158851ADC41E0A0 -:20680000E42EF12C009711F0EE24FF24C114D104E9F0D3018C918F5F8C93E114F10459F0C8 -:206820002D8D3E8D4F8D58A1211531054105510511F0BA1448F1C301682D63DD8D8D9E8D10 -:20684000AF8DB8A10097A105B10591F4E114F10409F4A2CFB3948B2D81508A1508F4BBCFDE -:20686000AA2019F0AB1408F439C022E030E096CFC30161E046DD6D8D7E8D8F8D98A1A4D420 -:20688000E5CFCC24DD2476CFC30166E03ADDC30164E037DD8D8D9E8DAF8DB8A1B595A79571 -:2068A00097958795B595A795979587952D8D3E8D4F8D58A1280F391F4A1F5B1F2D8F3E8F6D -:2068C0004F8F58A3BBCFC30161E01BDD6D8D7E8D8F8D98A179D420E030E060CF23E030E05F -:2068E0005DCF8F92AF92BF92CF92DF92EF92FF920F931F93CF93DF93EC018C010A5E1F4F5D -:206900006C897D89C801F2DB00D000D00F92288939894A895B89ECE5EE2EF12CEC0EFD1E5C -:2069200079E3C72ED12CCC0EDD1E6FE7A62EB12CAC0EBD1E8C859D85AE85BF85EDB7FEB795 -:2069400081839283A383B4838B858583CE01089664E08A84E2DE9C010F900F900F900F9011 -:206960000F90009711F09F838E83C901DF91CF911F910F91FF90EF90DF90CF90BF90AF9059 -:206980008F9008958F92AF92BF92CF92DF92EF92FF920F931F93CF93DF93EC018C010A5E9A -:2069A0001F4FC80162E070E0A1DBC8011ADB6B017C01695F7F4F8F4F9F4F28E030E040E051 -:2069C00050E07DD4213231058CF026E030E03F832E83C901DF91CF911F910F91FF90EF90B0 -:2069E000DF90CF90BF90AF908F900895C801B9017DDB00D000D00F928C859D85AE85BF85B9 -:206A0000EDB7FEB781839283A383B4831582CE0108966BE0A7019601EE24FF24CC24DD24F3 -:206A2000AA24BB24898479DE9C010F900F900F900F900F90009769F2CACF6F927F928F92CF -:206A4000AF92BF92CF92DF92EF92FF920F931F93DF93CF930F92CDB7DEB73C01CE0101963B -:206A60009DD383010A5E1F4F298130E040E050E0295F3F4F4F4F5F4FF3E05595479537957B -:206A80002795FA95D1F7C801B90130DB00D000D00F92298130E040E050E0F30184859585F3 -:206AA000A685B785EDB7FEB781839283A383B4831582C30108966BE0EE24FF24CC24DD2436 -:206AC000AA24BB24F301818428DE9C010F900F900F900F900F90009719F0F301978386839B -:206AE000C9010F90CF91DF911F910F91FF90EF90DF90CF90BF90AF908F907F906F900895D9 -:206B00002F923F924F925F926F927F928F92AF92BF92CF92DF92EF92FF920F931F93DF93A2 -:206B2000CF9300D0CDB7DEB79A8389831A012B013901C801B901DADAC114D10419F0C601AF -:206B4000B301D4DA00D000D00F928E899F89A88DB98DEDB7FEB781839283A383B4838A8DF2 -:206B6000858389819A8164E0A2019101D6DD0F900F900F900F900F900F900F90CF91DF9193 -:206B80001F910F91FF90EF90DF90CF90BF90AF908F907F906F905F904F903F902F90089515 -:206BA0008F92AF92BF92CF92DF92EF92FF920F931F93CF93DF93EC0189818131D9F114E0AF -:206BC000812E00D000D00F92488959896A897B892C893D898E010A5E1F4FBCE5EB2EF12C64 -:206BE000EC0EFD1EA9E3CA2ED12CCC0EDD1EEDB7FEB711821282138214821582CE0108967B -:206C0000AA24BB247DDF9C010F900F900F900F900F90009711F09F838E83C901DF91CF914E -:206C20001F910F91FF90EF90DF90CF90BF90AF908F9008958A84C5CF8F92AF92BF92CF9228 -:206C4000DF92EF92FF920F931F93CF93DF93EC0189818E30A9F104E0802E00D000D00F9267 -:206C6000488959896A897B892C893D898E010A5E1F4FEDB7FEB71182128213821482158248 -:206C8000CE010896EE24FF24CC24DD24AA24BB2437DF9C010F900F900F900F900F9000974F -:206CA00011F09F838E83C901DF91CF911F910F91FF90EF90DF90CF90BF90AF908F90089590 -:206CC0008A84CBCF8F92AF92BF92CF92DF92EF92FF920F931F93CF93DF93EC0100D000D0C0 -:206CE0000F92488959896A897B892C893D898C010A5E1F4FECE5EE2EF12CE80EF91E99E3D8 -:206D0000C92ED12CCC0EDD1E8FE7A82EB12CAC0EBD1E8C859D85AE85BF85EDB7FEB78183E5 -:206D20009283A383B4838B858583CE0108968A84E7DE9C010F900F900F900F900F9000973A -:206D400011F09F838E83C901DF91CF911F910F91FF90EF90DF90CF90BF90AF908F900895EF -:206D6000CF92DF92EF92FF920F931F93CF93DF938C016B017901B8018AD9E601288139812E -:206D8000F701A081B181AD014150504057FD38C0FD013296EE0DFF1D1196A00FB11F60E04A -:206DA00010E08291882329F1EC9001E00AC0762F660F7123B1F0E02A959587958823C1F0E9 -:206DC000000F90E080FFF8CF662389F721503040B601620F731FEB011A8162E071E071239C -:206DE00051F7702F7095E72295958795882341F7EC924150504011978FEF4F3F580789F644 -:206E0000DF91CF911F910F91FF90EF90DF90CF9008952F923F924F925F926F927F928F9242 -:206E20009F92AF92BF92CF92DF92EF92FF920F931F93DF93CF93CDB7DEB761970FB6F89421 -:206E4000DEBF0FBECDBF3C01B6E14B2E512C480E591EFC0164897589C20148D9C301089677 -:206E60009D838C83F301E45AFF4FFF83EE83C301C99699878887AFE72A2E312C260C371C4E -:206E800000D000D00F92F301208931894289538984859585A685B785EDB7FEB781839283B7 -:206EA000A383B483F3018385EDB7FEB785838C819D8164E08201EE80FF80C884D98451013E -:206EC000F30182842ADC9B838A830F900F900F900F900F90009709F087C0C3018B539F4F05 -:206EE0009D878C87FC0140815181141615060CF09DC0E0E0F0E060E000E010E0E60DF71D86 -:206F0000E953FF4F8081882351F090E09C0121703070020F131F959587958823B1F76F5F12 -:206F2000E62FF0E0E417F5074CF3CE01019636D1222717FD2095322F095F1F4F2F4F3F4F74 -:206F4000E3E03595279517950795EA95D1F71F870E879924C30188519F4F9B878A87F301AF -:206F6000EE55FF4FF98BE88B8981981608F043C08A859B856E857F85B9D8C2016A857B856D -:206F8000488959892C853D85EBDE00D000D00F92F301208931894289538984859585A68575 -:206FA000B785EDB7FEB781839283A383B483F3018385EDB7FEB785838C819D8164E0820177 -:206FC000EE80FF80C884D9845101F3018284A5DB0F900F900F900F900F90009739F4939449 -:206FE0008981981640F4C4CF8A819B81F301978386839B838A838A819B8161960FB6F8943A -:20700000DEBF0FBECDBFCF91DF911F910F91FF90EF90DF90CF90BF90AF909F908F907F9093 -:207020006F905F904F903F902F90089500E010E07CCFCF93DF93EC01188219821A821B820E -:207040001C821D821F821E821B86188681E089878A87188A198A1A8A1B8A1D8A1C8A1C8674 -:207060001D861E861F86CE01089660E04AD98E839F83DF91CF910895CF93DF93EC012E8144 -:207080003F812115310519F48881882321F0C901DF91CF910895CE01019680D08A819B81DE -:2070A000AC81BD810196A11DB11D8A839B83AC83BD83E981E83150F084E090E09F838E83DE -:2070C00024E030E0C901DF91CF910895F0E0EE0FFF1FE851FD4F0190F081E02DCE01099579 -:2070E0002E813F81D4CF0F931F93DF93CF93CDB7DEB7CB50D1400FB6F894DEBF0FBECDBFCA -:207100008E010F5F1F4FC80194DF2F8138852115310569F0C901C55FDE4F0FB6F894DEBF8D -:207120000FBECDBFCF91DF911F910F9108958981882381F7C801A0DF2F81388521153105EB -:20714000B1F3E8CF8130910551F08230910561F0009721F46115710571F4429808956115C9 -:20716000710539F0439A08956115710531F0459A089543980895429A08954598089580E0A2 -:2071800090E060E070E0DEDF80E090E061E070E0D9CF9093DC378093DB370895CF93DF935D -:2071A000EC01E091DB37F091DC37309729F009958883DF91CF9108951882DF91CF910895CE -:2071C00081E0349B80E00895AF92BF92CF92DF92EF92FF920F931F935B016C0116161706A6 -:2071E0001806190674F4EE24FF248701C8DF0894E11CF11C011D111DEA14FB040C051D0564 -:20720000ACF31F910F91FF90EF90DF90CF90BF90AF900895629FD001739FF001829FE00D95 -:20722000F11D649FE00DF11D929FF00D839FF00D749FF00D659FF00D9927729FB00DE11D58 -:20724000F91F639FB00DE11DF91FBD01CF0111240895AA1BBB1B51E107C0AA1FBB1FA617ED -:20726000B70710F0A61BB70B881F991F5A95A9F780959095BC01CD010895A1E21A2EAA1BED -:20728000BB1BFD010DC0AA1FBB1FEE1FFF1FA217B307E407F50720F0A21BB30BE40BF50BAB -:2072A000661F771F881F991F1A9469F760957095809590959B01AC01BD01CF01089597FB0C -:2072C000092E05260ED057FD04D0D7DF0AD0001C38F450954095309521953F4F4F4F5F4F5F -:2072E0000895F6F790958095709561957F4F8F4F9F4F08950790F691E02D09949111089591 -:2073000081568A5108F4805285580895FC0105900020E9F7809590958E0F9F1F0895FB01B3 -:20732000DC0104C08D910190801921F441505040C8F7881B990B0895FB01DC0102C001905F -:207340000D9241505040D8F70895FB01DC014150504030F08D910190801919F40020B9F7C2 -:20736000881B990B0895FB01DC014150504048F001900D920020C9F701C01D924150504056 -:20738000E0F708950F931F93DF93CF93CDB7DEB72E970FB6F894DEBF0FBECDBF0D891E89EF -:2073A0008F89988D26E02C831A83098397FF02C080E090E801979E838D839E01255E3F4F09 -:2073C000CE010196698D7A8DA90119D04D815E8157FD0AC02F813885421753070CF49A0131 -:2073E000020F131FF80110822E960FB6F894DEBF0FBECDBFCF91DF911F910F9108952F9236 -:207400003F924F925F926F927F928F929F92AF92BF92CF92DF92EF92FF920F931F93DF9329 -:20742000CF93CDB7DEB72C970FB6F894DEBF0FBECDBF6C011B018A01FC0117821682838181 -:2074400081FFC4C12E010894411C511CF6019381F10193FD859193FF81911F01882309F483 -:20746000B1C1853239F493FD859193FF81911F01853221F490E0B601F5D1E8CFEE24FF24A7 -:2074800020E02032B0F48B3269F08C3228F4803251F0833271F40BC08D3239F0803349F456 -:2074A00021602CC02260246029C0286027C0206125C027FD2CC0382F30533A3098F426FF86 -:2074C00008C08E2D880FE82EEE0CEE0CE80EE30E15C08F2D880FF82EFF0CFF0CF80EF30E36 -:2074E00020620CC08E3221F426FD6CC1206406C08C3611F4206802C0883649F4F10193FD41 -:20750000859193FF81911F01882309F0BACF982F9554933018F09052933028F40C5F1F4F4F -:20752000FFE3F9830DC0833631F0833771F0833509F05CC021C0F801808189830E5F1F4F9C -:20754000420171E0A72EB12C15C062E0662E712C600E711EF8018080918026FF03C06E2D13 -:2075600070E002C06FEF7FEFC4012C8770D15C0183012C852F7716C052E0652E712C600E96 -:20758000711EF8018080918026FF03C06E2D70E002C06FEF7FEFC4012C874ED15C012C854C -:2075A0002068830123FD1EC007C080E290E0B6012C8758D1FA942C858F2D90E0A816B906AD -:2075C000A0F310C0F40127FD859127FF81914F0190E0B6012C8746D12C85F110FA940894C4 -:2075E000A108B108A114B10469F7E9C0843611F0893641F527FF08C0F80160817181828149 -:2076000093810C5F1F4F09C0F80160817181882777FD8095982F0E5F1F4F4FE6B42EB22223 -:2076200097FF09C090958095709561957F4F8F4F9F4FF0E8BF2AA2012AE030E03FD1782EE8 -:20764000741844C0853731F43FEEB32EB2222AE030E025C099EFB92EB2228F36C1F0803768 -:2076600020F4883509F0AEC00DC0803721F0883709F0A8C002C020E1B22AB4FE0BC084E09D -:20768000B82A08C0B4FE09C0E6E0BE2A06C028E030E005C020E130E002C020E132E0B7FED9 -:2076A00008C0F80160817181828193810C5F1F4F07C0F8016081718180E090E00E5F1F4F08 -:2076C000A201FCD0782E7418FFE7BF22B6FE0BC02EEFB2227E1438F4B4FE07C0B2FC05C028 -:2076E0008FEEB82202C0A72C01C0AE2C8B2D90E0B4FE0DC0FE01E70DF11D2081203319F45A -:20770000E9EEBE2209C0A394B2FE06C004C086789070009709F0A3948B2C9924B3FC13C0BD -:20772000B0FE0EC0AF1428F4E72CEF0CEA18AF2C07C0E72C05C080E290E0B60193D0A39441 -:20774000AF14C8F304C0AF1410F4FA1801C0FF2484FE0EC080E390E0B60184D082FE1DC09F -:2077600081FE03C088E590E010C088E790E00DC0C40186789070009781F081FC02C080E202 -:2077800001C08BE2B7FC8DE290E0B6016BD005C080E390E0B60166D0EA947E14C8F37A94D9 -:2077A000F201E70DF11D808190E0B6015BD07720B1F705C080E290E0B60154D0FA94FF2023 -:2077C000C9F744CEF6012681378102C02FEF3FEFC9012C960FB6F894DEBF0FBECDBFCF9140 -:2077E000DF911F910F91FF90EF90DF90CF90BF90AF909F908F907F906F905F904F903F9066 -:207800002F900895F999FECF92BD81BDF89A992780B50895262FF999FECF92BD81BDF89A29 -:20782000019700B4021639F01FBA20BD0FB6F894FA9AF99A0FBE0895FC0105906150704030 -:207840000110D8F7809590958E0F9F1F0895FC016150704001900110D8F7809590958E0F70 -:207860009F1F08950F931F93CF93DF938C01EB018B8181FF1BC082FF0DC02E813F818C81DB -:207880009D812817390764F4E881F9810193F983E88306C0E885F985802F0995009731F4DB -:2078A0008E819F8101969F838E8302C00FEF1FEFC801DF91CF911F910F910895FA01AA27AF -:2078C000283051F1203181F1E8946F936E7F6E5F7F4F8F4F9F4FAF4FB1E03ED0B4E03CD03C -:2078E000670F781F891F9A1FA11D680F791F8A1F911DA11D6A0F711D811D911DA11D20D037 -:2079000009F468943F912AE0269F11243019305D3193DEF6CF010895462F4770405D419322 -:20792000B3E00FD0C9F7F6CF462F4F70405D4A3318F0495D31FD4052419302D0A9F7EACF95 -:20794000B4E0A6959795879577956795BA95C9F700976105710508959B01AC010A2E0694CE -:207960005795479537952795BA95C9F7620F731F841F951FA01D089517E000E0C4E6D7E0BC -:2079800040E005C022974109FE014BBFB3DCC636D1074007B9F7F894FFCF2E2E0053656CC2 -:2079A000656374204469736B006E6F20696D6167652066696C657320666F756E640001036D -:2079C0000507090E10121416181C1E696E636F6D706C657465207772697465006261642024 -:2079E000736563746F7220256420666F722074256400627566206C6F636B65642025642F23 -:207A000025643A256400636865636B73756D206661696C757265203000636865636B737589 -:207A20006D206661696C757265203100636865636B73756D206661696C7572652032006370 -:207A40006865636B73756D206661696C0043504C44204669726D77617265202564002564C8 -:207A6000002575006669726D776172652E7876660053442072656164206572726F7220527E -:207A800000526573756C743A207375636365737300526573756C743A206572726F722025CC -:207AA000640053442072656164207374617274206572726F7200534420726561642065722D -:207AC000726F7220440077722077726F6E6720747261636B2025642F25640052657665721F -:207AE0007465642074726B20253032642020200053442072656164206572726F7220570059 -:207B000053442077726974655374617274206661696C005344207772697465206572726FFF -:207B20007200534420777269746553746F70206661696C0053617665642074726B202530B6 -:207B4000326420696E20256C7520200053442063617264206572726F722025643A2564002B -:207B6000253032640025642000D5AAAD0000000000000000000000008A01AD01D8010D0224 -:207B80004E02A2301B311D35713424319A309A3003313D316236083109371C361C361C36EE -:127BA000D035D035D035D332C830C830C234A830993236 -:020000040001F9 -:20EFF800DDDDDDDD0001000097C00000B2C00000B0C00000AEC00000ACC00000AAC0000007 -:20F01800A8C00000A6C00000A4C00000A2C00000A0C000009EC000009CC000009AC00000D0 -:20F0380098C0000096C0000094C0000092C0000090C000008EC000008CC000008AC0000030 -:20F0580088C0000086C0000084C0000082C0000080C000007EC000007CC000007AC0000090 -:20F0780078C0000076C0000074C0000072C0000070C000001E051E1F150A0E11111F110E87 -:20F098001F15151F05050E151D1F041F111F1108100F1F041B1F10101F061F1F0E1F0E11D0 -:20F0B8000E1F05020010001F0D16121509011F010F101F0718071F0C1F000000031C030091 -:20F0D8000A004552524F525A58464C41534858495358454D5054590046454D555142494E32 -:08F0F800584E4F5458464F5585 -:20F100004E4400464C415348494E475846454D555142494E5851515100464C4F50505958E5 -:20F12000454D5558424F4F544C4F41444552000011241FBECFEFD0E4DEBFCDBF11E0A0E087 -:20F14000B1E0E8EEFFEF01E00BBF02C007900D92AA30B107D9F712E0AAE0B1E001C01D92D8 -:20F16000A733B107E1F7DBD03DC74ACF249A259A279A2E9A089588EC3197319731970000EE -:20F180008A95D1F7089502D02C9801C02C9A8FEF98E087FD2D9A87FF2D98880F1E998395DC -:20F1A0002F9A2F989A95A9F70895FB018BBF83E080935700E8958091570080FDFCCF81E1B1 -:20F1C00080935700E89508950F921F928BBFFB01DA0190E80D901D9081E080935700E8952E -:20F1E00032969A95B9F7FB0185E080935700E8958091570080FDFCCF81E180935700E89527 -:20F200001F900F9008955E9808955E9A0895A1E0B0E0ECE0F9EFB8C68983B8DF2A98898129 -:20F22000B7DF2A9A2196E2E0CBC6A2E0B0E0EAE1F9EFAAC66A838983E6DF89818068E7DFBF -:20F240006A81862F8064E3DF2296E2E0B9C6CF93DF93DBDFC8EFD1E080E0D9DF2197E1F7D1 -:20F26000DF91CF910895EF92FF920F931F93CF93DF938C01CADF1FC023E0829FC0011124B8 -:20F280000F5F1F4FEC01C753D0412CECE22E2FEEF22EE80EF91ECE01AA2797FDA095BA2FB6 -:20F2A000ABBFFC018791880FB2DF2196CE15DF0591F780E0ACDFC801AA2797FDA095BA2F6A -:20F2C000ABBFFC0187918823B9F6CDB7DEB7E6E073C61F93209A229A569A48DF2A98289A7A -:20F2E00018EC49DF1150E9F7289818EC44DF1150E9F7289A18EC3FDF1150E9F784DF81E28E -:20F3000086DF8FEB84DF84E182DF80E280DF8CE07EDF80E060E089DF9ADF1F910895A2E00B -:20F32000B0E0E4E9F9EF29C65C9A599A5A9A8FE493EC0197F1F700C00000499956C04C99AD -:20F3400054C0239AC6DF89E191EF8DDF80E062E06CDF8DE091E0A0D280E091E0ACD38823A9 -:20F3600009F03AC083E091EF7EDFEE24FF2487016E010894C11CD11C88E0B82EC801B701F9 -:20F3800014DF87E391E06FEF70E040E051E023D687E391E060E071E0A601ECD489819A81AF -:20F3A000009729F0C801B70147E351E00DDF85B18B2585B980E091E0A0E0B0E0E80EF91EC3 -:20F3C0000A1F1B1F90E0E91690EFF90691E0090790E0190799F603C080EF90EF44DF499B85 -:20F3E000FECF4C9BFCCF4A9BFACF80E090E0FC0125913491AFEF2F3F3A0711F0FC010995AF -:20F4000068DF80E060E011DF8AED90EF2CDFFFCFDF92EF92FF920F931F93182F042FF52ED2 -:20F42000E62ED72E87FF08C087E740E050E0BA01EFDF8230E0F41F77A6DE812FA9DE8D2D8D -:20F44000A7DE8E2DA5DE8F2DA3DE802FA1DE103421F0183421F081E003C085E901C087E80A -:20F4600097DE1AE094DE87FF02C01150D9F71F910F91FF90EF90DF900895A5E0B0E0E2E4ED -:20F48000FAEF7CC573DE04E676DE0150E9F70AE07DDE0150E9F780E440E050E0BA01B8DF06 -:20F4A000813009F067C088E44AEA51E060E070E0AFDF8130D1F58E010F5F1F4F45E0C42E93 -:20F4C000D12CCC0EDD1E780162DEF70181937F01EC15FD05C9F78B81813009F04BC08C8184 -:20F4E0008A3A09F047C008C046DE0894E108F108E114F10429F43EC030E1E32E37E2F32E7D -:20F5000089EE40E050E060E070E482DF882361F73DC03DDEF80181938F01EC15FD05C9F7B4 -:20F52000898186FF25C09CE026C089EE40E050E0BA016EDF823020F492E029EEE22E03C004 -:20F5400091E081E4E82E00E117E208C09D8313DE015010409D810115110561F08E2D40E0F5 -:20F5600050E0BA019D8354DF9D81882379F717C094E001C090E090930A019D8307DE81E004 -:20F580009D81911180E02596E8E014C58AE740E050E0BA013DDF882309F4BBCFEBCF80E506 -:20F5A00040E052E060E070E09D8332DF9D81882309F7E1CFA1E0B0E0EFEDFAEFDDC46C01DB -:20F5C000590180910A0183FD07C0E9E0440F551F661F771FEA95D1F781E51ADF882391F5EC -:20F5E00050E4E52E5CE9F52ED2DD8F3F39F40894E108F108E114F104B9F724C08E3F11F5E3 -:20F60000EE24FF24EA18FB0882E092E0E80EF91EE01AF10AA114B10429F0B9DD0894A1087C -:20F62000B108F8CFB4DDF60181936F0101501040C9F7ADDD0894E108F108E114F104C9F72B -:20F6400080E001C081E08983A1DD89812196EAE0AFC4CF93DF93C0910B01D0910C0162504F -:20F660007040804090402E813F81488559852250304040405040621773078407950780F4B0 -:20F680002A8130E040E050E02ED49B01AC018A899B89AC89BD89280F391F4A1F5B1F03C02D -:20F6A00020E030E0A901B901CA01DF91CF910895CF93DF93EC01E0910B01F0910C01198237 -:20F6C00018826C817D818E819F81613071058105910551F126813781408551856217730724 -:20F6E0008407950708F5611571058105910539F42081233021F466857785808991896887AF -:20F7000079878A879B87611571058105910511F0A0DF04C066857785808991896C877D8769 -:20F720008E879F8780E001C081E0DF91CF910895A4E0B0E0EDE9FBEF25C4DC01CB01E091C8 -:20F740000B01F0910C0182309105A105B10508F452C0268137814085518582179307A40785 -:20F76000B50708F048C02081223021F0233009F042C01CC0492F5A2F6B2F77270285138547 -:20F7800024853585400F511F621F731F9C013070220F331FCE01019602E010E00BDF8823A7 -:20F7A00051F529813A8140E050E029C0AC01BD0127E076956795579547952A95D1F7028516 -:20F7C000138524853585400F511F621F731F9C012F773070220F331F220F331FCE0101960D -:20F7E00004E010E0E7DE882331F429813A814B815C815F7004C021E030E040E050E0B901E4 -:20F80000CA012496E4E0DAC3A0E0B0E0E9E0FCEFB1C3F82EE92E5A016B012EEF31E002E0B6 -:20F8200010E0C8DE882369F58F2CE4014E019E2CE401888199812AEA8535920721F58F2D2F -:20F840009E2DB601A50126E330E0B4DE882331F48881998121E486349207B9F08F2D9E2D5A -:20F86000B601A50122E530E002E010E0A3DE882371F481E02881398191E42634390741F4A9 -:20F8800004C083E005C082E003C080E001C081E0CDB7DEB7ECE08AC3A8E2B0E0E1E5FCEFD8 -:20F8A00065C37C0110920C0110920B01009709F4F8C0E3DD80FDF7C06E010894C11CD11C31 -:20F8C000C60140E050E0BA019FDF8130C9F4C60140E050E0BA012EEB31E000E110E06ADE55 -:20F8E000882309F0E2C08D81882309F4E0C089849A84AB84BC84C601B501A40185DF03C089 -:20F90000882499245401833009F4CFC0882309F0CEC06E010894C11CD11CC601B501A401C1 -:20F920002DE030E004E210E045DE882309F0BDC0D60119966D917C911A9780E090E0611508 -:20F9400071058105910521F4688D798D8A8D9B8D2C8130E040E050E0C6D26DA37EA38FA3BE -:20F9600098A7F6014180528066247724480C591C6A1C7B1CD7011A964D925D926D927C9250 -:20F980001D97E9811296EC93D60114964D915C911597D70115965C934E931497D6011696A9 -:20F9A0006D917C91179780E090E0611571058105910521F46C897D898E899F8904E0569598 -:20F9C00047950A95E1F74A01AA24BB24D60111960D911C91129720E030E0601B710B820BD6 -:20F9E000930B2DA13EA14FA158A5621B730B840B950B681979098A099B092E2F30E040E0DE -:20FA000050E090D22E5F3F4F4F4F5F4FD70116962D933D934D935C931997273FBFE03B0713 -:20FA2000B0E04B07B0E05B0708F441C0273FEFEF3E07E0E04E07E0E05E0710F482E001C00B -:20FA400083E0D7018C93833029F488A199A1AAA1BBA108C08DA19EA1AFA1B8A5840D951D4D -:20FA6000A61DB71DF70186879787A08BB18B480C591C6A1C7B1C2DA13EA14FA158A5420E95 -:20FA8000531E641E751ED70152964D925D926D927C92559711961C921197F0920C01E0925B -:20FAA0000B0180E005C082E003C081E001C087E0A896E0E177C2ACE3B0E0E0E6FDEF54C248 -:20FAC000C0900B01D0900C01C114D10409F446C1F60111829E012F5F3F4F388B2F877C0174 -:20FAE000FC01208101962032D1F32F3209F47C01198A1A8A1B8A1C8AF7018081813240F46E -:20FB0000CE010D96D5DD1D8E882309F4F7C029C190E2892E8DE0482E512C4C0E5D1EBDE1D1 -:20FB20006B2E712C6C0E7D1EA8E22A2E312C2C0E3D1EEF85F889DF01CF010B9601C08D9280 -:20FB4000A817B907E1F790E0992428E0D701A90DB11D8C9193948132C0F08F32B1F08E32F4 -:20FB600011F0921738F0283081F48E3271F498E02BE0ECCF382F31563A3108F48052DF017C -:20FB8000A90FB11D8C939F5FE1CF91E0813208F090E09387C2018CDD882309F086C0498D80 -:20FBA0005A8D6B8D7C8D2D853E852F703070F5E0220F331FFA95E1F7C30100E210E0FADC7E -:20FBC000882309F0D1C08D8D882309F4CFC088A583FD0BC0F301AF85B889E215F30509F4D2 -:20FBE0006EC091918D919817C1F3A0900B01B0900C010D851E850F5F1F4F09F4B7C0898D10 -:20FC00009A8DAB8DBC8D0097A105B10509F4AEC098012F7030702115310509F043C0019607 -:20FC2000A11DB11D898F9A8FAB8FBC8F6D897E898F89988D611571058105910541F4F50105 -:20FC4000848195810817190708F090C02BC0F501228130E021503040A801E4E05695479559 -:20FC6000EA95E1F72423352321153105D9F460DD623071058105910508F476C0F501268125 -:20FC8000378140855185621773078407950708F06DC06D8B7E8B8F8B988FDBDC698F7A8FD8 -:20FCA0008B8F9C8F1E870D877ACF833009F059C0EF85F8899385992309F45AC052C0EF8552 -:20FCC000F88983858823D1F488A584FF51C0E90CF11CF30184899589A0E0B0E0DC0199279C -:20FCE0008827228D338D40E050E0822B932BA42BB52B898B9A8BAB8BBC8B1BCF8D8D882317 -:20FD000079F188A584FD2CC0BE01635E7F4FFB0184899589A0E0B0E0DC0199278827228D5F -:20FD2000338D40E050E0822B932BA42BB52BF601868F978FA0A3B1A3FB01848D958DA68D6E -:20FD4000B78DF601828F938FA48FB58F168A178A108E118E81E0818380E003C086E001C091 -:20FD600083E0EC96E2E11CC181E0FBCF83E0A0CF84E0F7CFA0E0B0E0EFEBFEEFF7C03C010C -:20FD80007B014A01C0910B01D0910C01FA0111821082209709F4A0C0898180FF9FC08A8D9E -:20FDA0009B8DAC8DBD8D2E893F89488D598D821B930BA40BB50B9B0140E050E08217930795 -:20FDC000A407B50708F47C015301412C72E0572E7AC08E899F89A88DB98D9C01AD013170CB -:20FDE000407050702115310541055105C1F59C01AD0169E056954795379527956A95D1F72B -:20FE0000CA80CA94C222C1F40097A105B10529F46E8D7F8D88A199A105C06AA17BA18CA10E -:20FE20009DA186DC623071058105910508F451C06AA37BA38CA39DA36AA17BA18CA19DA1C5 -:20FE400008DC611571058105910509F442C06C0D711D811D911D6EA37FA388A799A72E890B -:20FE60003F893170C201821B930B67018E159F0508F46C016114710419F480E090E001C07B -:20FE8000C5014EA15FA168A579A5860193DB882301F5960140E050E08E899F89A88DB98D4B -:20FEA000820F931FA41FB51F8E8B9F8BA88FB98FAC0CBD1CEC18FD08F401808191818C0D6B -:20FEC0009D1D91838083E114F10409F082CF80E006C0198281E003C086E001C085E0CDB728 -:20FEE000DEB7E0E15FC0629FD001739FF001829FE00DF11D649FE00DF11D929FF00D839F4E -:20FF0000F00D749FF00D659FF00D9927729FB00DE11DF91F639FB00DE11DF91FBD01CF01CC -:20FF200011240895A1E21A2EAA1BBB1BFD010DC0AA1FBB1FEE1FFF1FA217B307E407F50796 -:20FF400020F0A21BB30BE40BF50B661F771F881F991F1A9469F760957095809590959B01CF -:20FF6000AC01BD01CF0108952F923F924F925F926F927F928F929F92AF92BF92CF92DF927D -:20FF8000EF92FF920F931F93CF93DF93CDB7DEB7CA1BDB0B0FB6F894DEBF0FBECDBF09945F -:20FFA0002A88398848885F846E847D848C849B84AA84B984C884DF80EE80FD800C811B81CF -:20FFC000AA81B981CE0FD11D0FB6F894DEBF0FBECDBFED010895DC0101C06D934150504060 -:12FFE000E0F70895F894FFCF66656D752E62696E00002D -:040000050001F00006 -:00000001FF diff --git a/arduino/floppyemu/main.cpp b/arduino/floppyemu/main.cpp deleted file mode 100755 index bc8c805..0000000 --- a/arduino/floppyemu/main.cpp +++ /dev/null @@ -1,2021 +0,0 @@ -/* - Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved. - - Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported - license. (CC BY-NC 3.0) The terms of the license may be viewed at - http://creativecommons.org/licenses/by-nc/3.0/ - - Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/ - - Permissions beyond the scope of this license may be available at www.bigmessowires.com - or from mailto:steve@bigmessowires.com. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "portmacros.h" -#include "noklcd.h" -#include "millitimer.h" -#include "SdFat.h" -#include "SdBaseFile.h" -#include "micro.h" -#include "ports.h" -#include "diskmenu.h" - -#ifdef ENABLE_ORIGINAL_COMPILER_WORKAROUND - -// work-around for compiler bug -#undef PROGMEM -#define PROGMEM __attribute__(( section(".progmem.data") )) -#undef PSTR -#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];})) - -#endif - -// I/O pin assignments -#define CPLD_RESET_PORT B -#define CPLD_RESET_PIN 0 - -#define CPLD_STEP_DIR_MOTOR_ON_PORT C -#define CPLD_STEP_DIR_MOTOR_ON_PIN 7 - -#define CPLD_STEP_REQ_PORT D -#define CPLD_STEP_REQ_PIN 0 // PCINT24 -#define CPLD_STEP_REQ_INT_MSK PCMSK3 -#define CPLD_STEP_REQ_INT_PIN PCINT24 -#define CPLD_STEP_REQ_INT_ENABLE PCIE3 - -#define CPLD_CURRENT_SIDE_PORT C -#define CPLD_CURRENT_SIDE_PIN 1 // PCINT17 -#define CPLD_CURRENT_SIDE_INT_MSK PCMSK2 -#define CPLD_CURRENT_SIDE_INT_PIN PCINT17 -#define CPLD_CURRENT_SIDE_INT_ENABLE PCIE2 - -#define CPLD_EJECT_REQ_PORT D -#define CPLD_EJECT_REQ_PIN 3 - -#define CPLD_STEP_ACK_DISK_IN_PORT C -#define CPLD_STEP_ACK_DISK_IN_PIN 2 - -#define CPLD_WR_REQ_PORT C -#define CPLD_WR_REQ_PIN 0 // PCINT16 -#define CPLD_WR_REQ_INT_MSK PCMSK2 -#define CPLD_WR_REQ_INT_PIN PCINT16 -#define CPLD_WR_REQ_INT_ENABLE PCIE2 - -#define CPLD_RD_READY_TK0_PORT C -#define CPLD_RD_READY_TK0_PIN 5 - -#define CPLD_RD_ACK_WR_TICK_PORT A -#define CPLD_RD_ACK_WR_TICK_PIN 7 // PCINT7 -#define CPLD_RD_ACK_WR_TICK_INT_MSK PCMSK0 -#define CPLD_RD_ACK_WR_TICK_INT_PIN PCINT7 -#define CPLD_RD_ACK_WR_TICK_INT_ENABLE PCIE0 - -#define CPLD_DATA_PORT A - -#define CPLD_DATA_HIZ_PORT C -#define CPLD_DATA_HIZ_PIN 6 - -#define CPLD_TACH_PORT D -#define CPLD_TACH_PIN 5 - -#define CPLD_TMS_PORT C -#define CPLD_TMS_PIN 3 - -#define SELECT_BUTTON_PORT D -#define SELECT_BUTTON_PIN 4 - -#define PREV_BUTTON_PORT D -#define PREV_BUTTON_PIN 1 - -#define NEXT_BUTTON_PORT D -#define NEXT_BUTTON_PIN 2 - -#define STATUS_LED_PORT B -#define STATUS_LED_PIN 3 - -#define CARD_WPROT_PORT D -#define CARD_WPROT_PIN 7 - -#define SECTOR_DATA_SIZE 512 -#define INTER_SECTOR_GAP_SIZE 55 -#define ADDRESS_DATA_GAP_SIZE 10 -#define SECTOR_DATA_HEADER_SIZE 3 -#define SECTOR_DATA_SECTORNUM_START SECTOR_DATA_HEADER_SIZE -#define SECTOR_DATA_SECTORNUM_SIZE 1 -#define SECTOR_DATA_ENCODED_TAGS_START (SECTOR_DATA_HEADER_SIZE+SECTOR_DATA_SECTORNUM_SIZE) -#define SECTOR_DATA_ENCODED_TAGS_SIZE 16 -#define SECTOR_DATA_ENCODED_DATA_START (SECTOR_DATA_HEADER_SIZE+SECTOR_DATA_SECTORNUM_SIZE+SECTOR_DATA_ENCODED_TAGS_SIZE) -#define SECTOR_DATA_ENCODED_DATA_SIZE 683 -#define SECTOR_DATA_CHECKSUM_START (SECTOR_DATA_ENCODED_DATA_START+SECTOR_DATA_ENCODED_DATA_SIZE) - -// 8 byte marker placed at the end of the program binary, used by the bootloader. -// Configure the .bootldrinfo address to be 8 bytes below the bootloader start address for the type of Atmega being used. -#define DEVICEID_HIGH 0xDDDD -#define DEVICEID_LOW 0xDDDD -#define VERSIONID 0x0100 -const uint16_t bootloader_info[] __attribute__(( section(".bootldrinfo") )) = { DEVICEID_HIGH, DEVICEID_LOW, VERSIONID, 0x0000 }; - -const char versionStr[] PROGMEM = "App Version 1.0 L"; - -volatile uint8_t currentTrack; -volatile uint8_t prevTrack; -volatile uint8_t currentSide; -volatile uint8_t prevSide; -volatile uint8_t writeMode; -volatile bool restartDisk; -volatile bool writeError; - -bool diskInserted; -bool readOnly; -bool mfmMode; -uint16_t crc; -uint8_t numberOfDiskSides; -uint8_t currentSector; -uint16_t driveTachHalfPeriod; -uint8_t tachFlutter; - -uint8_t writeDisplayTimer; -uint8_t cpldFirmwareVersion; - -#define TEXTBUF_SIZE 22 -char textBuf[TEXTBUF_SIZE]; - -#define NUM_BUFFERS 24 -uint8_t sectorBuf[NUM_BUFFERS][SECTOR_DATA_SIZE]; -uint8_t extraBuf[SECTOR_DATA_SIZE]; - -bool selectedFileIsDiskCopyFormat; - -extern const uint16_t sony_track_start[] PROGMEM; -const uint16_t sony_track_start[80] = { - 0, 12, 24, 36, 48, 60 , 72, 84, - 96, 108, 120, 132, 144, 156, 168, 180, - - 192, 203, 214, 225, 236, 247, 258, 269, - 280, 291, 302, 313, 324, 335, 346, 357, - - 368, 378, 388, 398, 408, 418, 428, 438, - 448, 458, 468, 478, 488, 498, 508, 518, - - 528, 537, 546, 555, 564, 573, 582, 591, - 600, 609, 618, 627, 636, 645, 654, 663, - - 672, 680, 688, 696, 704, 712, 720, 728, - 736, 744, 752, 760, 768, 776, 784, 792 -}; - -extern const uint8_t sony_track_len[] PROGMEM; -const uint8_t sony_track_len[80] = { - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 -}; - -extern const uint8_t sony_to_disk_byte[] PROGMEM; -const uint8_t sony_to_disk_byte[] = { - 0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, /* 0x00 */ - 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, /* 0x10 */ - 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3, - 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, /* 0x20 */ - 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, - 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, /* 0x30 */ - 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF -}; - -extern const uint8_t disk_byte_to_sony[] PROGMEM; -const uint8_t disk_byte_to_sony[] = { - /* table begins at disk byte 0x96, value of 0xFF is an invalid disk byte */ - /* 0x96 */ 0x00, 0x01, 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x04, - /* 0x9E */ 0x05, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - /* 0xA6 */ 0x07, 0x08, 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, - /* 0xAE */ 0x0C, 0x0D, 0xFF, 0xFF, 0x0E, 0x0F, 0x10, 0x11, - /* 0xB6 */ 0x12, 0x13, 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, - /* 0xBE */ 0x19, 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - /* 0xC6 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0x1C, - /* 0xCE */ 0x1D, 0x1E, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, - /* 0xD6 */ 0x20, 0x21, 0xFF, 0x22, 0x23, 0x24, 0x25, 0x26, - /* 0xDE */ 0x27, 0x28, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, - /* 0xE6 */ 0x2A, 0x2B, 0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, - /* 0xEE */ 0x31, 0x32, 0xFF, 0xFF, 0x33, 0x34, 0x35, 0x36, - /* 0xF6 */ 0x37, 0x38, 0xFF, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, - /* 0xFE */ 0x3E, 0x3F -}; - -uint8_t sectorDataHeaderGCR[] = { 0xD5, 0xAA, 0xAD }; - -extern const uint16_t crc_ccitt[] PROGMEM; -const uint16_t crc_ccitt[] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 -}; - -void ResetDiskState(); - -uint16_t writeErrorNumber; - -void error(const char* msg) -{ - bool wasWriteError = writeError; - uint16_t wasWriteErrorNumber = writeErrorNumber; - - ResetDiskState(); // clears writeError and writeErrorNumber - - LcdClear(); - LcdGoto(0,0); - if (wasWriteError) - LcdTinyStringP(PSTR("WRITE ERROR "), TEXT_INVERSE); - else - LcdTinyStringP(PSTR("FATAL ERROR "), TEXT_INVERSE); - LcdGoto(0,1); - LcdTinyString(msg, TEXT_NORMAL); - - if (wasWriteError) - { - snprintf(textBuf, TEXTBUF_SIZE, "%u", wasWriteErrorNumber); - LcdGoto(0,5); - LcdTinyString(textBuf, TEXT_NORMAL); - } - - while (1); -} - -void InitPorts() -{ - // set all data lines as outputs, MSB (RD_ACK/WR_TICK) as input - DDR(CPLD_DATA_PORT) = 0x7F; - - // initialize the other output lines - DDR(CPLD_TACH_PORT) |= (1<> 4; - if (speedZone > 4) - speedZone = 4; - - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - driveTachHalfPeriod = F_CPU / (2 * zoneRPM[speedZone]); - // OCR1A update will be performed during the next sector 0 read - } - - TIFR1 = (1 << OCF1A); // Clear the timer 1 compare A match flag. Not sure this is actually necessary. -} - -uint16_t trackStart(uint8_t trackNumber) -{ - return mfmMode ? trackNumber * 18 : pgm_read_word(&sony_track_start[trackNumber]); -} - -uint8_t trackLength(uint8_t trackNumber) -{ - return mfmMode ? 18 : pgm_read_byte(&sony_track_len[trackNumber]); -} - -#define BUFFER_DIRTY 1 -#define BUFFER_DATA_VALID 2 -#define BUFFER_LOCKED 4 - -volatile uint8_t bufferState[NUM_BUFFERS]; -volatile uint8_t wrTrack; -volatile uint8_t wrSide; -volatile uint8_t wrSector; - -// these variables are used only within the interrupt routine, and do not need to be declared volatile -uint8_t wrTick; -uint16_t writeCount; -uint8_t writeTemp; -uint8_t currentWriteBufferNumber; -uint8_t ck5, ck6, ck7; -uint8_t XBit; -uint8_t* pSectorBuf; - -void WriteError() -{ - writeMode = false; - restartDisk = true; - writeError = true; - writeCount = 0; -} - -// pin state change interrupt: STEP -ISR(PCINT3_vect) -{ - // step to a new track? - if (bit_is_set(PIN(CPLD_STEP_REQ_PORT), CPLD_STEP_REQ_PIN)) - { - // determine the range of dirty sector buffers - uint8_t trackLen = trackLength(currentTrack); - uint8_t firstDirtyBuffer = NUM_BUFFERS, lastDirtyBuffer=0; - - for (uint8_t i=0; i= SECTOR_DATA_SECTORNUM_START) - { - strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); - writeErrorNumber = 1000 + writeCount; - WriteError(); - } - - restartDisk = true; - } -} - -// pin state change interrupt: SIDE, WR_REQ -ISR(PCINT2_vect) -{ - // did the current side change? - uint8_t newSide = ((PIN(CPLD_CURRENT_SIDE_PORT) >> CPLD_CURRENT_SIDE_PIN) & 0x01); - if (newSide != currentSide) - { - if (numberOfDiskSides == 2) - currentSide = newSide; - else - currentSide = 0; - restartDisk = true; - - // premature end of a write? - if (writeCount >= SECTOR_DATA_SECTORNUM_START) - { - strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); - writeErrorNumber = 2000 + writeCount; - WriteError(); - } - } - - // did the read/write mode change? RD_RW: 0 = write, 1 = read - uint8_t wreqBit = bit_is_clear(PIN(CPLD_WR_REQ_PORT), CPLD_WR_REQ_PIN); - if (wreqBit != writeMode) - { - writeMode = wreqBit; - - if (writeMode) - { - // switch the DATA pins to inputs - DDR(CPLD_DATA_PORT) = 0; - - // indicate that the data bus has been released - PORT(CPLD_DATA_HIZ_PORT) |= (1<= SECTOR_DATA_SECTORNUM_START) - { - strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); - writeErrorNumber = 3000 + writeCount; - WriteError(); - } - } - - restartDisk = true; - } -} - -void HandleGCRWrite() -{ - uint8_t diskByte = 0x80 | PIN(CPLD_DATA_PORT); - - if (writeCount < SECTOR_DATA_ENCODED_TAGS_START) - { - // look for the sector header - // the final header byte is the sector number - if (writeCount == SECTOR_DATA_SECTORNUM_START) - { - uint8_t sector = pgm_read_byte(&disk_byte_to_sony[diskByte - 0x96]); - - if (sector >= trackLength(currentTrack)) - { - snprintf(textBuf, TEXTBUF_SIZE, "bad sector %d for t%d", sector, currentTrack); - writeErrorNumber = 60; - WriteError(); - } - - uint8_t trackLen = trackLength(currentTrack); - currentWriteBufferNumber = trackLen * currentSide + sector; - - if (bufferState[currentWriteBufferNumber] & BUFFER_LOCKED) - { - snprintf(textBuf, TEXTBUF_SIZE, "buf locked %d/%d:%d", currentTrack, currentSide, sector); - writeErrorNumber = 61; - WriteError(); - } - - pSectorBuf = sectorBuf[currentWriteBufferNumber]; - bufferState[currentWriteBufferNumber] |= BUFFER_LOCKED; - bufferState[currentWriteBufferNumber] &= ~BUFFER_DATA_VALID; - wrTrack = currentTrack; - wrSide = currentSide; - wrSector = sector; - - // turn on the LED when receiving a sector write - PORT(STATUS_LED_PORT) &= ~(1<> 7; - ck7 = (ck7 << 1) | XBit; - break; - - case 1: - b = (writeTemp & 0xC0) | dataIn; // A7 A6 0 0 0 0 0 0 | 0 0 A5 A4 A3 A2 A1 A0 - b ^= ck7; - - if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) - *pSectorBuf++ = b; - - //ADDX(ck5, b); - addResult = (uint16_t)ck5 + b + XBit; - ck5 = addResult & 0xFF; - XBit = addResult >> 8; - writeTemp <<= 2; // B7 B6 C7 C6 0 0 0 0 - break; - - case 2: - b = (writeTemp & 0xC0) | dataIn; // B7 B6 0 0 0 0 0 0 | 0 0 B5 B4 B3 B2 B1 B0 - b ^= ck5; - - if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) - *pSectorBuf++ = b; - - //ADDX(ck6, b); - addResult = (uint16_t)ck6 + b + XBit; - ck6 = addResult & 0xFF; - XBit = addResult >> 8; - writeTemp <<= 2; // C7 C6 0 0 0 0 0 0 - break; - - case 3: - b = writeTemp | dataIn; // C7 C6 0 0 0 0 0 0 | 0 0 C5 C4 C3 C2 C1 C0 - b ^= ck6; - - if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) - *pSectorBuf++ = b; - - //ADDX(ck7, b); - addResult = (uint16_t)ck7 + b + XBit; - ck7 = addResult & 0xFF; - XBit = addResult >> 8; - break; - } - } - else - { - // verify the checksum - if (writeCount == SECTOR_DATA_CHECKSUM_START) - { - writeTemp = dataIn; - writeTemp <<= 2; - } - else if (writeCount == SECTOR_DATA_CHECKSUM_START+1) - { - b = (writeTemp & 0xC0) | dataIn; - writeTemp <<= 2; - if (b != ck5) - { - strncpy(textBuf, "checksum failure 0", TEXTBUF_SIZE); - writeErrorNumber = 62; - WriteError(); - } - } - else if (writeCount == SECTOR_DATA_CHECKSUM_START+2) - { - b = (writeTemp & 0xC0) | dataIn; - writeTemp <<= 2; - if (b != ck6) - { - strncpy(textBuf, "checksum failure 1", TEXTBUF_SIZE); - writeErrorNumber = 63; - WriteError(); - } - } - else if (writeCount == SECTOR_DATA_CHECKSUM_START+3) - { - b = writeTemp | dataIn; - writeTemp <<= 2; - if (b != ck7) - { - strncpy(textBuf, "checksum failure 2", TEXTBUF_SIZE); - writeErrorNumber = 64; - WriteError(); - } - - // success! - bufferState[currentWriteBufferNumber] |= BUFFER_DATA_VALID; - bufferState[currentWriteBufferNumber] |= BUFFER_DIRTY; - bufferState[currentWriteBufferNumber] &= ~BUFFER_LOCKED; - - // turn off the LED at the end of a sector write - PORT(STATUS_LED_PORT) |= (1<> 8) ^ 0xA1]); - crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xA1]); - crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xA1]); - crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xFB]); - - for (uint16_t i=0; i> 8) ^ sectorBuf[bufferNumber][i]]); - } - - if (crc != receivedCRC) - { - strncpy(textBuf, "checksum fail", TEXTBUF_SIZE); - writeErrorNumber = 70; - WriteError(); - } -} - -// pin state change interrupt: WR_TICK -ISR(PCINT0_vect) -{ - uint8_t wrTickBit = bit_is_set(PIN(CPLD_RD_ACK_WR_TICK_PORT), CPLD_RD_ACK_WR_TICK_PIN); - - // was a new byte written? - if (writeMode && wrTickBit != wrTick) - { - wrTick = wrTickBit; - - if (!mfmMode) - { - HandleGCRWrite(); - } - else - { - if (wrTickBit == 0) - { - // high nibble arrives first - writeTemp = (PIN(CPLD_DATA_PORT) << 4) & 0xF0; - return; - } - else - { - writeTemp |= (PIN(CPLD_DATA_PORT) & 0x0F); - - if (writeCount == 2) - { - if (writeTemp == 0xFB) - { - writeCount++; - - // header received OK! - currentWriteBufferNumber = currentSector; // assume the buffer to write was the last one read - - if (bufferState[currentWriteBufferNumber] & BUFFER_LOCKED) - { - snprintf(textBuf, TEXTBUF_SIZE, "buf locked %d/%d:%d", currentTrack, currentSide, currentSector); - writeErrorNumber = 71; - WriteError(); - return; - } - - pSectorBuf = sectorBuf[currentWriteBufferNumber]; - bufferState[currentWriteBufferNumber] |= BUFFER_LOCKED; - bufferState[currentWriteBufferNumber] &= ~BUFFER_DATA_VALID; - wrTrack = currentTrack; - wrSide = currentSide; - wrSector = currentSector; // assume the buffer to write was the last one read - - // turn on the LED when receiving a sector write - PORT(STATUS_LED_PORT) &= ~(1<> 2) | ((__c1 & 0xC0) >> 4) | ((__c2 & 0xC0) >> 6)) - -// rotate left -#define rot_ck0(__ck0) \ - do { \ - __ck0 &= 0xFF; \ - __ck0 = (__ck0 << 1) | (__ck0 >> 7);\ - } while(0) - -// ADC __ckr, __in; __out = __in ^ __ckl -#define enc_byte(__in, __out, __ckl, __ckr) \ - do { \ - uint8_t __d = __in; \ - __ckr += __d; \ - __ckr += (__ckl & 0x100) >> 8; \ - __ckl &= 0xFF; \ - __out = __d ^ __ckl; \ - } while(0) - -#define SendByteAndCheckRestart(b) \ - do { \ - if (restartDisk) \ - goto restart; \ - SendByte(b); \ - } while(0) - -void SendMFMSync() -{ - // send A1 sync - - // SendByte - // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups - PORT(CPLD_DATA_PORT) = 0x0A; // data in bits 3-0, sync flag in bit 4 - PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 8) ^ 0xA1]); - - // SendByte - // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups - PORT(CPLD_DATA_PORT) = 0x11; // data in bits 3-0, sync flag in bit 4 - PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 4) & 0x0F; - - //if (restartDisk) - // return; - - // SendByte - // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups - PORT(CPLD_DATA_PORT) = out; - PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 8) ^ data]); - - //if (restartDisk) - // return; - - // SendByte - // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups - PORT(CPLD_DATA_PORT) = out; - PORT(CPLD_RD_READY_TK0_PORT) |= (1< 128) - lcd_vop--; - } - else if (bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) - { - eeprom_update_byte((uint8_t*)1, lcd_vop); - break; - } - - LcdWrite(LCD_CMD, 0x21); // LCD Extended Commands. - LcdWrite(LCD_CMD, lcd_vop); // Set LCD Vop (Contrast). - LcdWrite(LCD_CMD, 0x20); - } -} - -void PromptForFirmwareUpdate() -{ - LcdGoto(0,0); - LcdClear(); - LcdGoto(0,0); - LcdTinyStringP(PSTR("CPLD FIRMWARE UPDATE"), TEXT_NORMAL); - LcdGoto(0,2); - LcdTinyStringP(PSTR("Release buttons to"), TEXT_NORMAL); - LcdGoto(0,3); - LcdTinyStringP(PSTR("begin"), TEXT_NORMAL); - - // wait for the buttons to be released - while (bit_is_clear(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) || - bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) || - bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) - {} - - LcdGoto(0,2); - LcdTinyStringP(PSTR("NEXT: Load firmware"), TEXT_NORMAL); - LcdGoto(0,3); - LcdTinyStringP(PSTR("PREV: Cancel"), TEXT_NORMAL); - _delay_ms(400); - - // wait for a button press - while (bit_is_set(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && - bit_is_set(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && - bit_is_set(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) - {} - - if (bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN)) - { - UpdateFirmware(); - } - else - { - LcdClear(); - } -} - -uint32_t imageFirstBlock, imageLastBlock; - -bool OpenImageFile() -{ - LcdClear(); - LcdGoto(0,0); - LcdTinyString(selectedLongFile, TEXT_NORMAL); - - LcdGoto(0,1); - - // open the disk image file - // to-do: check if the file is read-only on the card - bool openOK = true; - if (!f.open(selectedFile, O_RDWR)) - { - if (f.open(selectedFile, O_RDONLY)) - { - // TODO: How do we tell the CPLD the disk is read-only? - readOnly = true; - } - else - { - LcdTinyStringP(PSTR("error opening image"), TEXT_NORMAL); - openOK = false; - } - } - else - { - if (selectedFileType == DISK_IMAGE_400K || selectedFileType == DISK_IMAGE_DISKCOPY_400K) - { - numberOfDiskSides = 1; - } - else - { - numberOfDiskSides = 2; - } - } - - // get address of file on SD - if (openOK && !f.contiguousRange(&imageFirstBlock, &imageLastBlock)) - { - LcdTinyStringP(PSTR("image not contiguous"), TEXT_NORMAL); - openOK = false; - } - - if (!openOK) - { - _delay_ms(4000); // wait 4 seconds - } - else - { - LcdGoto(0,1); - // show disk image type - switch (selectedFileType) - { - case DISK_IMAGE_400K: - LcdTinyStringP(PSTR("400K raw image"), TEXT_NORMAL); - break; - - case DISK_IMAGE_800K: - LcdTinyStringP(PSTR("800K raw image"), TEXT_NORMAL); - break; - - case DISK_IMAGE_1440K: - LcdTinyStringP(PSTR("1440K raw image"), TEXT_NORMAL); - mfmMode = true; - break; - - case DISK_IMAGE_DISKCOPY_400K: - LcdTinyStringP(PSTR("400K DiskCopy image"), TEXT_NORMAL); - break; - - case DISK_IMAGE_DISKCOPY_800K: - LcdTinyStringP(PSTR("800K DiskCopy image"), TEXT_NORMAL); - break; - - case DISK_IMAGE_DISKCOPY_1440K: - LcdTinyStringP(PSTR("1440K DiskCopy image"), TEXT_NORMAL); - mfmMode = true; - break; - - default: - break; - } - - selectedFileIsDiskCopyFormat = (selectedFileType >= DISK_IMAGE_DISKCOPY_400K); - - if (bit_is_set(PIN(CARD_WPROT_PORT), CARD_WPROT_PIN)) - readOnly = true; - - // mount DiskCopy images read-only - if (selectedFileIsDiskCopyFormat) - readOnly = true; - - uint16_t volumeNameOffset = selectedFileIsDiskCopyFormat ? 0x424 + 0x54 : 0x424; - f.seekSet(volumeNameOffset); // offset of the Macintosh disk name in the image file - f.read(§orBuf[0][0], SECTOR_DATA_SIZE); - int nameLen = sectorBuf[0][0]; - uint8_t* name = §orBuf[0][1]; - name[nameLen] = 0; - name[21] = 0; // in case nameLen was bogus, terminate the string after 21 chars, which is the longest displayable name on the LCD - LcdGoto(0,2); - LcdTinyString((char*)name, TEXT_NORMAL); - LcdGoto(0,4); - LcdTinyStringP(PSTR("Track Side"), TEXT_NORMAL); - - // show a lock icon if the disk image is mounted as read-only - if (readOnly) - { - LcdGoto(77,0); - LcdWrite(LCD_DATA, 0x00); - LcdWrite(LCD_DATA, 0x78); - LcdWrite(LCD_DATA, 0x7E); - LcdWrite(LCD_DATA, 0x79); - LcdWrite(LCD_DATA, 0x79); - LcdWrite(LCD_DATA, 0x7E); - LcdWrite(LCD_DATA, 0x78); - } - } - - f.close(); - return openOK; -} - -void ResetDiskState() -{ - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - // useless code to prevent the "unused" bootloader_info array from being optimized away when optimizations are turned on - // there's probably a nicer way to accomplish this. - currentTrack = bootloader_info[currentTrack]; - - InitPorts(); - - currentTrack = 0; - prevTrack = 0; - restartDisk = false; - currentSide = 0; - prevSide = 0; - writeMode = 0; - diskInserted = false; - numberOfDiskSides = 2; - currentSector = 0; - readOnly = false; - mfmMode = false; - writeError = false; - writeDisplayTimer = 0; - tachFlutter = 0; - writeErrorNumber = 0; - writeCount = 0; - - for (uint8_t i=0; i= trackLen - 1) - return 0; - else - return prevSectorNumber + 1; - } - else - { - uint8_t halfTrackLen = (trackLen + 1) >> 1; - - // process sectors in interleaved order: - // 12 sector tracks: 0 6 1 7 2 8 3 9 4 10 5 11 - // 11 sector tracks: 0 6 1 7 2 8 3 9 4 10 5 - // 10 sector tracks: 0 5 1 6 2 7 3 8 4 9 - // 9 sector tracks: 0 5 1 6 2 7 3 8 4 - // 8 sector tracks: 0 4 1 5 2 6 3 7 - // This is how real floppies are formatted, and should improve read performance if the Mac - // can't completely process sector N before sector N+1 begins. It should also improve sector-by-sector - // write performance, because the Mac alternately reads (address header) and writes (data section) in - // this mode, and proper interleaving means it will read the desired address header sooner if the Mac - // isn't fast enough to process the sectors linearly (which it likely isn't). - if (prevSectorNumber > trackLen - 1 || - ((trackLen & 1) == 0 && prevSectorNumber == trackLen - 1) || - ((trackLen & 1) == 1 && prevSectorNumber == halfTrackLen - 1)) - return 0; - else if (prevSectorNumber < halfTrackLen) - return prevSectorNumber + halfTrackLen; - else - return prevSectorNumber + 1 - halfTrackLen; - } -} - -void ReadDiskCopy42Block(SdFat& sd, uint32_t blockToRead, uint8_t bufferNumber) -{ - // for a DiskCopy 4.2 image, read two blocks into a temp buffer, then copy the unaligned data into the sector buffer. - uint16_t i; - - if (!sd.card()->readStart(blockToRead)) - error("SD read start error"); - - // read part 1 - if (!sd.card()->readData(extraBuf)) - error("SD read error D"); - for (i=0; i<512-0x54; i++) - sectorBuf[bufferNumber][i] = extraBuf[0x54 + i]; - - // read part 2 - if (!sd.card()->readData(extraBuf)) - error("SD read error D"); - for (i=512-0x54; i<512; i++) - sectorBuf[bufferNumber][i] = extraBuf[0x54 + i - 512]; - - sd.card()->readStop(); -} - -void FlushDirtySectors(SdFat& sd, uint8_t trackNumber) -{ - uint8_t trackLen = trackLength(trackNumber); - uint8_t firstDirtyBuffer = NUM_BUFFERS, lastDirtyBuffer=0; - - // determine the dirty range - for (uint8_t i=0; ireadBlock(blockToRead, sectorBuf[i])) - error("SD read error W"); - } - } - - uint32_t firstBlockToWrite = imageFirstBlock + ((uint32_t)trackStart(trackNumber) * numberOfDiskSides + firstDirtyBuffer); - - if (mfmMode) - firstBlockToWrite += trackLen * wrSide; - - uint32_t numBuffersToWrite = lastDirtyBuffer + 1 - firstDirtyBuffer; - - if (!sd.card()->writeStart(firstBlockToWrite, numBuffersToWrite)) - error("SD writeStart fail"); - - for (uint8_t i=firstDirtyBuffer; i<=lastDirtyBuffer; i++) - { - if (!sd.card()->writeData(sectorBuf[i])) - error("SD write error"); - - bufferState[i] &= ~BUFFER_DIRTY; - bufferState[i] &= ~BUFFER_LOCKED; - } - - if (!sd.card()->writeStop()) - error("SD writeStop fail"); - - writeDisplayTimer = 25; - millitimerOff(); - - uint32_t writeTime = millis() - t0; - - snprintf(textBuf, TEXTBUF_SIZE, "Saved trk %02d in %lu ", trackNumber, writeTime); - LcdGoto(0,5); - LcdTinyString(textBuf, TEXT_NORMAL); - } - } -} - -int main(void) -{ - millitimerInit(); - ResetDiskState(); - - ShowVersion(); - - LcdClear(); - - sei(); - _delay_ms(100); // wait for pending interrupts?? - - millitimerOn(); - _delay_ms(100); // wait for pending interrupts?? - - // if select and next are both held down, enter contrast adjust mode - if (bit_is_set(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && - bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && - bit_is_clear(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) - { - AdjustContrast(); - } - - SdFat sd; - if (!sd.init(SPI_FULL_SPEED)) - { - snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData()); - error(textBuf); - } - - millitimerOff(); - - // if prev and next are both held down, enter firmware update mode - if (bit_is_clear(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && - bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && - bit_is_set(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) - { - PromptForFirmwareUpdate(); - } - - InitDiskMenu(sd); - DrawDiskMenu(sd); - - // main loop - while (true) - { - if (writeError) - { - // report error encounted in the interrupt routine - error(textBuf); - } - - cli(); - uint8_t trackNumber = currentTrack; // save track in a local var, since currentTrack is volatile - uint8_t sideNumber = currentSide; // save side in a local var, since currentSide is volatile - restartDisk = false; - sei(); - - if (diskInserted) - { - // show the current track and side - snprintf(textBuf, TEXTBUF_SIZE, "%02d", trackNumber); - LcdGoto(24,4); - LcdTinyString(textBuf, TEXT_NORMAL); - snprintf(textBuf, TEXTBUF_SIZE, "%d ", sideNumber); - LcdGoto(56,4); - LcdTinyString(textBuf, TEXT_NORMAL); - - // sync RAM buffer with SD card when switching tracks, or also when switching sides for mfmMode - if (prevTrack != trackNumber || (mfmMode && (prevSide != sideNumber))) - { - // write any dirty sectors from the previous track/side back to the SD card - FlushDirtySectors(sd, prevTrack); - prevTrack = trackNumber; - prevSide = sideNumber; - - // Also mark all the buffers on this track as invalid, since they don't contain valid data for the new track. - for (uint8_t i=0; i= trackLen) - currentSector = 0; - - bool prevMotorOn = !bit_is_clear(PIN(CPLD_STEP_DIR_MOTOR_ON_PORT), CPLD_STEP_DIR_MOTOR_ON_PIN); - - while (true) - { - // check for disk eject - if (bit_is_set(PIN(CPLD_EJECT_REQ_PORT), CPLD_EJECT_REQ_PIN)) - { - PORT(CPLD_RD_READY_TK0_PORT) &= ~(1<readBlock(blockToRead, sectorBuf[bufferNumber])) - error("SD read error R"); - } - - millitimerOff(); - - bufferState[bufferNumber] |= BUFFER_DATA_VALID; - bufferState[bufferNumber] &= ~BUFFER_LOCKED; - } - - if (currentSector == 0) - { - if (motorOn) - { - // toggle LED during drive activity - PORT(STATUS_LED_PORT) ^= (1< 1) - writeDisplayTimer--; - } - - // "Flutter" the drive's TACH speed slightly, every time we pass sector 0 (about every 100-150ms). This avoids a bug - // in P_Sony_MakeSpdTbl in the 64K ROM (used in the Mac 128K and Mac 512K) where - // the Mac will crash if two successive TACH measurements see the exact same speed. - tachFlutter += 25; - if (tachFlutter >= 125) - tachFlutter = 0; - - // Set the timeout. OC1A will toggle after this many counts. New timeout threshold won't take effect until the next timeout. - OCR1A = driveTachHalfPeriod - tachFlutter; - } - - if (mfmMode) - { - // insert sector-to-sector gap bytes - for (uint8_t i=0; i<50; i++) - { - SendMFMAndCheckRestart(0x4E); - } - - // insert sync bytes - for (uint8_t i=0; i<12; i++) - { - SendMFMAndCheckRestart(0x00); - } - - // send the address block - crc = 0xFFFF; // reset CRC - SendMFMSync(); - SendMFMSync(); - SendMFMSync(); - SendMFMAndCheckRestart(0xFE); - SendMFMAndCheckRestart(trackNumber); - SendMFMAndCheckRestart(sideNumber); - SendMFMAndCheckRestart(currentSector+1); // MFM sector numbers are 1-based - SendMFMAndCheckRestart(2); // size = 128 * 2^N bytes, so 2 means 512 - uint8_t crc0 = (crc >> 8) & 0xFF; - uint8_t crc1 = crc & 0xFF; - SendMFMAndCheckRestart(crc0); - SendMFMAndCheckRestart(crc1); - - // insert Address to Data gap bytes - for (uint8_t i=0; i<22; i++) - { - SendMFMAndCheckRestart(0x4E); - } - - // insert sync bytes - for (uint8_t i=0; i<12; i++) - { - SendMFMAndCheckRestart(0x00); - } - - // send the data block - crc = 0xFFFF; // reset CRC - SendMFMSync(); - SendMFMSync(); - SendMFMSync(); - SendMFMAndCheckRestart(0xFB); - - for (uint16_t i=0; i> 8) & 0xFF; - crc1 = crc & 0xFF; - SendMFMAndCheckRestart(crc0); - SendMFMAndCheckRestart(crc1); - } - else - { - // ensure a short gap between sectors - otherwise once they're all cached, one sector will appear - // to immediately follow another on disk, which may cause problems for the Mac. - // Bad voodoo here: - // 1. In the Finder StuffIt copy test that sometimes dies after the first 18 tracks, the length of delay here - // seems to affect what track it will freeze on. - // 2. With a longer delay here, the first ~10 sectors of copying seem to have fewer or no "long writes". - // 3. Depending on the delay here, the Transcend 2GB SD card sometimes gets "writeStop fail" when saving tracks. - for (uint16_t i=0; i> 6)); - uint8_t checksum = (uint8_t)((trackLow ^ currentSector ^ trackHigh ^ format) & 0x3F); - - SendByteAndCheckRestart(0xD5); - SendByteAndCheckRestart(0xAA); - SendByteAndCheckRestart(0x96); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[trackLow])); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[currentSector])); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[trackHigh])); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[format])); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[checksum])); - SendByteAndCheckRestart(0xDE); - SendByteAndCheckRestart(0xAA); - - // insert sync bytes between the address and data blocks - for (uint8_t i=0; i 0) - { - diskMenuSelection--; - DrawDiskMenu(sd); - _delay_ms(200); - } - } - else if (bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN)) - { - diskMenuSelection++; - DrawDiskMenu(sd); - _delay_ms(200); - } - else if (bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) - { - if (selectedFileType == DISK_IMAGE_DIRECTORY) - { - // remember where we came from, so we can get back later - char* pSubdirName = ((char*)sectorBuf[23]) + ((SHORTFILENAME_LEN+1) * subdirDepth); - strncpy(pSubdirName, selectedFile, SHORTFILENAME_LEN+1); - subdirDepth++; - - sd.chdir(selectedFile, true); - - diskMenuSelection = 0; - LcdClear(); - InitDiskMenu(sd); - DrawDiskMenu(sd); - _delay_ms(400); - } - else if (selectedFileType == DISK_IMAGE_UP_DIRECTORY) - { - subdirDepth--; - sd.chdir(true); // go to root directory - - for (uint8_t i=0; i -#ifdef USE_BOOTLDR_MAIN - int main(void) { while(1) { //TODO:: Please write your application code } -} - -#endif +} \ No newline at end of file diff --git a/arduino/bootldr/bootldr/bootldr.cproj b/floppy_emu_arduino/bootldr/bootldr/bootldr.cproj similarity index 100% rename from arduino/bootldr/bootldr/bootldr.cproj rename to floppy_emu_arduino/bootldr/bootldr/bootldr.cproj diff --git a/arduino/bootldr/bootldr/diskio.h b/floppy_emu_arduino/bootldr/bootldr/diskio.h similarity index 100% rename from arduino/bootldr/bootldr/diskio.h rename to floppy_emu_arduino/bootldr/bootldr/diskio.h diff --git a/arduino/bootldr/bootldr/integer.h b/floppy_emu_arduino/bootldr/bootldr/integer.h similarity index 100% rename from arduino/bootldr/bootldr/integer.h rename to floppy_emu_arduino/bootldr/bootldr/integer.h diff --git a/arduino/bootldr/bootldr/lcd.c b/floppy_emu_arduino/bootldr/bootldr/lcd.c similarity index 96% rename from arduino/bootldr/bootldr/lcd.c rename to floppy_emu_arduino/bootldr/bootldr/lcd.c index fd19604..b73a8ea 100755 --- a/arduino/bootldr/bootldr/lcd.c +++ b/floppy_emu_arduino/bootldr/bootldr/lcd.c @@ -146,4 +146,4 @@ void LcdInit() LcdGoto(0,0); LcdClear(); -} +} \ No newline at end of file diff --git a/arduino/bootldr/bootldr/lcd.h b/floppy_emu_arduino/bootldr/bootldr/lcd.h similarity index 100% rename from arduino/bootldr/bootldr/lcd.h rename to floppy_emu_arduino/bootldr/bootldr/lcd.h diff --git a/arduino/bootldr/bootldr/main.c b/floppy_emu_arduino/bootldr/bootldr/main.c similarity index 100% rename from arduino/bootldr/bootldr/main.c rename to floppy_emu_arduino/bootldr/bootldr/main.c diff --git a/arduino/bootldr/bootldr/mmc.c b/floppy_emu_arduino/bootldr/bootldr/mmc.c similarity index 100% rename from arduino/bootldr/bootldr/mmc.c rename to floppy_emu_arduino/bootldr/bootldr/mmc.c diff --git a/arduino/bootldr/bootldr/pff.c b/floppy_emu_arduino/bootldr/bootldr/pff.c similarity index 100% rename from arduino/bootldr/bootldr/pff.c rename to floppy_emu_arduino/bootldr/bootldr/pff.c diff --git a/arduino/bootldr/bootldr/pff.h b/floppy_emu_arduino/bootldr/bootldr/pff.h similarity index 100% rename from arduino/bootldr/bootldr/pff.h rename to floppy_emu_arduino/bootldr/bootldr/pff.h diff --git a/arduino/bootldr/how to configure bootloader.txt b/floppy_emu_arduino/bootldr/how to configure bootloader.txt similarity index 100% rename from arduino/bootldr/how to configure bootloader.txt rename to floppy_emu_arduino/bootldr/how to configure bootloader.txt diff --git a/arduino/floppyemu/cardtest.cpp b/floppy_emu_arduino/cardtest/cardtest.cpp old mode 100644 new mode 100755 similarity index 95% rename from arduino/floppyemu/cardtest.cpp rename to floppy_emu_arduino/cardtest/cardtest.cpp index f24bdd6..c08effc --- a/arduino/floppyemu/cardtest.cpp +++ b/floppy_emu_arduino/cardtest/cardtest.cpp @@ -1,235 +1,219 @@ -/* - Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved. - - Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported - license. (CC BY-NC 3.0) The terms of the license may be viewed at - http://creativecommons.org/licenses/by-nc/3.0/ - - Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/ - - Permissions beyond the scope of this license may be available at www.bigmessowires.com - or from mailto:steve@bigmessowires.com. -*/ - -#ifdef ARDUINO - -#include - -#include -#include -#include "noklcd.h" - -#else - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "portmacros.h" -#include "noklcd.h" -#include "millitimer.h" -#include "SdFat.h" -#include "SdBaseFile.h" -#include "micro.h" -#include "ports.h" -#include "diskmenu.h" -#include "cardtest.h" - -#ifdef ENABLE_ORIGINAL_COMPILER_WORKAROUND - -// work-around for compiler bug -#undef PROGMEM -#define PROGMEM __attribute__(( section(".progmem.data") )) -#undef PSTR -#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];})) - -#endif -#endif - - -#define STATUS_LED_PORT B -#define STATUS_LED_PIN 3 - -#define TEXTBUF_SIZE 22 -extern char textBuf[]; -extern uint8_t sectorBuf[512]; - -void CardTest() -{ - LcdClear(); - - //SdFat sd; - SDClass sd(4); - - if (!sd.init(SPI_HALF_SPEED)) - { - snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData()); - LcdGoto(0,0); - LcdTinyString(textBuf, TEXT_NORMAL); - while(1); - } - - cid_t cid; - - uint32_t cardSize = sd.card()->cardSize(); - cardSize /= (2L*1024L); - - sd.card()->readCID(&cid); - - snprintf(textBuf, TEXTBUF_SIZE, "CID %d %c%c%c%c%c %lu MB", cid.mid, cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cardSize); - LcdGoto(0,0); - LcdTinyString(textBuf, TEXT_NORMAL); - - csd_t csd; - sd.card()->readCSD(&csd); - - uint8_t writeBlockPow; // write block length, log2 - uint8_t sectorSizeCnt; // minimum erasable size, in write blocks - - if (csd.v1.csd_ver == 1) - { - csd1_t* c = &csd.v1; - - writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low; - sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low; - } - else - { - csd2_t* c = &csd.v2; - - writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low; - sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low; - } - - sectorSizeCnt += 1; // these all seem to be 2**n - 1? - - uint32_t writeBlock=1; - for (uint8_t i=0; ireadBlock(imageFirstBlock + b, sectorBuf)) - { - LcdGoto(0,2); - LcdTinyStringP(PSTR("SD read error"), TEXT_NORMAL); - while(1); - } - - // alter the data, to prevent any kind of compression/optimization on the card - for (uint16_t i=0; i<512; i++) - { - sectorBuf[i] ^= sectorBuf[i+1]; - } - - // blink the LED - if ((writeCount & 0x7) == 0) - PORT(STATUS_LED_PORT) ^= (1<writeBlock(imageFirstBlock + b, sectorBuf)) - { - LcdGoto(0,2); - LcdTinyStringP(PSTR("SD write error"), TEXT_NORMAL); - while(1); - } - - uint32_t writeTime = millis() - t0; - - // update stats - writeCount++; - writeTotalTime += writeTime; - if (writeTime > 20) - above20Count++; - if (writeTime > worstTime) - worstTime = writeTime; - - // pseudo-interleave - if ((cnt & 1) == 0) - b += 6; - else - b -= 5; - - _delay_ms(3); - } - } - - uint32_t avg = (writeTotalTime + (writeCount >> 1))/ writeCount; - - LcdGoto(0,2); - LcdTinyStringP(PSTR("AVG.ms/MAX.ms/LONG.%"), TEXT_NORMAL); - - snprintf(textBuf, TEXTBUF_SIZE, "512B RRWI %lu/%lu/%lu", avg, worstTime, above20Count*100/writeCount); - LcdGoto(0,3); - LcdTinyString(textBuf, TEXT_NORMAL); - - // Card: actual capacity, block size, erase size, best test result (random read-write interleaved) average/max/percent "long" over 20ms - // ---------------------------------------------------------- - // PNY class 10 8GB: 7708 MB, 512B block, 64K erase. 512B RRWI 10/189/1 (random read-write interleave) - // SanDisk unrated Ultra II 2GB: 1938 MB, 1024B block, 32K erase. 512B RRWI 7/79/0 - // Transcend unrated 2GB: 1875 MB, 1024B block, 128K erase. 512B RRWI 3/103/0 - // SanDisk unrated 128MB: 120 MB, 512B block, 16K erase. 512B RRWI 5/94/1 - - // enabling the TACH stuff seems to cause some cards to get errors during this test. Coupling between traces? Why doesn't it happen during normal operation? - - // Transcend unrated 2GB: Finder consistently "goes to sleep" after copying first 19 tracks, but worked twice after 3 tries. Maybe it's too fast? - - - - while(1); -} +/* + Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved. + + Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported + license. (CC BY-NC 3.0) The terms of the license may be viewed at + http://creativecommons.org/licenses/by-nc/3.0/ + + Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/ + + Permissions beyond the scope of this license may be available at www.bigmessowires.com + or from mailto:steve@bigmessowires.com. +*/ +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "portmacros.h" +#include "noklcd.h" +#include "millitimer.h" +#include "SdFat.h" +#include "SdBaseFile.h" +#include "micro.h" +#include "ports.h" +#include "diskmenu.h" +#include "cardtest.h" + +#ifdef PROGMEM_WORKAROUND +// work-around for compiler bug +#undef PROGMEM +#define PROGMEM __attribute__(( section(".progmem.data") )) +#undef PSTR +#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];})) +#endif + + +#define STATUS_LED_PORT B +#define STATUS_LED_PIN 3 + +#define TEXTBUF_SIZE 22 +extern char textBuf[]; +extern uint8_t sectorBuf[512]; + +void CardTest() +{ + LcdClear(); + + SdFat sd; + if (!sd.init(SPI_HALF_SPEED)) + { + snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData()); + LcdGoto(0,0); + LcdTinyString(textBuf, TEXT_NORMAL); + while(1); + } + + cid_t cid; + + uint32_t cardSize = sd.card()->cardSize(); + cardSize /= (2L*1024L); + + sd.card()->readCID(&cid); + + snprintf(textBuf, TEXTBUF_SIZE, "CID %d %c%c%c%c%c %lu MB", cid.mid, cid.pnm[0], cid.pnm[1], cid.pnm[2], cid.pnm[3], cid.pnm[4], cardSize); + LcdGoto(0,0); + LcdTinyString(textBuf, TEXT_NORMAL); + + csd_t csd; + sd.card()->readCSD(&csd); + + uint8_t writeBlockPow; // write block length, log2 + uint8_t sectorSizeCnt; // minimum erasable size, in write blocks + + if (csd.v1.csd_ver == 1) + { + csd1_t* c = &csd.v1; + + writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low; + sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low; + } + else + { + csd2_t* c = &csd.v2; + + writeBlockPow = 4*c->write_bl_len_high + c->write_bl_len_low; + sectorSizeCnt = 2*c->sector_size_high + c->sector_size_low; + } + + sectorSizeCnt += 1; // these all seem to be 2**n - 1? + + uint32_t writeBlock=1; + for (uint8_t i=0; ireadBlock(imageFirstBlock + b, sectorBuf)) + { + LcdGoto(0,2); + LcdTinyStringP(PSTR("SD read error"), TEXT_NORMAL); + while(1); + } + + // alter the data, to prevent any kind of compression/optimization on the card + for (uint16_t i=0; i<512; i++) + { + sectorBuf[i] ^= sectorBuf[i+1]; + } + + // blink the LED + if ((writeCount & 0x7) == 0) + PORT(STATUS_LED_PORT) ^= (1<writeBlock(imageFirstBlock + b, sectorBuf)) + { + LcdGoto(0,2); + LcdTinyStringP(PSTR("SD write error"), TEXT_NORMAL); + while(1); + } + + uint32_t writeTime = millis() - t0; + + // update stats + writeCount++; + writeTotalTime += writeTime; + if (writeTime > 20) + above20Count++; + if (writeTime > worstTime) + worstTime = writeTime; + + // pseudo-interleave + if ((cnt & 1) == 0) + b += 6; + else + b -= 5; + + _delay_ms(3); + } + } + + uint32_t avg = (writeTotalTime + (writeCount >> 1))/ writeCount; + + LcdGoto(0,2); + LcdTinyStringP(PSTR("AVG.ms/MAX.ms/LONG.%"), TEXT_NORMAL); + + snprintf(textBuf, TEXTBUF_SIZE, "512B RRWI %lu/%lu/%lu", avg, worstTime, above20Count*100/writeCount); + LcdGoto(0,3); + LcdTinyString(textBuf, TEXT_NORMAL); + + // Card: actual capacity, block size, erase size, best test result (random read-write interleaved) average/max/percent "long" over 20ms + // ---------------------------------------------------------- + // PNY class 10 8GB: 7708 MB, 512B block, 64K erase. 512B RRWI 10/189/1 (random read-write interleave) + // SanDisk unrated Ultra II 2GB: 1938 MB, 1024B block, 32K erase. 512B RRWI 7/79/0 + // Transcend unrated 2GB: 1875 MB, 1024B block, 128K erase. 512B RRWI 3/103/0 + // SanDisk unrated 128MB: 120 MB, 512B block, 16K erase. 512B RRWI 5/94/1 + + // enabling the TACH stuff seems to cause some cards to get errors during this test. Coupling between traces? Why doesn't it happen during normal operation? + + // Transcend unrated 2GB: Finder consistently "goes to sleep" after copying first 19 tracks, but worked twice after 3 tries. Maybe it's too fast? + + + + while(1); +} diff --git a/arduino/floppyemu/cardtest.h b/floppy_emu_arduino/cardtest/cardtest.h similarity index 100% rename from arduino/floppyemu/cardtest.h rename to floppy_emu_arduino/cardtest/cardtest.h diff --git a/arduino/floppyemu/diskmenu.cpp b/floppy_emu_arduino/diskmenu.cpp old mode 100755 new mode 100644 similarity index 96% rename from arduino/floppyemu/diskmenu.cpp rename to floppy_emu_arduino/diskmenu.cpp index 046b09a..0f5780e --- a/arduino/floppyemu/diskmenu.cpp +++ b/floppy_emu_arduino/diskmenu.cpp @@ -1,368 +1,368 @@ -/* - Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved. - - Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported - license. (CC BY-NC 3.0) The terms of the license may be viewed at - http://creativecommons.org/licenses/by-nc/3.0/ - - Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/ - - Permissions beyond the scope of this license may be available at www.bigmessowires.com - or from mailto:steve@bigmessowires.com. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "diskmenu.h" -#include "SdFat.h" -#include "SdBaseFile.h" -#include "noklcd.h" - -#define SECTORBUF_SIZE (23 * 512) // use the 24th buffer for directory breadcrumbs -extern uint8_t sectorBuf[24][512]; -extern uint8_t extraBuf[512]; - -typedef struct FileEntry -{ - char longName[FILENAME_LEN+1]; - char shortName[SHORTFILENAME_LEN+1]; - eImageType imageFileType; -} FileEntry; - -bool dirLfnNext(SdFat& sd, dir_t& dir, char* lfn) -{ - uint8_t offset[] = {1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30}; - uint8_t lfnIn = 130; - uint8_t i; - uint8_t ndir=0; - uint8_t sum; - uint8_t test=0; - bool haveLong = false; - - while( sd.vwd()->read( &dir, 32 ) == 32 ) - { - if( DIR_IS_LONG_NAME( &dir ) ) - { - if( ! haveLong ) - { - if(( dir.name[0] & 0XE0 ) != 0X40 ) - continue; - ndir = dir.name[0] & 0X1F; - test = dir.creationTimeTenths; - haveLong = true; - lfnIn = 130; - lfn[ lfnIn ] = 0; - } - else if( dir.name[0] != --ndir || test != dir.creationTimeTenths ) - { - haveLong = false; - continue; - } - char *p = (char*) & dir; - if( lfnIn > 0 ) - { - lfnIn -= 13; - for( i = 0; i < 13; i++ ) - lfn[lfnIn + i] = p[offset[i]]; - } - } - else if( DIR_IS_FILE_OR_SUBDIR( &dir ) - && dir.name[0] != DIR_NAME_DELETED - && dir.name[0] != DIR_NAME_FREE - && dir.name[0] != '.') - { - if( haveLong ) - { - for( sum = i = 0; i < 11; i++ ) - sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir.name[i]; - if( sum != test || ndir != 1 ) - haveLong = false; - } - if( haveLong ) - { - for( i = 0; lfnIn + i <= 130 ; i++ ) - lfn[i] = lfn[lfnIn + i]; - return true; - } - // else if( dir.reservedNT ) - // return "Reserved NT"; - else - { - SdBaseFile::dirName( dir, lfn ); - return true; - } - } - else - { - if( dir.name[0] == DIR_NAME_FREE ) - break; - haveLong = false; - } - } - lfn[ 0 ] = 0; - return false; -} - -eImageType DiskImageFileType(dir_t& dir, const char *filename) -{ - if (filename[0] == '.') - return DISK_IMAGE_NONE; - - if (DIR_IS_SUBDIR(&dir)) - return DISK_IMAGE_DIRECTORY; - - if (!DIR_IS_FILE(&dir)) - return DISK_IMAGE_NONE; - - uint32_t size = dir.fileSize; - - if (size == (unsigned long)1024 * 400) - return DISK_IMAGE_400K; - else if (size == (unsigned long)1024 * 800) - return DISK_IMAGE_800K; - else if (size == (unsigned long)1024 * 1440) - return DISK_IMAGE_1440K; - else if (size > (unsigned long)1024 * 400 && - size < (unsigned long)1024 * 1500) - { - // get the 8.3 filename - char shortName[SHORTFILENAME_LEN+1]; - SdBaseFile::dirName(dir, shortName); - - // read the first sector of the file - SdBaseFile f; - if (f.open(shortName, O_RDONLY)) - { - f.read(extraBuf, 512); - f.close(); - - // is it a DiskCopy 4.2 image? - if (extraBuf[0x52] == 0x01 && - extraBuf[0x53] == 0x00) - { - size = ((unsigned long)extraBuf[0x41] * 65536 + (unsigned long)extraBuf[0x42] * 256 + (unsigned long)extraBuf[0x43]) / 1024; - - if (size == 400) - return DISK_IMAGE_DISKCOPY_400K; - else if (size == 800) - return DISK_IMAGE_DISKCOPY_800K; - else if (size == 1440) - return DISK_IMAGE_DISKCOPY_1440K; - } - } - } - - return DISK_IMAGE_NONE; -} - -uint16_t diskMenuEntryCount; -uint16_t diskMenuOffset = 0; -uint16_t diskMenuSelection = 0; -char selectedFile[FILENAME_LEN+1]; -char selectedLongFile[FILENAME_LEN+1]; -eImageType selectedFileType; -uint8_t subdirDepth = 0; - -#define LONGFILENAME_LEN 130 - -void InitDiskMenu(SdFat& sd) -{ - dir_t dir; - char name[LONGFILENAME_LEN+1]; - - diskMenuEntryCount = 0; - - // use the sector buffers to hold the filenames - uint16_t maxEntries = SECTORBUF_SIZE / sizeof(FileEntry); - FileEntry* pFileEntries = (FileEntry*)sectorBuf; - - sd.vwd()->rewind(); - while (dirLfnNext(sd, dir, name) && diskMenuEntryCount < maxEntries) - { - eImageType imageType; - - if ((imageType = DiskImageFileType(dir, name)) != DISK_IMAGE_NONE) - { - strncpy(pFileEntries[diskMenuEntryCount].longName, name, FILENAME_LEN+1); - SdBaseFile::dirName(dir, pFileEntries[diskMenuEntryCount].shortName); - pFileEntries[diskMenuEntryCount].imageFileType = imageType; - diskMenuEntryCount++; - } - } - - // add up directory, if not at the root - if (!sd.vwd()->isRoot()) - { - strncpy(pFileEntries[diskMenuEntryCount].longName, "..", FILENAME_LEN+1); - strncpy(pFileEntries[diskMenuEntryCount].shortName, "..", SHORTFILENAME_LEN+1); - pFileEntries[diskMenuEntryCount].imageFileType = DISK_IMAGE_UP_DIRECTORY; - diskMenuEntryCount++; - } - - char file1[FILENAME_LEN+1], file2[FILENAME_LEN+1], temp[FILENAME_LEN+1]; - eImageType tempType; - - // sort the names by longname - for (uint16_t i=0; i file2, swap them - if (diff > 0) - { - strncpy(temp, pFileEntries[i].longName, FILENAME_LEN+1); - strncpy(pFileEntries[i].longName, pFileEntries[j].longName, FILENAME_LEN+1); - strncpy(pFileEntries[j].longName, temp, FILENAME_LEN+1); - - strncpy(temp, pFileEntries[i].shortName, SHORTFILENAME_LEN+1); - strncpy(pFileEntries[i].shortName, pFileEntries[j].shortName, SHORTFILENAME_LEN+1); - strncpy(pFileEntries[j].shortName, temp, SHORTFILENAME_LEN+1); - - tempType = pFileEntries[i].imageFileType; - pFileEntries[i].imageFileType = pFileEntries[j].imageFileType; - pFileEntries[j].imageFileType = tempType; - } - } - } -} - -void DrawDiskMenu(SdFat& sd) -{ - // scroll menu if necessary - if (diskMenuSelection < diskMenuOffset) - diskMenuOffset = diskMenuSelection; - if (diskMenuSelection > diskMenuOffset+4) - diskMenuOffset = diskMenuSelection-4; - - LcdGoto(0,0); - LcdWrite(LCD_DATA, 0x7F); - for (int i=0; i<19; i++) - LcdWrite(LCD_DATA, 0x40); - - LcdTinyStringFramed("Select Disk"); - - for (int i=0; i<19; i++) - LcdWrite(LCD_DATA, 0x40); - LcdWrite(LCD_DATA, 0x7F); - - if (diskMenuEntryCount == 0) - { - LcdGoto(0, 1); - LcdTinyString("no image files found", TEXT_NORMAL); - } - else - { - FileEntry* pFileEntries = (FileEntry*)sectorBuf; - - int row = 0; - for (uint16_t i=diskMenuOffset; i= barStart && y <= barEnd) - b = 0x80 | (b >> 1); - else - b = (b >> 1); - } - - LcdWrite(LCD_DATA, b); - } - } - - // prevent moving selection past end of list - if (diskMenuSelection >= diskMenuOffset + row) - { - diskMenuSelection = diskMenuOffset + row - 1; - if (row == 4 && diskMenuOffset > 0) - { - diskMenuOffset--; // scroll backwards - } - DrawDiskMenu(sd); // draw again - } - } -} +/* + Floppy Emu, copyright 2013 Steve Chamberlin, "Big Mess o' Wires". All rights reserved. + + Floppy Emu is licensed under a Creative Commons Attribution-NonCommercial 3.0 Unported + license. (CC BY-NC 3.0) The terms of the license may be viewed at + http://creativecommons.org/licenses/by-nc/3.0/ + + Based on a work at http://www.bigmessowires.com/macintosh-floppy-emu/ + + Permissions beyond the scope of this license may be available at www.bigmessowires.com + or from mailto:steve@bigmessowires.com. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "diskmenu.h" +#include "SdFat.h" +#include "SdBaseFile.h" +#include "noklcd.h" + +#define SECTORBUF_SIZE (23 * 512) // use the 24th buffer for directory breadcrumbs +extern uint8_t sectorBuf[24][512]; +extern uint8_t extraBuf[512]; + +typedef struct FileEntry +{ + char longName[FILENAME_LEN+1]; + char shortName[SHORTFILENAME_LEN+1]; + eImageType imageFileType; +} FileEntry; + +bool dirLfnNext(SdFat& sd, dir_t& dir, char* lfn) +{ + uint8_t offset[] = {1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30}; + uint8_t lfnIn = 130; + uint8_t i; + uint8_t ndir=0; + uint8_t sum; + uint8_t test=0; + bool haveLong = false; + + while( sd.vwd()->read( &dir, 32 ) == 32 ) + { + if( DIR_IS_LONG_NAME( &dir ) ) + { + if( ! haveLong ) + { + if(( dir.name[0] & 0XE0 ) != 0X40 ) + continue; + ndir = dir.name[0] & 0X1F; + test = dir.creationTimeTenths; + haveLong = true; + lfnIn = 130; + lfn[ lfnIn ] = 0; + } + else if( dir.name[0] != --ndir || test != dir.creationTimeTenths ) + { + haveLong = false; + continue; + } + char *p = (char*) & dir; + if( lfnIn > 0 ) + { + lfnIn -= 13; + for( i = 0; i < 13; i++ ) + lfn[lfnIn + i] = p[offset[i]]; + } + } + else if( DIR_IS_FILE_OR_SUBDIR( &dir ) + && dir.name[0] != DIR_NAME_DELETED + && dir.name[0] != DIR_NAME_FREE + && dir.name[0] != '.') + { + if( haveLong ) + { + for( sum = i = 0; i < 11; i++ ) + sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir.name[i]; + if( sum != test || ndir != 1 ) + haveLong = false; + } + if( haveLong ) + { + for( i = 0; lfnIn + i <= 130 ; i++ ) + lfn[i] = lfn[lfnIn + i]; + return true; + } + // else if( dir.reservedNT ) + // return "Reserved NT"; + else + { + SdBaseFile::dirName( dir, lfn ); + return true; + } + } + else + { + if( dir.name[0] == DIR_NAME_FREE ) + break; + haveLong = false; + } + } + lfn[ 0 ] = 0; + return false; +} + +eImageType DiskImageFileType(dir_t& dir, const char *filename) +{ + if (filename[0] == '.') + return DISK_IMAGE_NONE; + + if (DIR_IS_SUBDIR(&dir)) + return DISK_IMAGE_DIRECTORY; + + if (!DIR_IS_FILE(&dir)) + return DISK_IMAGE_NONE; + + uint32_t size = dir.fileSize; + + if (size == (unsigned long)1024 * 400) + return DISK_IMAGE_400K; + else if (size == (unsigned long)1024 * 800) + return DISK_IMAGE_800K; + else if (size == (unsigned long)1024 * 1440) + return DISK_IMAGE_1440K; + else if (size > (unsigned long)1024 * 400 && + size < (unsigned long)1024 * 1500) + { + // get the 8.3 filename + char shortName[SHORTFILENAME_LEN+1]; + SdBaseFile::dirName(dir, shortName); + + // read the first sector of the file + SdBaseFile f; + if (f.open(shortName, O_RDONLY)) + { + f.read(extraBuf, 512); + f.close(); + + // is it a DiskCopy 4.2 image? + if (extraBuf[0x52] == 0x01 && + extraBuf[0x53] == 0x00) + { + size = ((unsigned long)extraBuf[0x41] * 65536 + (unsigned long)extraBuf[0x42] * 256 + (unsigned long)extraBuf[0x43]) / 1024; + + if (size == 400) + return DISK_IMAGE_DISKCOPY_400K; + else if (size == 800) + return DISK_IMAGE_DISKCOPY_800K; + else if (size == 1440) + return DISK_IMAGE_DISKCOPY_1440K; + } + } + } + + return DISK_IMAGE_NONE; +} + +uint16_t diskMenuEntryCount; +uint16_t diskMenuOffset = 0; +uint16_t diskMenuSelection = 0; +char selectedFile[FILENAME_LEN+1]; +char selectedLongFile[FILENAME_LEN+1]; +eImageType selectedFileType; +uint8_t subdirDepth = 0; + +#define LONGFILENAME_LEN 130 + +void InitDiskMenu(SdFat& sd) +{ + dir_t dir; + char name[LONGFILENAME_LEN+1]; + + diskMenuEntryCount = 0; + + // use the sector buffers to hold the filenames + uint16_t maxEntries = SECTORBUF_SIZE / sizeof(FileEntry); + FileEntry* pFileEntries = (FileEntry*)sectorBuf; + + sd.vwd()->rewind(); + while (dirLfnNext(sd, dir, name) && diskMenuEntryCount < maxEntries) + { + eImageType imageType; + + if ((imageType = DiskImageFileType(dir, name)) != DISK_IMAGE_NONE) + { + strncpy(pFileEntries[diskMenuEntryCount].longName, name, FILENAME_LEN+1); + SdBaseFile::dirName(dir, pFileEntries[diskMenuEntryCount].shortName); + pFileEntries[diskMenuEntryCount].imageFileType = imageType; + diskMenuEntryCount++; + } + } + + // add up directory, if not at the root + if (!sd.vwd()->isRoot()) + { + strncpy(pFileEntries[diskMenuEntryCount].longName, "..", FILENAME_LEN+1); + strncpy(pFileEntries[diskMenuEntryCount].shortName, "..", SHORTFILENAME_LEN+1); + pFileEntries[diskMenuEntryCount].imageFileType = DISK_IMAGE_UP_DIRECTORY; + diskMenuEntryCount++; + } + + char file1[FILENAME_LEN+1], file2[FILENAME_LEN+1], temp[FILENAME_LEN+1]; + eImageType tempType; + + // sort the names by longname + for (uint16_t i=0; i file2, swap them + if (diff > 0) + { + strncpy(temp, pFileEntries[i].longName, FILENAME_LEN+1); + strncpy(pFileEntries[i].longName, pFileEntries[j].longName, FILENAME_LEN+1); + strncpy(pFileEntries[j].longName, temp, FILENAME_LEN+1); + + strncpy(temp, pFileEntries[i].shortName, SHORTFILENAME_LEN+1); + strncpy(pFileEntries[i].shortName, pFileEntries[j].shortName, SHORTFILENAME_LEN+1); + strncpy(pFileEntries[j].shortName, temp, SHORTFILENAME_LEN+1); + + tempType = pFileEntries[i].imageFileType; + pFileEntries[i].imageFileType = pFileEntries[j].imageFileType; + pFileEntries[j].imageFileType = tempType; + } + } + } +} + +void DrawDiskMenu(SdFat& sd) +{ + // scroll menu if necessary + if (diskMenuSelection < diskMenuOffset) + diskMenuOffset = diskMenuSelection; + if (diskMenuSelection > diskMenuOffset+4) + diskMenuOffset = diskMenuSelection-4; + + LcdGoto(0,0); + LcdWrite(LCD_DATA, 0x7F); + for (int i=0; i<19; i++) + LcdWrite(LCD_DATA, 0x40); + + LcdTinyStringFramed("Select Disk"); + + for (int i=0; i<19; i++) + LcdWrite(LCD_DATA, 0x40); + LcdWrite(LCD_DATA, 0x7F); + + if (diskMenuEntryCount == 0) + { + LcdGoto(0, 1); + LcdTinyString("no image files found", TEXT_NORMAL); + } + else + { + FileEntry* pFileEntries = (FileEntry*)sectorBuf; + + int row = 0; + for (uint16_t i=diskMenuOffset; i= barStart && y <= barEnd) + b = 0x80 | (b >> 1); + else + b = (b >> 1); + } + + LcdWrite(LCD_DATA, b); + } + } + + // prevent moving selection past end of list + if (diskMenuSelection >= diskMenuOffset + row) + { + diskMenuSelection = diskMenuOffset + row - 1; + if (row == 4 && diskMenuOffset > 0) + { + diskMenuOffset--; // scroll backwards + } + DrawDiskMenu(sd); // draw again + } + } +} diff --git a/arduino/floppyemu/diskmenu.h b/floppy_emu_arduino/diskmenu.h similarity index 100% rename from arduino/floppyemu/diskmenu.h rename to floppy_emu_arduino/diskmenu.h diff --git a/floppy_emu_arduino/floppy_emu_arduino.ino b/floppy_emu_arduino/floppy_emu_arduino.ino new file mode 100644 index 0000000..16803eb --- /dev/null +++ b/floppy_emu_arduino/floppy_emu_arduino.ino @@ -0,0 +1,471 @@ +/* + * floppy_emu_arduino.ino + * + * Created on: 2014/07/12 + * Author: sin + */ + +#include + +#include +#include + +#include "portmacros.h" + +#include "millitimer.h" +#include "diskmenu.h" +#include "noklcd.h" + +#include "floppyemu.h" + + SdFat sd; + +void setup() { + millitimerInit(); + ResetDiskState(); + + ShowVersion(); + + LcdClear(); + + sei(); + _delay_ms(100); // wait for pending interrupts?? + + millitimerOn(); + _delay_ms(100); // wait for pending interrupts?? + + // if select and next are both held down, enter contrast adjust mode + if (bit_is_set(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && + bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && + bit_is_clear(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) + { + AdjustContrast(); + } + + //SdFat sd; + if (!sd.init(SPI_FULL_SPEED)) + { + snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData()); + error(textBuf); + } + + millitimerOff(); + + // if prev and next are both held down, enter firmware update mode + if (bit_is_clear(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && + bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && + bit_is_set(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) + { + PromptForFirmwareUpdate(); + } + + InitDiskMenu(sd); + DrawDiskMenu(sd); + +} + + +// main loop +void loop() { + if (writeError) + { + // report error encounted in the interrupt routine + error(textBuf); + } + + cli(); + uint8_t trackNumber = currentTrack; // save track in a local var, since currentTrack is volatile + uint8_t sideNumber = currentSide; // save side in a local var, since currentSide is volatile + restartDisk = false; + sei(); + + if (diskInserted) + { + // show the current track and side + snprintf(textBuf, TEXTBUF_SIZE, "%02d", trackNumber); + LcdGoto(24,4); + LcdTinyString(textBuf, TEXT_NORMAL); + snprintf(textBuf, TEXTBUF_SIZE, "%d ", sideNumber); + LcdGoto(56,4); + LcdTinyString(textBuf, TEXT_NORMAL); + + // sync RAM buffer with SD card when switching tracks, or also when switching sides for mfmMode + if (prevTrack != trackNumber || (mfmMode && (prevSide != sideNumber))) + { + // write any dirty sectors from the previous track/side back to the SD card + FlushDirtySectors(sd, prevTrack); + prevTrack = trackNumber; + prevSide = sideNumber; + + // Also mark all the buffers on this track as invalid, since they don't contain valid data for the new track. + for (uint8_t i=0; i= trackLen) + currentSector = 0; + + bool prevMotorOn = !bit_is_clear(PIN(CPLD_STEP_DIR_MOTOR_ON_PORT), CPLD_STEP_DIR_MOTOR_ON_PIN); + + while (true) + { + // check for disk eject + if (bit_is_set(PIN(CPLD_EJECT_REQ_PORT), CPLD_EJECT_REQ_PIN)) + { + PORT(CPLD_RD_READY_TK0_PORT) &= ~(1<readBlock(blockToRead, sectorBuf[bufferNumber])) + error("SD read error R"); + } + + millitimerOff(); + + bufferState[bufferNumber] |= BUFFER_DATA_VALID; + bufferState[bufferNumber] &= ~BUFFER_LOCKED; + } + + if (currentSector == 0) + { + if (motorOn) + { + // toggle LED during drive activity + PORT(STATUS_LED_PORT) ^= (1< 1) + writeDisplayTimer--; + } + + // "Flutter" the drive's TACH speed slightly, every time we pass sector 0 (about every 100-150ms). This avoids a bug + // in P_Sony_MakeSpdTbl in the 64K ROM (used in the Mac 128K and Mac 512K) where + // the Mac will crash if two successive TACH measurements see the exact same speed. + tachFlutter += 25; + if (tachFlutter >= 125) + tachFlutter = 0; + + // Set the timeout. OC1A will toggle after this many counts. New timeout threshold won't take effect until the next timeout. + OCR1A = driveTachHalfPeriod - tachFlutter; + } + + if (mfmMode) + { + // insert sector-to-sector gap bytes + for (uint8_t i=0; i<50; i++) + { + SendMFMAndCheckRestart(0x4E); + } + + // insert sync bytes + for (uint8_t i=0; i<12; i++) + { + SendMFMAndCheckRestart(0x00); + } + + // send the address block + crc = 0xFFFF; // reset CRC + SendMFMSync(); + SendMFMSync(); + SendMFMSync(); + SendMFMAndCheckRestart(0xFE); + SendMFMAndCheckRestart(trackNumber); + SendMFMAndCheckRestart(sideNumber); + SendMFMAndCheckRestart(currentSector+1); // MFM sector numbers are 1-based + SendMFMAndCheckRestart(2); // size = 128 * 2^N bytes, so 2 means 512 + uint8_t crc0 = (crc >> 8) & 0xFF; + uint8_t crc1 = crc & 0xFF; + SendMFMAndCheckRestart(crc0); + SendMFMAndCheckRestart(crc1); + + // insert Address to Data gap bytes + for (uint8_t i=0; i<22; i++) + { + SendMFMAndCheckRestart(0x4E); + } + + // insert sync bytes + for (uint8_t i=0; i<12; i++) + { + SendMFMAndCheckRestart(0x00); + } + + // send the data block + crc = 0xFFFF; // reset CRC + SendMFMSync(); + SendMFMSync(); + SendMFMSync(); + SendMFMAndCheckRestart(0xFB); + + for (uint16_t i=0; i> 8) & 0xFF; + crc1 = crc & 0xFF; + SendMFMAndCheckRestart(crc0); + SendMFMAndCheckRestart(crc1); + } + else + { + // ensure a short gap between sectors - otherwise once they're all cached, one sector will appear + // to immediately follow another on disk, which may cause problems for the Mac. + // Bad voodoo here: + // 1. In the Finder StuffIt copy test that sometimes dies after the first 18 tracks, the length of delay here + // seems to affect what track it will freeze on. + // 2. With a longer delay here, the first ~10 sectors of copying seem to have fewer or no "long writes". + // 3. Depending on the delay here, the Transcend 2GB SD card sometimes gets "writeStop fail" when saving tracks. + for (uint16_t i=0; i> 6)); + uint8_t checksum = (uint8_t)((trackLow ^ currentSector ^ trackHigh ^ format) & 0x3F); + + SendByteAndCheckRestart(0xD5); + SendByteAndCheckRestart(0xAA); + SendByteAndCheckRestart(0x96); + SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[trackLow])); + SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[currentSector])); + SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[trackHigh])); + SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[format])); + SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[checksum])); + SendByteAndCheckRestart(0xDE); + SendByteAndCheckRestart(0xAA); + + // insert sync bytes between the address and data blocks + for (uint8_t i=0; i 0) + { + diskMenuSelection--; + DrawDiskMenu(sd); + _delay_ms(200); + } + } + else if (bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN)) + { + diskMenuSelection++; + DrawDiskMenu(sd); + _delay_ms(200); + } + else if (bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) + { + if (selectedFileType == DISK_IMAGE_DIRECTORY) + { + // remember where we came from, so we can get back later + char* pSubdirName = ((char*)sectorBuf[23]) + ((SHORTFILENAME_LEN+1) * subdirDepth); + strncpy(pSubdirName, selectedFile, SHORTFILENAME_LEN+1); + subdirDepth++; + + sd.chdir(selectedFile, true); + + diskMenuSelection = 0; + LcdClear(); + InitDiskMenu(sd); + DrawDiskMenu(sd); + _delay_ms(400); + } + else if (selectedFileType == DISK_IMAGE_UP_DIRECTORY) + { + subdirDepth--; + sd.chdir(true); // go to root directory + + for (uint8_t i=0; i -#include - -// I/O pin assignments -#define CPLD_RESET_PORT B -#define CPLD_RESET_PIN 0 - -#define CPLD_STEP_DIR_MOTOR_ON_PORT C -#define CPLD_STEP_DIR_MOTOR_ON_PIN 7 - -#define CPLD_STEP_REQ_PORT D -#define CPLD_STEP_REQ_PIN 0 // PCINT24 -#define CPLD_STEP_REQ_INT_MSK PCMSK3 -#define CPLD_STEP_REQ_INT_PIN PCINT24 -#define CPLD_STEP_REQ_INT_ENABLE PCIE3 - -#define CPLD_CURRENT_SIDE_PORT C -#define CPLD_CURRENT_SIDE_PIN 1 // PCINT17 -#define CPLD_CURRENT_SIDE_INT_MSK PCMSK2 -#define CPLD_CURRENT_SIDE_INT_PIN PCINT17 -#define CPLD_CURRENT_SIDE_INT_ENABLE PCIE2 - -#define CPLD_EJECT_REQ_PORT D -#define CPLD_EJECT_REQ_PIN 3 - -#define CPLD_STEP_ACK_DISK_IN_PORT C -#define CPLD_STEP_ACK_DISK_IN_PIN 2 - -#define CPLD_WR_REQ_PORT C -#define CPLD_WR_REQ_PIN 0 // PCINT16 -#define CPLD_WR_REQ_INT_MSK PCMSK2 -#define CPLD_WR_REQ_INT_PIN PCINT16 -#define CPLD_WR_REQ_INT_ENABLE PCIE2 - -#define CPLD_RD_READY_TK0_PORT C -#define CPLD_RD_READY_TK0_PIN 5 - -#define CPLD_RD_ACK_WR_TICK_PORT A -#define CPLD_RD_ACK_WR_TICK_PIN 7 // PCINT7 -#define CPLD_RD_ACK_WR_TICK_INT_MSK PCMSK0 -#define CPLD_RD_ACK_WR_TICK_INT_PIN PCINT7 -#define CPLD_RD_ACK_WR_TICK_INT_ENABLE PCIE0 - -#define CPLD_DATA_PORT A - -#define CPLD_DATA_HIZ_PORT C -#define CPLD_DATA_HIZ_PIN 6 - -#define CPLD_TACH_PORT D -#define CPLD_TACH_PIN 5 - -#define CPLD_TMS_PORT C -#define CPLD_TMS_PIN 3 - -#define SELECT_BUTTON_PORT D -#define SELECT_BUTTON_PIN 4 - -#define PREV_BUTTON_PORT D -#define PREV_BUTTON_PIN 1 - -#define NEXT_BUTTON_PORT D -#define NEXT_BUTTON_PIN 2 - -#define STATUS_LED_PORT B -#define STATUS_LED_PIN 3 - -#define CARD_WPROT_PORT D -#define CARD_WPROT_PIN 7 - -#define SECTOR_DATA_SIZE 512 -#define INTER_SECTOR_GAP_SIZE 55 -#define ADDRESS_DATA_GAP_SIZE 10 -#define SECTOR_DATA_HEADER_SIZE 3 -#define SECTOR_DATA_SECTORNUM_START SECTOR_DATA_HEADER_SIZE -#define SECTOR_DATA_SECTORNUM_SIZE 1 -#define SECTOR_DATA_ENCODED_TAGS_START (SECTOR_DATA_HEADER_SIZE+SECTOR_DATA_SECTORNUM_SIZE) -#define SECTOR_DATA_ENCODED_TAGS_SIZE 16 -#define SECTOR_DATA_ENCODED_DATA_START (SECTOR_DATA_HEADER_SIZE+SECTOR_DATA_SECTORNUM_SIZE+SECTOR_DATA_ENCODED_TAGS_SIZE) -#define SECTOR_DATA_ENCODED_DATA_SIZE 683 -#define SECTOR_DATA_CHECKSUM_START (SECTOR_DATA_ENCODED_DATA_START+SECTOR_DATA_ENCODED_DATA_SIZE) - - -// 8 byte marker placed at the end of the program binary, used by the bootloader. -// Configure the .bootldrinfo address to be 8 bytes below the bootloader start address for the type of Atmega being used. -#define DEVICEID_HIGH 0xDDDD -#define DEVICEID_LOW 0xDDDD -#define VERSIONID 0x0100 -const uint16_t bootloader_info[] __attribute__(( section(".bootldrinfo") )) = { DEVICEID_HIGH, DEVICEID_LOW, VERSIONID, 0x0000 }; - -const char versionStr[] PROGMEM = "App Version 1.0 L"; - -volatile uint8_t currentTrack; -volatile uint8_t prevTrack; -volatile uint8_t currentSide; -volatile uint8_t prevSide; -volatile uint8_t writeMode; -volatile bool restartDisk; -volatile bool writeError; - -bool diskInserted; -bool readOnly; -bool mfmMode; -uint16_t crc; -uint8_t numberOfDiskSides; -uint8_t currentSector; -uint16_t driveTachHalfPeriod; -uint8_t tachFlutter; - -uint8_t writeDisplayTimer; -uint8_t cpldFirmwareVersion; - -#define TEXTBUF_SIZE 22 -char textBuf[TEXTBUF_SIZE]; - -#define NUM_BUFFERS 24 -uint8_t sectorBuf[NUM_BUFFERS][SECTOR_DATA_SIZE]; -uint8_t extraBuf[SECTOR_DATA_SIZE]; - -bool selectedFileIsDiskCopyFormat; - -extern const uint16_t sony_track_start[] PROGMEM; -const uint16_t sony_track_start[80] = { - 0, 12, 24, 36, 48, 60 , 72, 84, - 96, 108, 120, 132, 144, 156, 168, 180, - - 192, 203, 214, 225, 236, 247, 258, 269, - 280, 291, 302, 313, 324, 335, 346, 357, - - 368, 378, 388, 398, 408, 418, 428, 438, - 448, 458, 468, 478, 488, 498, 508, 518, - - 528, 537, 546, 555, 564, 573, 582, 591, - 600, 609, 618, 627, 636, 645, 654, 663, - - 672, 680, 688, 696, 704, 712, 720, 728, - 736, 744, 752, 760, 768, 776, 784, 792 -}; - -extern const uint8_t sony_track_len[] PROGMEM; -const uint8_t sony_track_len[80] = { - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 -}; - -extern const uint8_t sony_to_disk_byte[] PROGMEM; -const uint8_t sony_to_disk_byte[] = { - 0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, /* 0x00 */ - 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3, - 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, /* 0x10 */ - 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3, - 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, /* 0x20 */ - 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, - 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, /* 0x30 */ - 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF -}; - -extern const uint8_t disk_byte_to_sony[] PROGMEM; -const uint8_t disk_byte_to_sony[] = { - /* table begins at disk byte 0x96, value of 0xFF is an invalid disk byte */ - /* 0x96 */ 0x00, 0x01, 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x04, - /* 0x9E */ 0x05, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - /* 0xA6 */ 0x07, 0x08, 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, - /* 0xAE */ 0x0C, 0x0D, 0xFF, 0xFF, 0x0E, 0x0F, 0x10, 0x11, - /* 0xB6 */ 0x12, 0x13, 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, - /* 0xBE */ 0x19, 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - /* 0xC6 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0x1C, - /* 0xCE */ 0x1D, 0x1E, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, - /* 0xD6 */ 0x20, 0x21, 0xFF, 0x22, 0x23, 0x24, 0x25, 0x26, - /* 0xDE */ 0x27, 0x28, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, - /* 0xE6 */ 0x2A, 0x2B, 0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, - /* 0xEE */ 0x31, 0x32, 0xFF, 0xFF, 0x33, 0x34, 0x35, 0x36, - /* 0xF6 */ 0x37, 0x38, 0xFF, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, - /* 0xFE */ 0x3E, 0x3F -}; - -uint8_t sectorDataHeaderGCR[] = { 0xD5, 0xAA, 0xAD }; - -extern const uint16_t crc_ccitt[] PROGMEM; -const uint16_t crc_ccitt[] = { - 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, - 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, - 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, - 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, - 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, - 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, - 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, - 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, - 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, - 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, - 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, - 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, - 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, - 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, - 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, - 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, - 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, - 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, - 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, - 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, - 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, - 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, - 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, - 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, - 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, - 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, - 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, - 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, - 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, - 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, - 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, - 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 -}; - -void ResetDiskState(); - -uint16_t writeErrorNumber; - -void error(const char* msg) -{ - bool wasWriteError = writeError; - uint16_t wasWriteErrorNumber = writeErrorNumber; - - ResetDiskState(); // clears writeError and writeErrorNumber - - LcdClear(); - LcdGoto(0,0); - if (wasWriteError) - LcdTinyStringP(PSTR("WRITE ERROR "), TEXT_INVERSE); - else - LcdTinyStringP(PSTR("FATAL ERROR "), TEXT_INVERSE); - LcdGoto(0,1); - LcdTinyString(msg, TEXT_NORMAL); - - if (wasWriteError) - { - snprintf(textBuf, TEXTBUF_SIZE, "%u", wasWriteErrorNumber); - LcdGoto(0,5); - LcdTinyString(textBuf, TEXT_NORMAL); - } - - while (1); -} - -void InitPorts() -{ - // set all data lines as outputs, MSB (RD_ACK/WR_TICK) as input - DDR(CPLD_DATA_PORT) = 0x7F; - - // initialize the other output lines - DDR(CPLD_TACH_PORT) |= (1<> 4; - if (speedZone > 4) - speedZone = 4; - - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - driveTachHalfPeriod = F_CPU / (2 * zoneRPM[speedZone]); - // OCR1A update will be performed during the next sector 0 read - } - - TIFR1 = (1 << OCF1A); // Clear the timer 1 compare A match flag. Not sure this is actually necessary. -} - -uint16_t trackStart(uint8_t trackNumber) -{ - return mfmMode ? trackNumber * 18 : pgm_read_word(&sony_track_start[trackNumber]); -} - -uint8_t trackLength(uint8_t trackNumber) -{ - return mfmMode ? 18 : pgm_read_byte(&sony_track_len[trackNumber]); -} - -#define BUFFER_DIRTY 1 -#define BUFFER_DATA_VALID 2 -#define BUFFER_LOCKED 4 - -volatile uint8_t bufferState[NUM_BUFFERS]; -volatile uint8_t wrTrack; -volatile uint8_t wrSide; -volatile uint8_t wrSector; - -// these variables are used only within the interrupt routine, and do not need to be declared volatile -uint8_t wrTick; -uint16_t writeCount; -uint8_t writeTemp; -uint8_t currentWriteBufferNumber; -uint8_t ck5, ck6, ck7; -uint8_t XBit; -uint8_t* pSectorBuf; - -void WriteError() -{ - writeMode = false; - restartDisk = true; - writeError = true; - writeCount = 0; -} - -// pin state change interrupt: STEP -ISR(PCINT3_vect) -{ - // step to a new track? - if (bit_is_set(PIN(CPLD_STEP_REQ_PORT), CPLD_STEP_REQ_PIN)) - { - // determine the range of dirty sector buffers - uint8_t trackLen = trackLength(currentTrack); - uint8_t firstDirtyBuffer = NUM_BUFFERS, lastDirtyBuffer=0; - - for (uint8_t i=0; i= SECTOR_DATA_SECTORNUM_START) - { - strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); - writeErrorNumber = 1000 + writeCount; - WriteError(); - } - - restartDisk = true; - } -} - -// pin state change interrupt: SIDE, WR_REQ -ISR(PCINT2_vect) -{ - // did the current side change? - uint8_t newSide = ((PIN(CPLD_CURRENT_SIDE_PORT) >> CPLD_CURRENT_SIDE_PIN) & 0x01); - if (newSide != currentSide) - { - if (numberOfDiskSides == 2) - currentSide = newSide; - else - currentSide = 0; - restartDisk = true; - - // premature end of a write? - if (writeCount >= SECTOR_DATA_SECTORNUM_START) - { - strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); - writeErrorNumber = 2000 + writeCount; - WriteError(); - } - } - - // did the read/write mode change? RD_RW: 0 = write, 1 = read - uint8_t wreqBit = bit_is_clear(PIN(CPLD_WR_REQ_PORT), CPLD_WR_REQ_PIN); - if (wreqBit != writeMode) - { - writeMode = wreqBit; - - if (writeMode) - { - // switch the DATA pins to inputs - DDR(CPLD_DATA_PORT) = 0; - - // indicate that the data bus has been released - PORT(CPLD_DATA_HIZ_PORT) |= (1<= SECTOR_DATA_SECTORNUM_START) - { - strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); - writeErrorNumber = 3000 + writeCount; - WriteError(); - } - } - - restartDisk = true; - } -} - -void HandleGCRWrite() -{ - uint8_t diskByte = 0x80 | PIN(CPLD_DATA_PORT); - - if (writeCount < SECTOR_DATA_ENCODED_TAGS_START) - { - // look for the sector header - // the final header byte is the sector number - if (writeCount == SECTOR_DATA_SECTORNUM_START) - { - uint8_t sector = pgm_read_byte(&disk_byte_to_sony[diskByte - 0x96]); - - if (sector >= trackLength(currentTrack)) - { - snprintf(textBuf, TEXTBUF_SIZE, "bad sector %d for t%d", sector, currentTrack); - writeErrorNumber = 60; - WriteError(); - } - - uint8_t trackLen = trackLength(currentTrack); - currentWriteBufferNumber = trackLen * currentSide + sector; - - if (bufferState[currentWriteBufferNumber] & BUFFER_LOCKED) - { - snprintf(textBuf, TEXTBUF_SIZE, "buf locked %d/%d:%d", currentTrack, currentSide, sector); - writeErrorNumber = 61; - WriteError(); - } - - pSectorBuf = sectorBuf[currentWriteBufferNumber]; - bufferState[currentWriteBufferNumber] |= BUFFER_LOCKED; - bufferState[currentWriteBufferNumber] &= ~BUFFER_DATA_VALID; - wrTrack = currentTrack; - wrSide = currentSide; - wrSector = sector; - - // turn on the LED when receiving a sector write - PORT(STATUS_LED_PORT) &= ~(1<> 7; - ck7 = (ck7 << 1) | XBit; - break; - - case 1: - b = (writeTemp & 0xC0) | dataIn; // A7 A6 0 0 0 0 0 0 | 0 0 A5 A4 A3 A2 A1 A0 - b ^= ck7; - - if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) - *pSectorBuf++ = b; - - //ADDX(ck5, b); - addResult = (uint16_t)ck5 + b + XBit; - ck5 = addResult & 0xFF; - XBit = addResult >> 8; - writeTemp <<= 2; // B7 B6 C7 C6 0 0 0 0 - break; - - case 2: - b = (writeTemp & 0xC0) | dataIn; // B7 B6 0 0 0 0 0 0 | 0 0 B5 B4 B3 B2 B1 B0 - b ^= ck5; - - if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) - *pSectorBuf++ = b; - - //ADDX(ck6, b); - addResult = (uint16_t)ck6 + b + XBit; - ck6 = addResult & 0xFF; - XBit = addResult >> 8; - writeTemp <<= 2; // C7 C6 0 0 0 0 0 0 - break; - - case 3: - b = writeTemp | dataIn; // C7 C6 0 0 0 0 0 0 | 0 0 C5 C4 C3 C2 C1 C0 - b ^= ck6; - - if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) - *pSectorBuf++ = b; - - //ADDX(ck7, b); - addResult = (uint16_t)ck7 + b + XBit; - ck7 = addResult & 0xFF; - XBit = addResult >> 8; - break; - } - } - else - { - // verify the checksum - if (writeCount == SECTOR_DATA_CHECKSUM_START) - { - writeTemp = dataIn; - writeTemp <<= 2; - } - else if (writeCount == SECTOR_DATA_CHECKSUM_START+1) - { - b = (writeTemp & 0xC0) | dataIn; - writeTemp <<= 2; - if (b != ck5) - { - strncpy(textBuf, "checksum failure 0", TEXTBUF_SIZE); - writeErrorNumber = 62; - WriteError(); - } - } - else if (writeCount == SECTOR_DATA_CHECKSUM_START+2) - { - b = (writeTemp & 0xC0) | dataIn; - writeTemp <<= 2; - if (b != ck6) - { - strncpy(textBuf, "checksum failure 1", TEXTBUF_SIZE); - writeErrorNumber = 63; - WriteError(); - } - } - else if (writeCount == SECTOR_DATA_CHECKSUM_START+3) - { - b = writeTemp | dataIn; - writeTemp <<= 2; - if (b != ck7) - { - strncpy(textBuf, "checksum failure 2", TEXTBUF_SIZE); - writeErrorNumber = 64; - WriteError(); - } - - // success! - bufferState[currentWriteBufferNumber] |= BUFFER_DATA_VALID; - bufferState[currentWriteBufferNumber] |= BUFFER_DIRTY; - bufferState[currentWriteBufferNumber] &= ~BUFFER_LOCKED; - - // turn off the LED at the end of a sector write - PORT(STATUS_LED_PORT) |= (1<> 8) ^ 0xA1]); - crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xA1]); - crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xA1]); - crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xFB]); - - for (uint16_t i=0; i> 8) ^ sectorBuf[bufferNumber][i]]); - } - - if (crc != receivedCRC) - { - strncpy(textBuf, "checksum fail", TEXTBUF_SIZE); - writeErrorNumber = 70; - WriteError(); - } -} - -// pin state change interrupt: WR_TICK -ISR(PCINT0_vect) -{ - uint8_t wrTickBit = bit_is_set(PIN(CPLD_RD_ACK_WR_TICK_PORT), CPLD_RD_ACK_WR_TICK_PIN); - - // was a new byte written? - if (writeMode && wrTickBit != wrTick) - { - wrTick = wrTickBit; - - if (!mfmMode) - { - HandleGCRWrite(); - } - else - { - if (wrTickBit == 0) - { - // high nibble arrives first - writeTemp = (PIN(CPLD_DATA_PORT) << 4) & 0xF0; - return; - } - else - { - writeTemp |= (PIN(CPLD_DATA_PORT) & 0x0F); - - if (writeCount == 2) - { - if (writeTemp == 0xFB) - { - writeCount++; - - // header received OK! - currentWriteBufferNumber = currentSector; // assume the buffer to write was the last one read - - if (bufferState[currentWriteBufferNumber] & BUFFER_LOCKED) - { - snprintf(textBuf, TEXTBUF_SIZE, "buf locked %d/%d:%d", currentTrack, currentSide, currentSector); - writeErrorNumber = 71; - WriteError(); - return; - } - - pSectorBuf = sectorBuf[currentWriteBufferNumber]; - bufferState[currentWriteBufferNumber] |= BUFFER_LOCKED; - bufferState[currentWriteBufferNumber] &= ~BUFFER_DATA_VALID; - wrTrack = currentTrack; - wrSide = currentSide; - wrSector = currentSector; // assume the buffer to write was the last one read - - // turn on the LED when receiving a sector write - PORT(STATUS_LED_PORT) &= ~(1<> 2) | ((__c1 & 0xC0) >> 4) | ((__c2 & 0xC0) >> 6)) - -// rotate left -#define rot_ck0(__ck0) \ - do { \ - __ck0 &= 0xFF; \ - __ck0 = (__ck0 << 1) | (__ck0 >> 7);\ - } while(0) - -// ADC __ckr, __in; __out = __in ^ __ckl -#define enc_byte(__in, __out, __ckl, __ckr) \ - do { \ - uint8_t __d = __in; \ - __ckr += __d; \ - __ckr += (__ckl & 0x100) >> 8; \ - __ckl &= 0xFF; \ - __out = __d ^ __ckl; \ - } while(0) - -#define SendByteAndCheckRestart(b) \ - do { \ - if (restartDisk) \ - goto restart; \ - SendByte(b); \ - } while(0) - -void SendMFMSync() -{ - // send A1 sync - - // SendByte - // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups - PORT(CPLD_DATA_PORT) = 0x0A; // data in bits 3-0, sync flag in bit 4 - PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 8) ^ 0xA1]); - - // SendByte - // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups - PORT(CPLD_DATA_PORT) = 0x11; // data in bits 3-0, sync flag in bit 4 - PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 4) & 0x0F; - - //if (restartDisk) - // return; - - // SendByte - // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups - PORT(CPLD_DATA_PORT) = out; - PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 8) ^ data]); - - //if (restartDisk) - // return; - - // SendByte - // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups - PORT(CPLD_DATA_PORT) = out; - PORT(CPLD_RD_READY_TK0_PORT) |= (1< 128) - lcd_vop--; - } - else if (bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) - { - eeprom_update_byte((uint8_t*)1, lcd_vop); - break; - } - - LcdWrite(LCD_CMD, 0x21); // LCD Extended Commands. - LcdWrite(LCD_CMD, lcd_vop); // Set LCD Vop (Contrast). - LcdWrite(LCD_CMD, 0x20); - } -} - -void PromptForFirmwareUpdate() -{ - LcdGoto(0,0); - LcdClear(); - LcdGoto(0,0); - LcdTinyStringP(PSTR("CPLD FIRMWARE UPDATE"), TEXT_NORMAL); - LcdGoto(0,2); - LcdTinyStringP(PSTR("Release buttons to"), TEXT_NORMAL); - LcdGoto(0,3); - LcdTinyStringP(PSTR("begin"), TEXT_NORMAL); - - // wait for the buttons to be released - while (bit_is_clear(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) || - bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) || - bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) - {} - - LcdGoto(0,2); - LcdTinyStringP(PSTR("NEXT: Load firmware"), TEXT_NORMAL); - LcdGoto(0,3); - LcdTinyStringP(PSTR("PREV: Cancel"), TEXT_NORMAL); - _delay_ms(400); - - // wait for a button press - while (bit_is_set(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && - bit_is_set(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && - bit_is_set(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) - {} - - if (bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN)) - { - UpdateFirmware(); - } - else - { - LcdClear(); - } -} - -uint32_t imageFirstBlock, imageLastBlock; - -bool OpenImageFile() -{ - LcdClear(); - LcdGoto(0,0); - LcdTinyString(selectedLongFile, TEXT_NORMAL); - - LcdGoto(0,1); - - // open the disk image file - // to-do: check if the file is read-only on the card - bool openOK = true; - if (!f.open(selectedFile, O_RDWR)) - { - if (f.open(selectedFile, O_RDONLY)) - { - // TODO: How do we tell the CPLD the disk is read-only? - readOnly = true; - } - else - { - LcdTinyStringP(PSTR("error opening image"), TEXT_NORMAL); - openOK = false; - } - } - else - { - if (selectedFileType == DISK_IMAGE_400K || selectedFileType == DISK_IMAGE_DISKCOPY_400K) - { - numberOfDiskSides = 1; - } - else - { - numberOfDiskSides = 2; - } - } - - // get address of file on SD - if (openOK && !f.contiguousRange(&imageFirstBlock, &imageLastBlock)) - { - LcdTinyStringP(PSTR("image not contiguous"), TEXT_NORMAL); - openOK = false; - } - - if (!openOK) - { - _delay_ms(4000); // wait 4 seconds - } - else - { - LcdGoto(0,1); - // show disk image type - switch (selectedFileType) - { - case DISK_IMAGE_400K: - LcdTinyStringP(PSTR("400K raw image"), TEXT_NORMAL); - break; - - case DISK_IMAGE_800K: - LcdTinyStringP(PSTR("800K raw image"), TEXT_NORMAL); - break; - - case DISK_IMAGE_1440K: - LcdTinyStringP(PSTR("1440K raw image"), TEXT_NORMAL); - mfmMode = true; - break; - - case DISK_IMAGE_DISKCOPY_400K: - LcdTinyStringP(PSTR("400K DiskCopy image"), TEXT_NORMAL); - break; - - case DISK_IMAGE_DISKCOPY_800K: - LcdTinyStringP(PSTR("800K DiskCopy image"), TEXT_NORMAL); - break; - - case DISK_IMAGE_DISKCOPY_1440K: - LcdTinyStringP(PSTR("1440K DiskCopy image"), TEXT_NORMAL); - mfmMode = true; - break; - - default: - break; - } - - selectedFileIsDiskCopyFormat = (selectedFileType >= DISK_IMAGE_DISKCOPY_400K); - - if (bit_is_set(PIN(CARD_WPROT_PORT), CARD_WPROT_PIN)) - readOnly = true; - - // mount DiskCopy images read-only - if (selectedFileIsDiskCopyFormat) - readOnly = true; - - uint16_t volumeNameOffset = selectedFileIsDiskCopyFormat ? 0x424 + 0x54 : 0x424; - f.seekSet(volumeNameOffset); // offset of the Macintosh disk name in the image file - f.read(§orBuf[0][0], SECTOR_DATA_SIZE); - int nameLen = sectorBuf[0][0]; - uint8_t* name = §orBuf[0][1]; - name[nameLen] = 0; - name[21] = 0; // in case nameLen was bogus, terminate the string after 21 chars, which is the longest displayable name on the LCD - LcdGoto(0,2); - LcdTinyString((char*)name, TEXT_NORMAL); - LcdGoto(0,4); - LcdTinyStringP(PSTR("Track Side"), TEXT_NORMAL); - - // show a lock icon if the disk image is mounted as read-only - if (readOnly) - { - LcdGoto(77,0); - LcdWrite(LCD_DATA, 0x00); - LcdWrite(LCD_DATA, 0x78); - LcdWrite(LCD_DATA, 0x7E); - LcdWrite(LCD_DATA, 0x79); - LcdWrite(LCD_DATA, 0x79); - LcdWrite(LCD_DATA, 0x7E); - LcdWrite(LCD_DATA, 0x78); - } - } - - f.close(); - return openOK; -} - -void ResetDiskState() -{ - ATOMIC_BLOCK(ATOMIC_RESTORESTATE) - { - // useless code to prevent the "unused" bootloader_info array from being optimized away when optimizations are turned on - // there's probably a nicer way to accomplish this. - currentTrack = bootloader_info[currentTrack]; - - InitPorts(); - - currentTrack = 0; - prevTrack = 0; - restartDisk = false; - currentSide = 0; - prevSide = 0; - writeMode = 0; - diskInserted = false; - numberOfDiskSides = 2; - currentSector = 0; - readOnly = false; - mfmMode = false; - writeError = false; - writeDisplayTimer = 0; - tachFlutter = 0; - writeErrorNumber = 0; - writeCount = 0; - - for (uint8_t i=0; i= trackLen - 1) - return 0; - else - return prevSectorNumber + 1; - } - else - { - uint8_t halfTrackLen = (trackLen + 1) >> 1; - - // process sectors in interleaved order: - // 12 sector tracks: 0 6 1 7 2 8 3 9 4 10 5 11 - // 11 sector tracks: 0 6 1 7 2 8 3 9 4 10 5 - // 10 sector tracks: 0 5 1 6 2 7 3 8 4 9 - // 9 sector tracks: 0 5 1 6 2 7 3 8 4 - // 8 sector tracks: 0 4 1 5 2 6 3 7 - // This is how real floppies are formatted, and should improve read performance if the Mac - // can't completely process sector N before sector N+1 begins. It should also improve sector-by-sector - // write performance, because the Mac alternately reads (address header) and writes (data section) in - // this mode, and proper interleaving means it will read the desired address header sooner if the Mac - // isn't fast enough to process the sectors linearly (which it likely isn't). - if (prevSectorNumber > trackLen - 1 || - ((trackLen & 1) == 0 && prevSectorNumber == trackLen - 1) || - ((trackLen & 1) == 1 && prevSectorNumber == halfTrackLen - 1)) - return 0; - else if (prevSectorNumber < halfTrackLen) - return prevSectorNumber + halfTrackLen; - else - return prevSectorNumber + 1 - halfTrackLen; - } -} - -void ReadDiskCopy42Block(SdFat& sd, uint32_t blockToRead, uint8_t bufferNumber) -{ - // for a DiskCopy 4.2 image, read two blocks into a temp buffer, then copy the unaligned data into the sector buffer. - uint16_t i; - - if (!sd.card()->readStart(blockToRead)) - error("SD read start error"); - - // read part 1 - if (!sd.card()->readData(extraBuf)) - error("SD read error D"); - for (i=0; i<512-0x54; i++) - sectorBuf[bufferNumber][i] = extraBuf[0x54 + i]; - - // read part 2 - if (!sd.card()->readData(extraBuf)) - error("SD read error D"); - for (i=512-0x54; i<512; i++) - sectorBuf[bufferNumber][i] = extraBuf[0x54 + i - 512]; - - sd.card()->readStop(); -} - -void FlushDirtySectors(SdFat& sd, uint8_t trackNumber) -{ - uint8_t trackLen = trackLength(trackNumber); - uint8_t firstDirtyBuffer = NUM_BUFFERS, lastDirtyBuffer=0; - - // determine the dirty range - for (uint8_t i=0; ireadBlock(blockToRead, sectorBuf[i])) - error("SD read error W"); - } - } - - uint32_t firstBlockToWrite = imageFirstBlock + ((uint32_t)trackStart(trackNumber) * numberOfDiskSides + firstDirtyBuffer); - - if (mfmMode) - firstBlockToWrite += trackLen * wrSide; - - uint32_t numBuffersToWrite = lastDirtyBuffer + 1 - firstDirtyBuffer; - - if (!sd.card()->writeStart(firstBlockToWrite, numBuffersToWrite)) - error("SD writeStart fail"); - - for (uint8_t i=firstDirtyBuffer; i<=lastDirtyBuffer; i++) - { - if (!sd.card()->writeData(sectorBuf[i])) - error("SD write error"); - - bufferState[i] &= ~BUFFER_DIRTY; - bufferState[i] &= ~BUFFER_LOCKED; - } - - if (!sd.card()->writeStop()) - error("SD writeStop fail"); - - writeDisplayTimer = 25; - millitimerOff(); - - uint32_t writeTime = millis() - t0; - - snprintf(textBuf, TEXTBUF_SIZE, "Saved trk %02d in %lu ", trackNumber, writeTime); - LcdGoto(0,5); - LcdTinyString(textBuf, TEXT_NORMAL); - } - } -} - - -void setup() { -} - -void loop() { -} - - -int main(void) -{ - millitimerInit(); - ResetDiskState(); - - ShowVersion(); - - LcdClear(); - - sei(); - _delay_ms(100); // wait for pending interrupts?? - - millitimerOn(); - _delay_ms(100); // wait for pending interrupts?? - - // if select and next are both held down, enter contrast adjust mode - if (bit_is_set(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && - bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && - bit_is_clear(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) - { - AdjustContrast(); - } - - SdFat sd; - if (!sd.init(SPI_FULL_SPEED)) - { - snprintf(textBuf, TEXTBUF_SIZE, "SD card error %d:%d", sd.card()->errorCode(), sd.card()->errorData()); - error(textBuf); - } - - millitimerOff(); - - // if prev and next are both held down, enter firmware update mode - if (bit_is_clear(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && - bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && - bit_is_set(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) - { - PromptForFirmwareUpdate(); - } - - InitDiskMenu(sd); - DrawDiskMenu(sd); - - // main loop - while (true) - { - if (writeError) - { - // report error encounted in the interrupt routine - error(textBuf); - } - - cli(); - uint8_t trackNumber = currentTrack; // save track in a local var, since currentTrack is volatile - uint8_t sideNumber = currentSide; // save side in a local var, since currentSide is volatile - restartDisk = false; - sei(); - - if (diskInserted) - { - // show the current track and side - snprintf(textBuf, TEXTBUF_SIZE, "%02d", trackNumber); - LcdGoto(24,4); - LcdTinyString(textBuf, TEXT_NORMAL); - snprintf(textBuf, TEXTBUF_SIZE, "%d ", sideNumber); - LcdGoto(56,4); - LcdTinyString(textBuf, TEXT_NORMAL); - - // sync RAM buffer with SD card when switching tracks, or also when switching sides for mfmMode - if (prevTrack != trackNumber || (mfmMode && (prevSide != sideNumber))) - { - // write any dirty sectors from the previous track/side back to the SD card - FlushDirtySectors(sd, prevTrack); - prevTrack = trackNumber; - prevSide = sideNumber; - - // Also mark all the buffers on this track as invalid, since they don't contain valid data for the new track. - for (uint8_t i=0; i= trackLen) - currentSector = 0; - - bool prevMotorOn = !bit_is_clear(PIN(CPLD_STEP_DIR_MOTOR_ON_PORT), CPLD_STEP_DIR_MOTOR_ON_PIN); - - while (true) - { - // check for disk eject - if (bit_is_set(PIN(CPLD_EJECT_REQ_PORT), CPLD_EJECT_REQ_PIN)) - { - PORT(CPLD_RD_READY_TK0_PORT) &= ~(1<readBlock(blockToRead, sectorBuf[bufferNumber])) - error("SD read error R"); - } - - millitimerOff(); - - bufferState[bufferNumber] |= BUFFER_DATA_VALID; - bufferState[bufferNumber] &= ~BUFFER_LOCKED; - } - - if (currentSector == 0) - { - if (motorOn) - { - // toggle LED during drive activity - PORT(STATUS_LED_PORT) ^= (1< 1) - writeDisplayTimer--; - } - - // "Flutter" the drive's TACH speed slightly, every time we pass sector 0 (about every 100-150ms). This avoids a bug - // in P_Sony_MakeSpdTbl in the 64K ROM (used in the Mac 128K and Mac 512K) where - // the Mac will crash if two successive TACH measurements see the exact same speed. - tachFlutter += 25; - if (tachFlutter >= 125) - tachFlutter = 0; - - // Set the timeout. OC1A will toggle after this many counts. New timeout threshold won't take effect until the next timeout. - OCR1A = driveTachHalfPeriod - tachFlutter; - } - - if (mfmMode) - { - // insert sector-to-sector gap bytes - for (uint8_t i=0; i<50; i++) - { - SendMFMAndCheckRestart(0x4E); - } - - // insert sync bytes - for (uint8_t i=0; i<12; i++) - { - SendMFMAndCheckRestart(0x00); - } - - // send the address block - crc = 0xFFFF; // reset CRC - SendMFMSync(); - SendMFMSync(); - SendMFMSync(); - SendMFMAndCheckRestart(0xFE); - SendMFMAndCheckRestart(trackNumber); - SendMFMAndCheckRestart(sideNumber); - SendMFMAndCheckRestart(currentSector+1); // MFM sector numbers are 1-based - SendMFMAndCheckRestart(2); // size = 128 * 2^N bytes, so 2 means 512 - uint8_t crc0 = (crc >> 8) & 0xFF; - uint8_t crc1 = crc & 0xFF; - SendMFMAndCheckRestart(crc0); - SendMFMAndCheckRestart(crc1); - - // insert Address to Data gap bytes - for (uint8_t i=0; i<22; i++) - { - SendMFMAndCheckRestart(0x4E); - } - - // insert sync bytes - for (uint8_t i=0; i<12; i++) - { - SendMFMAndCheckRestart(0x00); - } - - // send the data block - crc = 0xFFFF; // reset CRC - SendMFMSync(); - SendMFMSync(); - SendMFMSync(); - SendMFMAndCheckRestart(0xFB); - - for (uint16_t i=0; i> 8) & 0xFF; - crc1 = crc & 0xFF; - SendMFMAndCheckRestart(crc0); - SendMFMAndCheckRestart(crc1); - } - else - { - // ensure a short gap between sectors - otherwise once they're all cached, one sector will appear - // to immediately follow another on disk, which may cause problems for the Mac. - // Bad voodoo here: - // 1. In the Finder StuffIt copy test that sometimes dies after the first 18 tracks, the length of delay here - // seems to affect what track it will freeze on. - // 2. With a longer delay here, the first ~10 sectors of copying seem to have fewer or no "long writes". - // 3. Depending on the delay here, the Transcend 2GB SD card sometimes gets "writeStop fail" when saving tracks. - for (uint16_t i=0; i> 6)); - uint8_t checksum = (uint8_t)((trackLow ^ currentSector ^ trackHigh ^ format) & 0x3F); - - SendByteAndCheckRestart(0xD5); - SendByteAndCheckRestart(0xAA); - SendByteAndCheckRestart(0x96); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[trackLow])); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[currentSector])); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[trackHigh])); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[format])); - SendByteAndCheckRestart(pgm_read_byte(&sony_to_disk_byte[checksum])); - SendByteAndCheckRestart(0xDE); - SendByteAndCheckRestart(0xAA); - - // insert sync bytes between the address and data blocks - for (uint8_t i=0; i 0) - { - diskMenuSelection--; - DrawDiskMenu(sd); - _delay_ms(200); - } - } - else if (bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN)) - { - diskMenuSelection++; - DrawDiskMenu(sd); - _delay_ms(200); - } - else if (bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) - { - if (selectedFileType == DISK_IMAGE_DIRECTORY) - { - // remember where we came from, so we can get back later - char* pSubdirName = ((char*)sectorBuf[23]) + ((SHORTFILENAME_LEN+1) * subdirDepth); - strncpy(pSubdirName, selectedFile, SHORTFILENAME_LEN+1); - subdirDepth++; - - sd.chdir(selectedFile, true); - - diskMenuSelection = 0; - LcdClear(); - InitDiskMenu(sd); - DrawDiskMenu(sd); - _delay_ms(400); - } - else if (selectedFileType == DISK_IMAGE_UP_DIRECTORY) - { - subdirDepth--; - sd.chdir(true); // go to root directory - - for (uint8_t i=0; i +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "portmacros.h" +#include "noklcd.h" +//#include "millitimer.h" +#include "SdFat.h" +#include "SdBaseFile.h" +#include "micro.h" +#include "ports.h" +#include "diskmenu.h" + +#include "floppyemu.h" + +#ifdef PROGMEM_WORKAROUND +// work-around for compiler bug +#undef PROGMEM +#define PROGMEM __attribute__(( section(".progmem.data") )) +#undef PSTR +#define PSTR(s) (__extension__({static prog_char __c[] PROGMEM = (s); &__c[0];})) +#endif + +#ifndef FLOPPYEMU_H_ + +// I/O pin assignments +#define CPLD_RESET_PORT B +#define CPLD_RESET_PIN 0 + +#define CPLD_STEP_DIR_MOTOR_ON_PORT C +#define CPLD_STEP_DIR_MOTOR_ON_PIN 7 + +#define CPLD_STEP_REQ_PORT D +#define CPLD_STEP_REQ_PIN 0 // PCINT24 +#define CPLD_STEP_REQ_INT_MSK PCMSK3 +#define CPLD_STEP_REQ_INT_PIN PCINT24 +#define CPLD_STEP_REQ_INT_ENABLE PCIE3 + +#define CPLD_CURRENT_SIDE_PORT C +#define CPLD_CURRENT_SIDE_PIN 1 // PCINT17 +#define CPLD_CURRENT_SIDE_INT_MSK PCMSK2 +#define CPLD_CURRENT_SIDE_INT_PIN PCINT17 +#define CPLD_CURRENT_SIDE_INT_ENABLE PCIE2 + +#define CPLD_EJECT_REQ_PORT D +#define CPLD_EJECT_REQ_PIN 3 + +#define CPLD_STEP_ACK_DISK_IN_PORT C +#define CPLD_STEP_ACK_DISK_IN_PIN 2 + +#define CPLD_WR_REQ_PORT C +#define CPLD_WR_REQ_PIN 0 // PCINT16 +#define CPLD_WR_REQ_INT_MSK PCMSK2 +#define CPLD_WR_REQ_INT_PIN PCINT16 +#define CPLD_WR_REQ_INT_ENABLE PCIE2 + +#define CPLD_RD_READY_TK0_PORT C +#define CPLD_RD_READY_TK0_PIN 5 + +#define CPLD_RD_ACK_WR_TICK_PORT A +#define CPLD_RD_ACK_WR_TICK_PIN 7 // PCINT7 +#define CPLD_RD_ACK_WR_TICK_INT_MSK PCMSK0 +#define CPLD_RD_ACK_WR_TICK_INT_PIN PCINT7 +#define CPLD_RD_ACK_WR_TICK_INT_ENABLE PCIE0 + +#define CPLD_DATA_PORT A + +#define CPLD_DATA_HIZ_PORT C +#define CPLD_DATA_HIZ_PIN 6 + +#define CPLD_TACH_PORT D +#define CPLD_TACH_PIN 5 + +#define CPLD_TMS_PORT C +#define CPLD_TMS_PIN 3 + +#define SELECT_BUTTON_PORT D +#define SELECT_BUTTON_PIN 4 + +#define PREV_BUTTON_PORT D +#define PREV_BUTTON_PIN 1 + +#define NEXT_BUTTON_PORT D +#define NEXT_BUTTON_PIN 2 + +#define STATUS_LED_PORT B +#define STATUS_LED_PIN 3 + +#define CARD_WPROT_PORT D +#define CARD_WPROT_PIN 7 + +#endif + +#define SECTOR_DATA_SIZE 512 +#define INTER_SECTOR_GAP_SIZE 55 +#define ADDRESS_DATA_GAP_SIZE 10 +#define SECTOR_DATA_HEADER_SIZE 3 +#define SECTOR_DATA_SECTORNUM_START SECTOR_DATA_HEADER_SIZE +#define SECTOR_DATA_SECTORNUM_SIZE 1 +#define SECTOR_DATA_ENCODED_TAGS_START (SECTOR_DATA_HEADER_SIZE+SECTOR_DATA_SECTORNUM_SIZE) +#define SECTOR_DATA_ENCODED_TAGS_SIZE 16 +#define SECTOR_DATA_ENCODED_DATA_START (SECTOR_DATA_HEADER_SIZE+SECTOR_DATA_SECTORNUM_SIZE+SECTOR_DATA_ENCODED_TAGS_SIZE) +#define SECTOR_DATA_ENCODED_DATA_SIZE 683 +#define SECTOR_DATA_CHECKSUM_START (SECTOR_DATA_ENCODED_DATA_START+SECTOR_DATA_ENCODED_DATA_SIZE) + +// 8 byte marker placed at the end of the program binary, used by the bootloader. +// Configure the .bootldrinfo address to be 8 bytes below the bootloader start address for the type of Atmega being used. +#define DEVICEID_HIGH 0xDDDD +#define DEVICEID_LOW 0xDDDD +#define VERSIONID 0x0100 +const uint16_t bootloader_info[] __attribute__(( section(".bootldrinfo") )) = { DEVICEID_HIGH, DEVICEID_LOW, VERSIONID, 0x0000 }; + +const char versionStr[] PROGMEM = "App Version 1.0 L"; + +#ifndef FLOPPYEMU_H_ + +volatile uint8_t currentTrack; +volatile uint8_t prevTrack; +volatile uint8_t currentSide; +volatile uint8_t prevSide; +volatile uint8_t writeMode; +volatile bool restartDisk; +volatile bool writeError; + +bool diskInserted; +bool readOnly; +bool mfmMode; +uint16_t crc; +uint8_t numberOfDiskSides; +uint8_t currentSector; +uint16_t driveTachHalfPeriod; +uint8_t tachFlutter; + +uint8_t writeDisplayTimer; +uint8_t cpldFirmwareVersion; + +#define TEXTBUF_SIZE 22 +char textBuf[TEXTBUF_SIZE]; +#endif + +#define NUM_BUFFERS 24 +uint8_t sectorBuf[NUM_BUFFERS][SECTOR_DATA_SIZE]; +uint8_t extraBuf[SECTOR_DATA_SIZE]; + +bool selectedFileIsDiskCopyFormat; + +extern const uint16_t sony_track_start[] PROGMEM; +const uint16_t sony_track_start[80] = { + 0, 12, 24, 36, 48, 60 , 72, 84, + 96, 108, 120, 132, 144, 156, 168, 180, + + 192, 203, 214, 225, 236, 247, 258, 269, + 280, 291, 302, 313, 324, 335, 346, 357, + + 368, 378, 388, 398, 408, 418, 428, 438, + 448, 458, 468, 478, 488, 498, 508, 518, + + 528, 537, 546, 555, 564, 573, 582, 591, + 600, 609, 618, 627, 636, 645, 654, 663, + + 672, 680, 688, 696, 704, 712, 720, 728, + 736, 744, 752, 760, 768, 776, 784, 792 +}; + +extern const uint8_t sony_track_len[] PROGMEM; +const uint8_t sony_track_len[80] = { + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 +}; + +extern const uint8_t sony_to_disk_byte[] PROGMEM; +const uint8_t sony_to_disk_byte[] = { + 0x96, 0x97, 0x9A, 0x9B, 0x9D, 0x9E, 0x9F, 0xA6, /* 0x00 */ + 0xA7, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB2, 0xB3, + 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, /* 0x10 */ + 0xBD, 0xBE, 0xBF, 0xCB, 0xCD, 0xCE, 0xCF, 0xD3, + 0xD6, 0xD7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, /* 0x20 */ + 0xDF, 0xE5, 0xE6, 0xE7, 0xE9, 0xEA, 0xEB, 0xEC, + 0xED, 0xEE, 0xEF, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, /* 0x30 */ + 0xF7, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +extern const uint8_t disk_byte_to_sony[] PROGMEM; +const uint8_t disk_byte_to_sony[] = { + /* table begins at disk byte 0x96, value of 0xFF is an invalid disk byte */ + /* 0x96 */ 0x00, 0x01, 0xFF, 0xFF, 0x02, 0x03, 0xFF, 0x04, + /* 0x9E */ 0x05, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* 0xA6 */ 0x07, 0x08, 0xFF, 0xFF, 0xFF, 0x09, 0x0A, 0x0B, + /* 0xAE */ 0x0C, 0x0D, 0xFF, 0xFF, 0x0E, 0x0F, 0x10, 0x11, + /* 0xB6 */ 0x12, 0x13, 0xFF, 0x14, 0x15, 0x16, 0x17, 0x18, + /* 0xBE */ 0x19, 0x1A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + /* 0xC6 */ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1B, 0xFF, 0x1C, + /* 0xCE */ 0x1D, 0x1E, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, + /* 0xD6 */ 0x20, 0x21, 0xFF, 0x22, 0x23, 0x24, 0x25, 0x26, + /* 0xDE */ 0x27, 0x28, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x29, + /* 0xE6 */ 0x2A, 0x2B, 0xFF, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, + /* 0xEE */ 0x31, 0x32, 0xFF, 0xFF, 0x33, 0x34, 0x35, 0x36, + /* 0xF6 */ 0x37, 0x38, 0xFF, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, + /* 0xFE */ 0x3E, 0x3F +}; + +uint8_t sectorDataHeaderGCR[] = { 0xD5, 0xAA, 0xAD }; + +extern const uint16_t crc_ccitt[] PROGMEM; +const uint16_t crc_ccitt[] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; + +#ifndef FLOPPYEMU_H_ +void ResetDiskState(); +#endif + +uint16_t writeErrorNumber; + +void error(const char* msg) +{ + bool wasWriteError = writeError; + uint16_t wasWriteErrorNumber = writeErrorNumber; + + ResetDiskState(); // clears writeError and writeErrorNumber + + LcdClear(); + LcdGoto(0,0); + if (wasWriteError) + LcdTinyStringP(PSTR("WRITE ERROR "), TEXT_INVERSE); + else + LcdTinyStringP(PSTR("FATAL ERROR "), TEXT_INVERSE); + LcdGoto(0,1); + LcdTinyString(msg, TEXT_NORMAL); + + if (wasWriteError) + { + snprintf(textBuf, TEXTBUF_SIZE, "%u", wasWriteErrorNumber); + LcdGoto(0,5); + LcdTinyString(textBuf, TEXT_NORMAL); + } + + while (1); +} + +void InitPorts() +{ + // set all data lines as outputs, MSB (RD_ACK/WR_TICK) as input + DDR(CPLD_DATA_PORT) = 0x7F; + + // initialize the other output lines + DDR(CPLD_TACH_PORT) |= (1<> 4; + if (speedZone > 4) + speedZone = 4; + + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + driveTachHalfPeriod = F_CPU / (2 * zoneRPM[speedZone]); + // OCR1A update will be performed during the next sector 0 read + } + + TIFR1 = (1 << OCF1A); // Clear the timer 1 compare A match flag. Not sure this is actually necessary. +} + +uint16_t trackStart(uint8_t trackNumber) +{ + return mfmMode ? trackNumber * 18 : pgm_read_word(&sony_track_start[trackNumber]); +} + +uint8_t trackLength(uint8_t trackNumber) +{ + return mfmMode ? 18 : pgm_read_byte(&sony_track_len[trackNumber]); +} + +#define BUFFER_DIRTY 1 +#define BUFFER_DATA_VALID 2 +#define BUFFER_LOCKED 4 + +volatile uint8_t bufferState[NUM_BUFFERS]; +volatile uint8_t wrTrack; +volatile uint8_t wrSide; +volatile uint8_t wrSector; + +// these variables are used only within the interrupt routine, and do not need to be declared volatile +uint8_t wrTick; +uint16_t writeCount; +uint8_t writeTemp; +uint8_t currentWriteBufferNumber; +uint8_t ck5, ck6, ck7; +uint8_t XBit; +uint8_t* pSectorBuf; + +void WriteError() +{ + writeMode = false; + restartDisk = true; + writeError = true; + writeCount = 0; +} + +// pin state change interrupt: STEP +ISR(PCINT3_vect) +{ + // step to a new track? + if (bit_is_set(PIN(CPLD_STEP_REQ_PORT), CPLD_STEP_REQ_PIN)) + { + // determine the range of dirty sector buffers + uint8_t trackLen = trackLength(currentTrack); + uint8_t firstDirtyBuffer = NUM_BUFFERS, lastDirtyBuffer=0; + + for (uint8_t i=0; i= SECTOR_DATA_SECTORNUM_START) + { + strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); + writeErrorNumber = 1000 + writeCount; + WriteError(); + } + + restartDisk = true; + } +} + +// pin state change interrupt: SIDE, WR_REQ +ISR(PCINT2_vect) +{ + // did the current side change? + uint8_t newSide = ((PIN(CPLD_CURRENT_SIDE_PORT) >> CPLD_CURRENT_SIDE_PIN) & 0x01); + if (newSide != currentSide) + { + if (numberOfDiskSides == 2) + currentSide = newSide; + else + currentSide = 0; + restartDisk = true; + + // premature end of a write? + if (writeCount >= SECTOR_DATA_SECTORNUM_START) + { + strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); + writeErrorNumber = 2000 + writeCount; + WriteError(); + } + } + + // did the read/write mode change? RD_RW: 0 = write, 1 = read + uint8_t wreqBit = bit_is_clear(PIN(CPLD_WR_REQ_PORT), CPLD_WR_REQ_PIN); + if (wreqBit != writeMode) + { + writeMode = wreqBit; + + if (writeMode) + { + // switch the DATA pins to inputs + DDR(CPLD_DATA_PORT) = 0; + + // indicate that the data bus has been released + PORT(CPLD_DATA_HIZ_PORT) |= (1<= SECTOR_DATA_SECTORNUM_START) + { + strncpy(textBuf, "incomplete write", TEXTBUF_SIZE); + writeErrorNumber = 3000 + writeCount; + WriteError(); + } + } + + restartDisk = true; + } +} + +void HandleGCRWrite() +{ + uint8_t diskByte = 0x80 | PIN(CPLD_DATA_PORT); + + if (writeCount < SECTOR_DATA_ENCODED_TAGS_START) + { + // look for the sector header + // the final header byte is the sector number + if (writeCount == SECTOR_DATA_SECTORNUM_START) + { + uint8_t sector = pgm_read_byte(&disk_byte_to_sony[diskByte - 0x96]); + + if (sector >= trackLength(currentTrack)) + { + snprintf(textBuf, TEXTBUF_SIZE, "bad sector %d for t%d", sector, currentTrack); + writeErrorNumber = 60; + WriteError(); + } + + uint8_t trackLen = trackLength(currentTrack); + currentWriteBufferNumber = trackLen * currentSide + sector; + + if (bufferState[currentWriteBufferNumber] & BUFFER_LOCKED) + { + snprintf(textBuf, TEXTBUF_SIZE, "buf locked %d/%d:%d", currentTrack, currentSide, sector); + writeErrorNumber = 61; + WriteError(); + } + + pSectorBuf = sectorBuf[currentWriteBufferNumber]; + bufferState[currentWriteBufferNumber] |= BUFFER_LOCKED; + bufferState[currentWriteBufferNumber] &= ~BUFFER_DATA_VALID; + wrTrack = currentTrack; + wrSide = currentSide; + wrSector = sector; + + // turn on the LED when receiving a sector write + PORT(STATUS_LED_PORT) &= ~(1<> 7; + ck7 = (ck7 << 1) | XBit; + break; + + case 1: + b = (writeTemp & 0xC0) | dataIn; // A7 A6 0 0 0 0 0 0 | 0 0 A5 A4 A3 A2 A1 A0 + b ^= ck7; + + if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) + *pSectorBuf++ = b; + + //ADDX(ck5, b); + addResult = (uint16_t)ck5 + b + XBit; + ck5 = addResult & 0xFF; + XBit = addResult >> 8; + writeTemp <<= 2; // B7 B6 C7 C6 0 0 0 0 + break; + + case 2: + b = (writeTemp & 0xC0) | dataIn; // B7 B6 0 0 0 0 0 0 | 0 0 B5 B4 B3 B2 B1 B0 + b ^= ck5; + + if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) + *pSectorBuf++ = b; + + //ADDX(ck6, b); + addResult = (uint16_t)ck6 + b + XBit; + ck6 = addResult & 0xFF; + XBit = addResult >> 8; + writeTemp <<= 2; // C7 C6 0 0 0 0 0 0 + break; + + case 3: + b = writeTemp | dataIn; // C7 C6 0 0 0 0 0 0 | 0 0 C5 C4 C3 C2 C1 C0 + b ^= ck6; + + if (writeCount >= SECTOR_DATA_ENCODED_DATA_START) + *pSectorBuf++ = b; + + //ADDX(ck7, b); + addResult = (uint16_t)ck7 + b + XBit; + ck7 = addResult & 0xFF; + XBit = addResult >> 8; + break; + } + } + else + { + // verify the checksum + if (writeCount == SECTOR_DATA_CHECKSUM_START) + { + writeTemp = dataIn; + writeTemp <<= 2; + } + else if (writeCount == SECTOR_DATA_CHECKSUM_START+1) + { + b = (writeTemp & 0xC0) | dataIn; + writeTemp <<= 2; + if (b != ck5) + { + strncpy(textBuf, "checksum failure 0", TEXTBUF_SIZE); + writeErrorNumber = 62; + WriteError(); + } + } + else if (writeCount == SECTOR_DATA_CHECKSUM_START+2) + { + b = (writeTemp & 0xC0) | dataIn; + writeTemp <<= 2; + if (b != ck6) + { + strncpy(textBuf, "checksum failure 1", TEXTBUF_SIZE); + writeErrorNumber = 63; + WriteError(); + } + } + else if (writeCount == SECTOR_DATA_CHECKSUM_START+3) + { + b = writeTemp | dataIn; + writeTemp <<= 2; + if (b != ck7) + { + strncpy(textBuf, "checksum failure 2", TEXTBUF_SIZE); + writeErrorNumber = 64; + WriteError(); + } + + // success! + bufferState[currentWriteBufferNumber] |= BUFFER_DATA_VALID; + bufferState[currentWriteBufferNumber] |= BUFFER_DIRTY; + bufferState[currentWriteBufferNumber] &= ~BUFFER_LOCKED; + + // turn off the LED at the end of a sector write + PORT(STATUS_LED_PORT) |= (1<> 8) ^ 0xA1]); + crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xA1]); + crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xA1]); + crc = (crc << 8) ^ pgm_read_word(&crc_ccitt[(uint8_t)(crc >> 8) ^ 0xFB]); + + for (uint16_t i=0; i> 8) ^ sectorBuf[bufferNumber][i]]); + } + + if (crc != receivedCRC) + { + strncpy(textBuf, "checksum fail", TEXTBUF_SIZE); + writeErrorNumber = 70; + WriteError(); + } +} + +// pin state change interrupt: WR_TICK +ISR(PCINT0_vect) +{ + uint8_t wrTickBit = bit_is_set(PIN(CPLD_RD_ACK_WR_TICK_PORT), CPLD_RD_ACK_WR_TICK_PIN); + + // was a new byte written? + if (writeMode && wrTickBit != wrTick) + { + wrTick = wrTickBit; + + if (!mfmMode) + { + HandleGCRWrite(); + } + else + { + if (wrTickBit == 0) + { + // high nibble arrives first + writeTemp = (PIN(CPLD_DATA_PORT) << 4) & 0xF0; + return; + } + else + { + writeTemp |= (PIN(CPLD_DATA_PORT) & 0x0F); + + if (writeCount == 2) + { + if (writeTemp == 0xFB) + { + writeCount++; + + // header received OK! + currentWriteBufferNumber = currentSector; // assume the buffer to write was the last one read + + if (bufferState[currentWriteBufferNumber] & BUFFER_LOCKED) + { + snprintf(textBuf, TEXTBUF_SIZE, "buf locked %d/%d:%d", currentTrack, currentSide, currentSector); + writeErrorNumber = 71; + WriteError(); + return; + } + + pSectorBuf = sectorBuf[currentWriteBufferNumber]; + bufferState[currentWriteBufferNumber] |= BUFFER_LOCKED; + bufferState[currentWriteBufferNumber] &= ~BUFFER_DATA_VALID; + wrTrack = currentTrack; + wrSide = currentSide; + wrSector = currentSector; // assume the buffer to write was the last one read + + // turn on the LED when receiving a sector write + PORT(STATUS_LED_PORT) &= ~(1<> 2) | ((__c1 & 0xC0) >> 4) | ((__c2 & 0xC0) >> 6)) + +// rotate left +#define rot_ck0(__ck0) \ + do { \ + __ck0 &= 0xFF; \ + __ck0 = (__ck0 << 1) | (__ck0 >> 7);\ + } while(0) + +// ADC __ckr, __in; __out = __in ^ __ckl +#define enc_byte(__in, __out, __ckl, __ckr) \ + do { \ + uint8_t __d = __in; \ + __ckr += __d; \ + __ckr += (__ckl & 0x100) >> 8; \ + __ckl &= 0xFF; \ + __out = __d ^ __ckl; \ + } while(0) + +#define SendByteAndCheckRestart(b) \ + do { \ + if (restartDisk) \ + goto restart; \ + SendByte(b); \ + } while(0) + +void SendMFMSync() +{ + // send A1 sync + + // SendByte + // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups + PORT(CPLD_DATA_PORT) = 0x0A; // data in bits 3-0, sync flag in bit 4 + PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 8) ^ 0xA1]); + + // SendByte + // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups + PORT(CPLD_DATA_PORT) = 0x11; // data in bits 3-0, sync flag in bit 4 + PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 4) & 0x0F; + + //if (restartDisk) + // return; + + // SendByte + // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups + PORT(CPLD_DATA_PORT) = out; + PORT(CPLD_RD_READY_TK0_PORT) |= (1<> 8) ^ data]); + + //if (restartDisk) + // return; + + // SendByte + // TODO: what if an interrupt has switched the data port to an input? This will turn on pull-ups + PORT(CPLD_DATA_PORT) = out; + PORT(CPLD_RD_READY_TK0_PORT) |= (1< 128) + lcd_vop--; + } + else if (bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) + { + eeprom_update_byte((uint8_t*)1, lcd_vop); + break; + } + + LcdWrite(LCD_CMD, 0x21); // LCD Extended Commands. + LcdWrite(LCD_CMD, lcd_vop); // Set LCD Vop (Contrast). + LcdWrite(LCD_CMD, 0x20); + } +} + +void PromptForFirmwareUpdate() +{ + LcdGoto(0,0); + LcdClear(); + LcdGoto(0,0); + LcdTinyStringP(PSTR("CPLD FIRMWARE UPDATE"), TEXT_NORMAL); + LcdGoto(0,2); + LcdTinyStringP(PSTR("Release buttons to"), TEXT_NORMAL); + LcdGoto(0,3); + LcdTinyStringP(PSTR("begin"), TEXT_NORMAL); + + // wait for the buttons to be released + while (bit_is_clear(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) || + bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) || + bit_is_clear(PIN(SELECT_BUTTON_PORT), SELECT_BUTTON_PIN)) + {} + + LcdGoto(0,2); + LcdTinyStringP(PSTR("NEXT: Load firmware"), TEXT_NORMAL); + LcdGoto(0,3); + LcdTinyStringP(PSTR("PREV: Cancel"), TEXT_NORMAL); + _delay_ms(400); + + // wait for a button press + while (bit_is_set(PIN(PREV_BUTTON_PORT), PREV_BUTTON_PIN) && + bit_is_set(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN) && + bit_is_set(PIN(SELECT_BUTTON_PORT),SELECT_BUTTON_PIN)) + {} + + if (bit_is_clear(PIN(NEXT_BUTTON_PORT), NEXT_BUTTON_PIN)) + { + UpdateFirmware(); + } + else + { + LcdClear(); + } +} + +uint32_t imageFirstBlock, imageLastBlock; + +bool OpenImageFile() +{ + LcdClear(); + LcdGoto(0,0); + LcdTinyString(selectedLongFile, TEXT_NORMAL); + + LcdGoto(0,1); + + // open the disk image file + // to-do: check if the file is read-only on the card + bool openOK = true; + if (!f.open(selectedFile, O_RDWR)) + { + if (f.open(selectedFile, O_RDONLY)) + { + // TODO: How do we tell the CPLD the disk is read-only? + readOnly = true; + } + else + { + LcdTinyStringP(PSTR("error opening image"), TEXT_NORMAL); + openOK = false; + } + } + else + { + if (selectedFileType == DISK_IMAGE_400K || selectedFileType == DISK_IMAGE_DISKCOPY_400K) + { + numberOfDiskSides = 1; + } + else + { + numberOfDiskSides = 2; + } + } + + // get address of file on SD + if (openOK && !f.contiguousRange(&imageFirstBlock, &imageLastBlock)) + { + LcdTinyStringP(PSTR("image not contiguous"), TEXT_NORMAL); + openOK = false; + } + + if (!openOK) + { + _delay_ms(4000); // wait 4 seconds + } + else + { + LcdGoto(0,1); + // show disk image type + switch (selectedFileType) + { + case DISK_IMAGE_400K: + LcdTinyStringP(PSTR("400K raw image"), TEXT_NORMAL); + break; + + case DISK_IMAGE_800K: + LcdTinyStringP(PSTR("800K raw image"), TEXT_NORMAL); + break; + + case DISK_IMAGE_1440K: + LcdTinyStringP(PSTR("1440K raw image"), TEXT_NORMAL); + mfmMode = true; + break; + + case DISK_IMAGE_DISKCOPY_400K: + LcdTinyStringP(PSTR("400K DiskCopy image"), TEXT_NORMAL); + break; + + case DISK_IMAGE_DISKCOPY_800K: + LcdTinyStringP(PSTR("800K DiskCopy image"), TEXT_NORMAL); + break; + + case DISK_IMAGE_DISKCOPY_1440K: + LcdTinyStringP(PSTR("1440K DiskCopy image"), TEXT_NORMAL); + mfmMode = true; + break; + + default: + break; + } + + selectedFileIsDiskCopyFormat = (selectedFileType >= DISK_IMAGE_DISKCOPY_400K); + + if (bit_is_set(PIN(CARD_WPROT_PORT), CARD_WPROT_PIN)) + readOnly = true; + + // mount DiskCopy images read-only + if (selectedFileIsDiskCopyFormat) + readOnly = true; + + uint16_t volumeNameOffset = selectedFileIsDiskCopyFormat ? 0x424 + 0x54 : 0x424; + f.seekSet(volumeNameOffset); // offset of the Macintosh disk name in the image file + f.read(§orBuf[0][0], SECTOR_DATA_SIZE); + int nameLen = sectorBuf[0][0]; + uint8_t* name = §orBuf[0][1]; + name[nameLen] = 0; + name[21] = 0; // in case nameLen was bogus, terminate the string after 21 chars, which is the longest displayable name on the LCD + LcdGoto(0,2); + LcdTinyString((char*)name, TEXT_NORMAL); + LcdGoto(0,4); + LcdTinyStringP(PSTR("Track Side"), TEXT_NORMAL); + + // show a lock icon if the disk image is mounted as read-only + if (readOnly) + { + LcdGoto(77,0); + LcdWrite(LCD_DATA, 0x00); + LcdWrite(LCD_DATA, 0x78); + LcdWrite(LCD_DATA, 0x7E); + LcdWrite(LCD_DATA, 0x79); + LcdWrite(LCD_DATA, 0x79); + LcdWrite(LCD_DATA, 0x7E); + LcdWrite(LCD_DATA, 0x78); + } + } + + f.close(); + return openOK; +} + +void ResetDiskState() +{ + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) + { + // useless code to prevent the "unused" bootloader_info array from being optimized away when optimizations are turned on + // there's probably a nicer way to accomplish this. + currentTrack = bootloader_info[currentTrack]; + + InitPorts(); + + currentTrack = 0; + prevTrack = 0; + restartDisk = false; + currentSide = 0; + prevSide = 0; + writeMode = 0; + diskInserted = false; + numberOfDiskSides = 2; + currentSector = 0; + readOnly = false; + mfmMode = false; + writeError = false; + writeDisplayTimer = 0; + tachFlutter = 0; + writeErrorNumber = 0; + writeCount = 0; + + for (uint8_t i=0; i= trackLen - 1) + return 0; + else + return prevSectorNumber + 1; + } + else + { + uint8_t halfTrackLen = (trackLen + 1) >> 1; + + // process sectors in interleaved order: + // 12 sector tracks: 0 6 1 7 2 8 3 9 4 10 5 11 + // 11 sector tracks: 0 6 1 7 2 8 3 9 4 10 5 + // 10 sector tracks: 0 5 1 6 2 7 3 8 4 9 + // 9 sector tracks: 0 5 1 6 2 7 3 8 4 + // 8 sector tracks: 0 4 1 5 2 6 3 7 + // This is how real floppies are formatted, and should improve read performance if the Mac + // can't completely process sector N before sector N+1 begins. It should also improve sector-by-sector + // write performance, because the Mac alternately reads (address header) and writes (data section) in + // this mode, and proper interleaving means it will read the desired address header sooner if the Mac + // isn't fast enough to process the sectors linearly (which it likely isn't). + if (prevSectorNumber > trackLen - 1 || + ((trackLen & 1) == 0 && prevSectorNumber == trackLen - 1) || + ((trackLen & 1) == 1 && prevSectorNumber == halfTrackLen - 1)) + return 0; + else if (prevSectorNumber < halfTrackLen) + return prevSectorNumber + halfTrackLen; + else + return prevSectorNumber + 1 - halfTrackLen; + } +} + +void ReadDiskCopy42Block(SdFat& sd, uint32_t blockToRead, uint8_t bufferNumber) +{ + // for a DiskCopy 4.2 image, read two blocks into a temp buffer, then copy the unaligned data into the sector buffer. + uint16_t i; + + if (!sd.card()->readStart(blockToRead)) + error("SD read start error"); + + // read part 1 + if (!sd.card()->readData(extraBuf)) + error("SD read error D"); + for (i=0; i<512-0x54; i++) + sectorBuf[bufferNumber][i] = extraBuf[0x54 + i]; + + // read part 2 + if (!sd.card()->readData(extraBuf)) + error("SD read error D"); + for (i=512-0x54; i<512; i++) + sectorBuf[bufferNumber][i] = extraBuf[0x54 + i - 512]; + + sd.card()->readStop(); +} + +void FlushDirtySectors(SdFat& sd, uint8_t trackNumber) +{ + uint8_t trackLen = trackLength(trackNumber); + uint8_t firstDirtyBuffer = NUM_BUFFERS, lastDirtyBuffer=0; + + // determine the dirty range + for (uint8_t i=0; ireadBlock(blockToRead, sectorBuf[i])) + error("SD read error W"); + } + } + + uint32_t firstBlockToWrite = imageFirstBlock + ((uint32_t)trackStart(trackNumber) * numberOfDiskSides + firstDirtyBuffer); + + if (mfmMode) + firstBlockToWrite += trackLen * wrSide; + + uint32_t numBuffersToWrite = lastDirtyBuffer + 1 - firstDirtyBuffer; + + if (!sd.card()->writeStart(firstBlockToWrite, numBuffersToWrite)) + error("SD writeStart fail"); + + for (uint8_t i=firstDirtyBuffer; i<=lastDirtyBuffer; i++) + { + if (!sd.card()->writeData(sectorBuf[i])) + error("SD write error"); + + bufferState[i] &= ~BUFFER_DIRTY; + bufferState[i] &= ~BUFFER_LOCKED; + } + + if (!sd.card()->writeStop()) + error("SD writeStop fail"); + + writeDisplayTimer = 25; + millitimerOff(); + + uint32_t writeTime = millis() - t0; + + snprintf(textBuf, TEXTBUF_SIZE, "Saved trk %02d in %lu ", trackNumber, writeTime); + LcdGoto(0,5); + LcdTinyString(textBuf, TEXT_NORMAL); + } + } +} + + diff --git a/floppy_emu_arduino/floppyemu.cppproj b/floppy_emu_arduino/floppyemu.cppproj new file mode 100755 index 0000000..2f2d5e5 --- /dev/null +++ b/floppy_emu_arduino/floppyemu.cppproj @@ -0,0 +1,189 @@ + + + + 2.0 + 5.1 + {e27520eb-9b21-411f-b8c6-71c8e4b8b1b6} + ATmega1284P + none + Executable + CPP + $(MSBuildProjectDirectory)\$(Configuration) + + + floppyemu + floppyemu + floppyemu + com.atmel.avrdbg.tool.ispmk2 + com.Atmel.AVRGCC8 + Native + 2.11.1 + ISP + + com.atmel.avrdbg.tool.ispmk2 + AVRISP mkII + 000200006259 + + 127.0.0.1 + 49229 + False + + + JTAG + + 1000000 + 1000000 + 150000 + false + false + 0 + 0 + 0 + 0 + + + + + + floppyemu + .elf + + + True + True + True + True + True + True + True + True + + + F_CPU=20000000 + + + + + ../SdFat + ../xsvf + + + Optimize more (-O2) + True + True + True + True + + + m + + + True + True + + + .bootldrinfo=0xF7FC + + + + + True + C:\Users\chamberlin\Documents\floppyemu\AVR\Release + C:\Users\chamberlin\Documents\floppyemu\AVR\Release\Makefile + + + floppyemu + .elf + + + True + True + True + True + True + True + True + True + True + Default (-g2) + True + + + m + + + Default (-g2) + + + + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + Sd2Card.cpp + + + compile + SdBaseFile.cpp + + + compile + SdFat.cpp + + + compile + SdVolume.cpp + + + compile + lenval.cpp + + + compile + lenval.h + + + compile + micro.cpp + + + compile + micro.h + + + compile + ports.cpp + + + compile + ports.h + + + + \ No newline at end of file diff --git a/floppy_emu_arduino/floppyemu.h b/floppy_emu_arduino/floppyemu.h new file mode 100644 index 0000000..bdcc75f --- /dev/null +++ b/floppy_emu_arduino/floppyemu.h @@ -0,0 +1,110 @@ +/* + * floppyemu.h + * + * Created on: 2014/07/12 + * Author: sin + */ + +#ifndef FLOPPYEMU_H_ +#define FLOPPYEMU_H_ + +// I/O pin assignments +#define CPLD_RESET_PORT B +#define CPLD_RESET_PIN 0 + +#define CPLD_STEP_DIR_MOTOR_ON_PORT C +#define CPLD_STEP_DIR_MOTOR_ON_PIN 7 + +#define CPLD_STEP_REQ_PORT D +#define CPLD_STEP_REQ_PIN 0 // PCINT24 +#define CPLD_STEP_REQ_INT_MSK PCMSK3 +#define CPLD_STEP_REQ_INT_PIN PCINT24 +#define CPLD_STEP_REQ_INT_ENABLE PCIE3 + +#define CPLD_CURRENT_SIDE_PORT C +#define CPLD_CURRENT_SIDE_PIN 1 // PCINT17 +#define CPLD_CURRENT_SIDE_INT_MSK PCMSK2 +#define CPLD_CURRENT_SIDE_INT_PIN PCINT17 +#define CPLD_CURRENT_SIDE_INT_ENABLE PCIE2 + +#define CPLD_EJECT_REQ_PORT D +#define CPLD_EJECT_REQ_PIN 3 + +#define CPLD_STEP_ACK_DISK_IN_PORT C +#define CPLD_STEP_ACK_DISK_IN_PIN 2 + +#define CPLD_WR_REQ_PORT C +#define CPLD_WR_REQ_PIN 0 // PCINT16 +#define CPLD_WR_REQ_INT_MSK PCMSK2 +#define CPLD_WR_REQ_INT_PIN PCINT16 +#define CPLD_WR_REQ_INT_ENABLE PCIE2 + +#define CPLD_RD_READY_TK0_PORT C +#define CPLD_RD_READY_TK0_PIN 5 + +#define CPLD_RD_ACK_WR_TICK_PORT A +#define CPLD_RD_ACK_WR_TICK_PIN 7 // PCINT7 +#define CPLD_RD_ACK_WR_TICK_INT_MSK PCMSK0 +#define CPLD_RD_ACK_WR_TICK_INT_PIN PCINT7 +#define CPLD_RD_ACK_WR_TICK_INT_ENABLE PCIE0 + +#define CPLD_DATA_PORT A + +#define CPLD_DATA_HIZ_PORT C +#define CPLD_DATA_HIZ_PIN 6 + +#define CPLD_TACH_PORT D +#define CPLD_TACH_PIN 5 + +#define CPLD_TMS_PORT C +#define CPLD_TMS_PIN 3 + +#define SELECT_BUTTON_PORT D +#define SELECT_BUTTON_PIN 4 + +#define PREV_BUTTON_PORT D +#define PREV_BUTTON_PIN 1 + +#define NEXT_BUTTON_PORT D +#define NEXT_BUTTON_PIN 2 + +#define STATUS_LED_PORT B +#define STATUS_LED_PIN 3 + +#define CARD_WPROT_PORT D +#define CARD_WPROT_PIN 7 + +// global variables predefinitions + +#define TEXTBUF_SIZE 22 +char textBuf[TEXTBUF_SIZE]; + +volatile uint8_t currentTrack; +volatile uint8_t prevTrack; +volatile uint8_t currentSide; +volatile uint8_t prevSide; +volatile uint8_t writeMode; +volatile bool restartDisk; +volatile bool writeError; + +bool diskInserted; +bool readOnly; +bool mfmMode; +uint16_t crc; +uint8_t numberOfDiskSides; +uint8_t currentSector; +uint16_t driveTachHalfPeriod; +uint8_t tachFlutter; + +uint8_t writeDisplayTimer; +uint8_t cpldFirmwareVersion; + +// public functions predefinitions + +void ResetDiskState(); +void ShowVersion(); +void AdjustContrast(void); +void error(const char* msg); +void PromptForFirmwareUpdate(); + +#endif /* FLOPPYEMU_H_ */ diff --git a/arduino/floppyemu/millitimer.cpp b/floppy_emu_arduino/millitimer.cpp similarity index 100% rename from arduino/floppyemu/millitimer.cpp rename to floppy_emu_arduino/millitimer.cpp diff --git a/arduino/floppyemu/millitimer.h b/floppy_emu_arduino/millitimer.h similarity index 100% rename from arduino/floppyemu/millitimer.h rename to floppy_emu_arduino/millitimer.h diff --git a/arduino/floppyemu/noklcd.cpp b/floppy_emu_arduino/noklcd.cpp similarity index 100% rename from arduino/floppyemu/noklcd.cpp rename to floppy_emu_arduino/noklcd.cpp diff --git a/arduino/floppyemu/noklcd.h b/floppy_emu_arduino/noklcd.h similarity index 100% rename from arduino/floppyemu/noklcd.h rename to floppy_emu_arduino/noklcd.h diff --git a/arduino/floppyemu/portmacros.h b/floppy_emu_arduino/portmacros.h similarity index 100% rename from arduino/floppyemu/portmacros.h rename to floppy_emu_arduino/portmacros.h diff --git a/arduino/floppyemu/xsvf/lenval.cpp b/floppy_emu_arduino/xsvf/lenval.cpp similarity index 100% rename from arduino/floppyemu/xsvf/lenval.cpp rename to floppy_emu_arduino/xsvf/lenval.cpp diff --git a/arduino/floppyemu/xsvf/lenval.h b/floppy_emu_arduino/xsvf/lenval.h similarity index 100% rename from arduino/floppyemu/xsvf/lenval.h rename to floppy_emu_arduino/xsvf/lenval.h diff --git a/arduino/floppyemu/xsvf/micro.cpp b/floppy_emu_arduino/xsvf/micro.cpp similarity index 100% rename from arduino/floppyemu/xsvf/micro.cpp rename to floppy_emu_arduino/xsvf/micro.cpp diff --git a/arduino/floppyemu/xsvf/micro.h b/floppy_emu_arduino/xsvf/micro.h similarity index 100% rename from arduino/floppyemu/xsvf/micro.h rename to floppy_emu_arduino/xsvf/micro.h diff --git a/arduino/floppyemu/xsvf/ports.cpp b/floppy_emu_arduino/xsvf/ports.cpp similarity index 100% rename from arduino/floppyemu/xsvf/ports.cpp rename to floppy_emu_arduino/xsvf/ports.cpp diff --git a/arduino/floppyemu/xsvf/ports.h b/floppy_emu_arduino/xsvf/ports.h similarity index 100% rename from arduino/floppyemu/xsvf/ports.h rename to floppy_emu_arduino/xsvf/ports.h