From 6ecd0745a39e88ddaa699c5443f3091853165254 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Mon, 11 Feb 2019 13:03:18 +0100 Subject: [PATCH] v2.1 beta 2 - Nextor will now try to load MSXDOS2.SYS if NEXTOR.SYS is not found in the boot drive. - The method for selecting partitions for automatic mapping has changed from requiring a NEXTOR.DAT file in the root directory to having the "active" flag set in the partition table. - Now the first 9 partitions of a device will be scanned during the automatic mapping procedure, this includes extended partitions. - FDISK allows to change the "active" flag of new and existing partitions. - FDISK now always creates extended partitions, even if 4 or less partitions are defined. - FDISK now creates FAT16 partitions with a partition type code of 14 (FAT16 LBA) instead of 6 (FAT16 CHS). - The numeric keyboard can now be used both when booting and when changing disks in disk emulation mode. - Russian keyboard is now properly recognized (numeric keys only). - Introduced the boot key inverters. - Introduced the one-time boot keys. - Introduced the NEXBOOT.COM tool to set the RAM based one-time boot keys. - Introduced the RAM based one-time disk emulation mode. - The method to enter the old disk emulation mode (now named "persistent") has changed from requiring a NEXT_DSK.DAT file in the root directory to storing a pointer to the emulation data file in the partition table of the device. - Pressing the 0 key at boot time will delete the pointer to the emulation data file in the partition table, thus permanently disabling the emulation mode - no need to manually do anything else. - When Nextor is waiting for a disk key press after having pressed GRAPH in disk emulation mode, now you can press GRAPH again to cancel the disk change. - The first Nextor kernel to boot now clears the screen before invoking the driver initialization. - ARG is no longer used as temporary work area by the Nextor kernel, this should improve the compatibility of games in disk emulation mode. - Fix: drive was remapped in case of error (even if it was retried successfully). - Fix: boot sector checksum calculation had a bug that caused "Wrong disk" errors. - Fix: #1 pressing CTRL+STOP while Nextor was trying to load NEXTOR.SYS hanged the computer. - Fix: #23 computer hanged when booting with one single drive letter (e.g. when using single-device controller in a computer without internal disk drive). - Fix: #29 wrong stack management hangedd the computer when a file handle was read or written to a number of times. - Fix: computer crashing when more than one Nextor kernel was present as soon as the extended BIOS hook was called (for example, when loading COMMAND2.COM). - BREAKING CHANGE: The address of CODE_ADD, used by the CALLB0 routine, has changed to F1D0h (it was F84Ch). - Fix: there was Nextor kernel code in the 1K free area in pages 0 and 3, so putting anything here caused problems, e.g. DOS 1 mode didn't work. - _GPART now returns the status byte of the partition, and allows to retrieve the device sector number that holds the partition table entry instead of information about the partition. --- .gitignore | 1 + docs/DRIVER.ASM | 4 +- docs/Nextor 2.1 Driver Development Guide.md | 18 +- docs/Nextor 2.1 Getting Started Guide.md | 106 +- docs/Nextor 2.1 Programmers Reference.md | 150 +- docs/Nextor 2.1 User Manual.md | 211 +- docs/img/gsg/DirAAndDirB.png | Bin 7847 -> 26580 bytes docs/img/gsg/DirAAndDirBDos1Mode.png | Bin 8019 -> 24633 bytes .../gsg/DirAAndDirBDos1ModeWithNextorDat.png | Bin 8638 -> 11515 bytes docs/img/gsg/DirAAndDirBWithFiles.png | Bin 9839 -> 31078 bytes docs/img/gsg/DirInDos1Mode.png | Bin 5398 -> 11633 bytes docs/img/gsg/DirInDos1ModeWithNextorDat.png | Bin 5991 -> 11382 bytes docs/img/gsg/DirTwoSystemFiles.png | Bin 5891 -> 13180 bytes docs/img/gsg/DirWithNextorDat.png | Bin 6359 -> 19864 bytes docs/img/gsg/DriversOneController.png | Bin 3182 -> 7371 bytes docs/img/gsg/DriversOneDrive.png | Bin 3993 -> 9506 bytes docs/img/gsg/DriversTwoDrives.png | Bin 4527 -> 10215 bytes docs/img/gsg/DrvinfoInBasic.png | Bin 5464 -> 12110 bytes docs/img/gsg/FourPartitionsList.png | Bin 2855 -> 6244 bytes docs/img/gsg/NextorPrompt.png | Bin 1480 -> 4029 bytes docs/img/gsg/Partitions2And4Active.PNG | Bin 0 -> 5264 bytes docs/img/gsg/Partitions2And4Active.png | Bin 0 -> 5264 bytes source/kernel/bank0/betainfo.mac | 4 + source/kernel/bank0/dosboot.mac | 62 +- source/kernel/bank0/init.mac | 640 +++- source/kernel/bank1/dosinit.mac | 13 +- source/kernel/bank1/mapinit.mac | 37 +- source/kernel/bank2/err.mac | 24 +- source/kernel/bank2/files.mac | 21 +- source/kernel/bank2/rw.mac | 12 +- source/kernel/bank2/val.mac | 157 +- source/kernel/bank3/dos1ker.mac | 95 +- source/kernel/bank4/partit.mac | 1159 +++--- source/kernel/bank5/AsmCall.h | 11 - source/kernel/bank5/compfdsk.bat | 4 +- source/kernel/bank5/drivercall.c | 40 + source/kernel/bank5/drivercall.h | 11 + source/kernel/bank5/fdisk.c | 208 +- source/kernel/bank5/fdisk.h | 3 +- source/kernel/bank5/fdisk2.c | 98 +- source/kernel/bank6/dos.h | 4 +- source/kernel/compile.bat | 55 +- source/kernel/condasm.inc | 3 +- source/kernel/data.mac | 56 +- source/kernel/drivers/.gitignore | 1 + source/kernel/drivers/Flashjacks/chgbnk.dat | 1 + .../flashjacks.asm} | 1186 +++--- .../drivers/MegaFlashRomSD/driver-1slot.dat | Bin 0 -> 11370 bytes .../drivers/MegaFlashRomSD/driver-2slots.dat | Bin 0 -> 11370 bytes .../kernel/drivers/SunriseIDE/DRIVER.01.MAC | 1623 -------- .../SunriseIDE/{DRIVER.MAC => driver.mac} | 13 +- source/kernel/drivers/SunriseIDE/sunride.asm | 3315 +++++++++++++++++ source/kernel/drv.mac | 568 +-- source/kernel/kvar.mac | 48 + source/tools/.gitignore | 3 + source/tools/C/.gitignore | 3 + source/{kernel/bank5 => tools/C}/AsmCall.c | 37 +- .../{kernel/bank5/asm.h => tools/C/AsmCall.h} | 31 +- source/tools/C/asm.h | 8 +- source/tools/C/compemu.bat | 2 +- source/tools/C/compnexboot.bat | 7 + source/{kernel/bank5 => tools/C}/dos.h | 47 +- source/tools/C/emufile.c | 491 ++- source/tools/C/nexboot.c | 206 + source/{kernel/bank5 => tools/C}/partit.h | 3 +- source/{kernel/bank5 => tools/C}/printf.c | 9 +- source/tools/C/strcmpi.c | 12 + source/tools/C/strcmpi.h | 6 + source/{kernel/bank5 => tools/C}/system.h | 5 +- source/{kernel/bank5 => tools/C}/types.h | 0 source/tools/C/vsft.c | 19 +- source/tools/compile.bat | 8 +- wintools/.gitignore | 1 + wintools/mknexrom.c | 109 +- wintools/mknexrom.exe | Bin 97792 -> 140288 bytes wintools/mknexrom.obj | Bin 10376 -> 0 bytes 76 files changed, 7158 insertions(+), 3811 deletions(-) create mode 100644 docs/img/gsg/Partitions2And4Active.PNG create mode 100644 docs/img/gsg/Partitions2And4Active.png delete mode 100644 source/kernel/bank5/AsmCall.h create mode 100644 source/kernel/bank5/drivercall.c create mode 100644 source/kernel/bank5/drivercall.h create mode 100644 source/kernel/drivers/Flashjacks/chgbnk.dat rename source/kernel/drivers/{SunriseIDE/DRIVER.02.MAC => Flashjacks/flashjacks.asm} (59%) create mode 100644 source/kernel/drivers/MegaFlashRomSD/driver-1slot.dat create mode 100644 source/kernel/drivers/MegaFlashRomSD/driver-2slots.dat delete mode 100644 source/kernel/drivers/SunriseIDE/DRIVER.01.MAC rename source/kernel/drivers/SunriseIDE/{DRIVER.MAC => driver.mac} (95%) create mode 100644 source/kernel/drivers/SunriseIDE/sunride.asm create mode 100644 source/tools/.gitignore create mode 100644 source/tools/C/.gitignore rename source/{kernel/bank5 => tools/C}/AsmCall.c (69%) rename source/{kernel/bank5/asm.h => tools/C/AsmCall.h} (57%) create mode 100644 source/tools/C/compnexboot.bat rename source/{kernel/bank5 => tools/C}/dos.h (53%) create mode 100644 source/tools/C/nexboot.c rename source/{kernel/bank5 => tools/C}/partit.h (93%) rename source/{kernel/bank5 => tools/C}/printf.c (92%) create mode 100644 source/tools/C/strcmpi.c create mode 100644 source/tools/C/strcmpi.h rename source/{kernel/bank5 => tools/C}/system.h (84%) rename source/{kernel/bank5 => tools/C}/types.h (100%) create mode 100644 wintools/.gitignore delete mode 100644 wintools/mknexrom.obj diff --git a/.gitignore b/.gitignore index e5fb2f49..7e768cef 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ syntax: glob .vs/ +.vscode/ bin/** *.sym *.SYM diff --git a/docs/DRIVER.ASM b/docs/DRIVER.ASM index 3daaf7ec..07b7ec05 100644 --- a/docs/DRIVER.ASM +++ b/docs/DRIVER.ASM @@ -1,4 +1,4 @@ - ; Dummy disk driver for Nextor 2.0 + ; Dummy disk driver for Nextor 2.1 ; By Konamiman, 8/2018 ; ; This code can be used as the basis for developing @@ -21,7 +21,7 @@ DRV_START: ;This is a 2 byte buffer to store the address of code to be executed. ;It is used by some of the kernel page 0 routines. -CODE_ADD: equ 0F84Ch +CODE_ADD: equ 0F1D0h ;----------------------------------------------------------------------------- diff --git a/docs/Nextor 2.1 Driver Development Guide.md b/docs/Nextor 2.1 Driver Development Guide.md index b32343d2..62e63ae0 100644 --- a/docs/Nextor 2.1 Driver Development Guide.md +++ b/docs/Nextor 2.1 Driver Development Guide.md @@ -102,7 +102,9 @@ [5. Change history](#5-change-history) -[5.1. v2.1.0 beta 1](#51-v210-beta-1) +[5.1. v2.1.0 beta 2](#51-v210-beta-2) + +[5.2. v2.1.0 beta 1](#52-v210-beta-1) ## 1. Introduction @@ -428,7 +430,7 @@ Input: Address of code to invoke in (CODE_ADD). Output: AF, BC, DE, HL, IX, IY returned from the called routine. ``` -Note: the address of CODE_ADD is F84Ch. +Note: the address of CODE_ADD is F1D0h. #### 4.2.4. CALBNK (4042h) @@ -611,13 +613,13 @@ Please note also the following: #### 4.4.4. DRV_BASSTAT (4139h) -This is the entry for the BASIC extended statements ("CALLs") handler. It works the same way as the standard handlers (see _MSX2 Technical Handbook_, chapter 2, for details), except that if the handled statements have parameters, the MSX BIOS routine CALBAS (needed to invoke the MSX BASIC interpreter helper routines) can't be used directly; instead, it must be invoked via the CALLB0 entry in kernel page 0. +This is the entry for the BASIC extended statements ("CALLs") handler. It works the same way as the standard handlers (see [MSX2 Technical Handbook, chapter 2](https://github.com/Konamiman/MSX2-Technical-Handbook/blob/master/md/Chapter2.md), for details), except that if the handled statements have parameters, the MSX BIOS routine CALBAS (needed to invoke the MSX BASIC interpreter helper routines) can't be used directly; instead, it must be invoked via [the CALLB0 entry](#423-callb0-403fh) in kernel page 0. If the driver does not handle BASIC extended statements, it must simply set the carry flag and return. #### 4.4.5. DRV_BASDEV (413Ch) -This is the entry for the BASIC extended devices handler. It works the same way as the standard handlers (see _MSX2 Technical Handbook_, chapter 2, for details), but see the note on DRV_BASSTAT about CALBAS. +This is the entry for the BASIC extended devices handler. It works the same way as the standard handlers (see [MSX2 Technical Handbook, chapter 2](https://github.com/Konamiman/MSX2-Technical-Handbook/blob/master/md/Chapter2.md), for details), but see the note about CALBAS on [DRV_BASSTAT](#444-drv_basstat-4139h). If the driver does not handle BASIC extended devices, it must simply set the carry flag and return. @@ -1018,6 +1020,12 @@ This section contains the change history for the different versions of Nextor. O This list contains the changes for the 2.1 branch only. For the change history of the 2.0 branch see the _[Nextor 2.0 Driver Development Guide](../../../blob/v2.0/docs/Nextor%202.0%20Driver%20Development%20Guide.md#5-change-history)_ document. -### 5.1. v2.1 beta 1 +### 5.1. v2.1.0 beta 2 + +- **BREAKING CHANGE:** The address of CODE_ADD, used by [the CALLB0 routine](#423-callb0-403fh), has changed to F1D0h (it was F84Ch). + +- Fix: there was Nextor kernel code in the 1K free area in pages 0 and 3, so putting anything here caused problems, e.g. DOS 1 mode didn't work. + +### 5.2. v2.1.0 beta 1 Added the "User is requesting reduced drive count" flag to the input of [the DRV_INIT routine](#443-drv_init-4136h) and [the DRV_CONFIG routine](#448-drv_config-4151h). diff --git a/docs/Nextor 2.1 Getting Started Guide.md b/docs/Nextor 2.1 Getting Started Guide.md index ca551c83..940b2759 100644 --- a/docs/Nextor 2.1 Getting Started Guide.md +++ b/docs/Nextor 2.1 Getting Started Guide.md @@ -1,4 +1,4 @@ -# Nextor 2.0 Getting Started Guide +# Nextor 2.1 Getting Started Guide ## Index @@ -39,11 +39,11 @@ Note: in this guide the following Nextor tools will be used: MAPDRV.COM, LOCK.CO This section explains the steps needed to setup blueMSX in order to follow this guide. The blueMSX emulator can be downloaded at http://www.bluemsx.com. -a. Download the following files from [Konamiman's MSX page](https://www.konamiman.com/msx/msx-e.html#nextor): +a. Download the following files from [the lastest release of Nextor in GitHub](https://github.com/Konamiman/Nextor/releases/latest): -* Nextor kernel with Sunrise IDE driver. +* Nextor kernel with Sunrise IDE driver. Please choose the file with _.SunriseIDE.emulators.ROM_ extension (the _.SunriseIDE.ROM_ version works but only recgonizes the slave IDE device in emulators). -* Nextor tools disk image +* Nextor tools disk image (_tools.dsk.zip_). b. Run blueMSX and select the _Tools - Machine Editor_ menu. @@ -67,15 +67,15 @@ Now you have an emulated MSX2 with a Sunrise IDE controller that has the Nextor If you want to follow the steps of this guide by using a real MSX computer with a Sunrise IDE controller and a floppy disk drive instead of an emulator, you will need to do the following: -* Download the Nextor kernel with Sunrise IDE driver. +* Download the Nextor kernel with Sunrise IDE driver (the file with extension _.SunriseIDE.ROM_). * Copy the NEXTOR.SYS and COMMAND2.COM files and the Nextor tools to a floppy disk. You have two options: * Download the Nextor tools disk image file and transfer its contents to a floppy disk. - * Download the Nextor tools LZH file and uncompress it to a floppy disk, together with the NEXTOR.SYS and COMMAND2.COM files. + * Download the Nextor tools ZIP file (_tools.zip_) and uncompress it to a floppy disk, together with the NEXTOR.SYS and COMMAND2.COM files. -Note: The Nextor kernel, NEXTOR.SYS and the Nextor tools are available at [Konamiman's MSX page](https://www.konamiman.com/msx/msx-e.html#nextor). +Note: The Nextor kernel, NEXTOR.SYS and the Nextor tools are available as assets in [the lastest release of Nextor in GitHub](https://github.com/Konamiman/Nextor/releases/latest). * Copy the MSXDOS.SYS and COMMAND.COM files to the floppy disk, these are necessary for the steps that involve booting in MSX-DOS 1 mode. These files are included in the Nextor tools disk image file, but can be found on other places on Internet too (search for "MSXDOS.SYS" on any search engine). @@ -92,7 +92,9 @@ a. Boot your MSX. You will see that you boot in the COMMAND2 prompt in drive B:, ![](img/gsg/NextorPrompt.png) -***What has happened?*** Nextor has assigned one drive to the Sunrise IDE driver (A:) and two drives to the floppy disk drive (B: and C:). Then it has attempted to search a suitable FAT12 or FAT16 partition in the attached hard disk in order to assign it to drive A:, but since the hard disk has no partitions yet, drive A: has been left unassigned. Drive B:, assigned to the floppy disk, is the first valid drive, and so it is used as the boot drive. +***What has happened?*** Nextor has assigned one drive to the Sunrise IDE driver (A:) and one drive to the floppy disk drive (B:). Then it has attempted to search a suitable FAT12 or FAT16 partition in the attached hard disk in order to assign it to drive A:, but since the hard disk has no partitions yet, drive A: has been left unassigned. Drive B:, assigned to the floppy disk, is the first valid drive, and so it is used as the boot drive. + +**Note:** You may be wondering why the floppy disk drive gets only one drive letter assigned, and not two as usual. That's because by default Nextor inverts the behavior of the CTRL key at boot time. There's a way to customize this, see ["Boot key inverters" in the Nextor 2.1 User Manual](Nextor%202.1%20User%20Manual.md#291-boot-key-inverters). b. Type BASIC and then CALL FDISK to invoke the device partitioning tool. @@ -112,6 +114,8 @@ j. Press "S" to see the defined partitions. You should see four partitions, as i ![](img/gsg/FourPartitionsList.png) +Note: the asterisk "*" next to the partition number means that the partition will be created with the "active" flag set in the partition table. We'll see what this implies in next section. + k. Press ESC to return to the main menu, then press "W" to create the partitions on the disk. Press "y" on the data destroy warning prompt. l. Reset your MSX. You will see that the computer boots in the BASIC prompt. @@ -150,13 +154,21 @@ COPY NEXTOR.SYS D: COPY COMMAND2.COM D: ``` -d. Create an empty file named NEXTOR.DAT in drive D:. You can achieve this by executing a `COPY CON D:NEXTOR.DAT` command, then pressing CTRL+Z, then pressing Enter. +d. Type BASIC and then CALL FDISK to invoke the device partitioning tool. + +e. Press "1" to select the Sunrise IDE driver, then "1" again to select the hard disk, then "1" again to select the first logical unit, then "S" to show the partitions list. + +f. Press "1" and then "y" to remove the "active" flag from the first partition in the partition table. -e. Reset your MSX, and when you are in the COMMAND2 prompt, perform a DIR command and check that this time drive A: is assigned to the second (25MB big) partition: +g. Press "2" and then "y" to set the "active" flag for the second partition in the partition table. + +h. Reset your MSX, and when you are in the COMMAND2 prompt, perform a DIR command and check that this time drive A: is assigned to the second (25MB big) partition: ![](img/gsg/DirWithNextorDat.png) -***What has happened?*** When performing the automatic drive to device and partition mapping assignment at boot time, Nextor normally selects the first valid (FAT12 or FAT16) partition available. But if there are partitions with a file named "NEXTOR.DAT" in the root directory, then these partition have preference in the assignment process. The contents of the NEXTOR.DAT file are irrelevant in this version of Nextor. +***What has happened?*** When performing the automatic drive to device and partition mapping assignment at boot time, Nextor selects the first valid (FAT12 or FAT16) partition available that has the "active" flag set in the partition table. You can set and reset this flag for any of the first 9 partitions in the device using FDISK (either partitions that you are creating, or already existing partitions). + +If none of the existing partitions has the "active" flag set in the partition table, then the first suitable partition found will be mapped. We'll see this in the next section. ## 5. Booting in MSX-DOS 1 mode @@ -187,21 +199,23 @@ e. Map partition 4 to drive D: by executing the following: B:MAPDRV D: 4 1 1 -f. Copy the MSX-DOS 1 system files to drive D: as you did in step b, then create an empty NEXTOR.DAT file in drive D: as you did in the previous section. +f. Copy the MSX-DOS 1 system files to drive D: as you did in step b + +g. Go to BASIC, run FDISK and go to the partitions list for the first device, as you did in the previous section. This time set the "active" flag for partition 4. You should see that both partitions 2 and 4 are active now: -g. Boot the computer while keeping pressed the "1" key. You will boot in MSX-DOS 1 mode and in the COMMAND.COM prompt again. Issue a DIR command and you should see the following (notice the 9M free space): +![](img/gsg/Partitions2And4Active.png) + +h. Boot the computer while keeping pressed the "1" key. You will boot in MSX-DOS 1 mode and in the COMMAND.COM prompt again. Issue a DIR command and you should see the following (notice the 9M free space): ![](img/gsg/DirInDos1ModeWithNextorDat.png) -***What has happened?*** The rule "give priority to partitions holding a file named NEXTOR.DAT at the root directory during the automatic drive to device and partition assignment at boot time" is valid when booting in MSX-DOS 1 mode too, but this time only the MSX-DOS 1 compatible partitions are checked (partitions 3 and 4 in this case, being partition 4 the "winner" partition). +***What has happened?*** The rule "give priority to partitions having the 'active' flag set during the automatic drive to device and partition assignment at boot time" is valid when booting in MSX-DOS 1 mode too, but this time only the MSX-DOS 1 compatible partitions are checked (partitions 3 and 4 in this case, being partition 4 the "winner" partition). The remaining steps will leave the environment ready for the next section. -h. Boot the computer in normal mode. - -i. You should have booted with partition 2 (the one 25M big) mapped to drive A:. If so, simply delete the NEXTOR.DAT file in that drive (`DEL NEXTOR.DAT`). If not, map partition 2 to drive D: (`B:MAPDRV D: 2 1 1`) and then delete the file (`DEL D:NEXTOR.DAT`). +i. Boot the computer in normal mode. -j. Map partition 4 to drive D: and then delete the NEXTOR.DAT file. +j. Go to BASIC, run FDISK and reset the "active" flag of both partitions 2 and 4, so that none of the partitions has the flag set. ## 6. Using a second storage device @@ -213,63 +227,69 @@ a. Select the _File - Hard Disk - IDE Sunrise Secondary - Insert New Disk Image_ b. Reset the computer, go to BASIC and invoke the device partitioning tool with CALL FDISK. -c. Partition the device as you did in [3. Booting and creating partitions](#3-booting-and-creating-partitions). This time, however, you should select device 2 in the device selection screen; and you should create just two partitions, the first one having a size of 85M and the second one of 15M. +c. Partition the device as you did in [3. Booting and creating partitions](#3-booting-and-creating-partitions). This time, however, you should select device 2 in the device selection screen; and you should create just two partitions, the first one having a size of 85M and the second one of 15M. Also, please remove the "active" flag from the first partition (you can do this either before or after writing the partitions in the device). d. Reset the computer. Once in the COMMAND2 prompt, issue a _DIR_ command and check that drive A: has 50M free. Then issue a _DIR B:_ command and check that drive B: has 85M free (again, please be patient, especially with the second DIR command): ![](img/gsg/DirAAndDirB.png) -***What has happened?*** This time, Nextor has assigned two drives (A: and B:) to the Sunrise IDE driver, since two devices have been detected; the floppy disk controller has now drives C: and D: assigned. At boot time, Nextor assigns as many drives as devices are available to each controller (for device-based controllers only; see the _[Nextor 2.1 User Manual](Nextor%202.1%20User%20Manual.md)_ for details about the controller types). +***What has happened?*** This time, Nextor has assigned two drives (A: and B:) to the Sunrise IDE driver, since two devices have been detected; the floppy disk controller has now drive C: assigned. At boot time, Nextor assigns as many drives as devices are available to each controller (for device-based controllers only; see the _[Nextor 2.1 User Manual](Nextor%202.1%20User%20Manual.md)_ for details about the controller types). Drive A: has been mapped to the first available partition on the first available device, as usual. However, once this has been done, Nextor has searched for more suitable partitions on additional devices to be mapped to drive B:. So drive A: is mapped to the first partition in the master device (50M big) and drive B: is mapped to the first partition in the slave device (85M big). -e. Create an empty NEXTOR.DAT file in drive B:. Also, copy the NEXTOR.SYS and COMMAND2.COM files to drive B:. +e. Copy the NEXTOR.SYS and COMMAND2.COM files to drive B:. + +f. Go to BASIC, run FDISK and set the "active" flag of partition 1 (85M) in the device with number 2. -f. Reset your computer and issue a _DIR_ command, then a _DIR B:_ command. Notice that the mapping is reversed relative to the previous case (A: is mapped to the 85M partition on slave device, B: is mapped to the 50M partition on master device): +g. Reset your computer and issue a _DIR_ command, then a _DIR B:_ command. Notice that the mapping is reversed relative to the previous case (A: is mapped to the 85M partition on slave device, B: is mapped to the 50M partition on master device): ![](img/gsg/DirAAndDirBWithFiles.png) -***What has happened?*** The rule "give priority to partitions holding a file named NEXTOR.DAT at the root directory during the automatic drive to device and partition assignment at boot time" applies to all partitions on all devices, not only to the first device. Taking in account both the master and the slave devices, the only partition having a NEXTOR.DAT file is the first partition on the slave device, and therefore this one is assigned to drive A:. After this is done, other devices are scanned for a partition to be mapped to drive B:; in this case the only "other device" available is the master device, and thus its first partition is mapped to drive B:. +***What has happened?*** The rule "give priority to partitions having the 'active' flag set during the automatic drive to device and partition assignment at boot time" applies to all partitions on all devices, not only to the first device. Taking in account both the master and the slave devices, the only partition having the 'active' flag set is the first partition on the slave device, and therefore this one is assigned to drive A:. After this is done, other devices are scanned for a partition to be mapped to drive B:; in this case the only "other device" available is the master device, and thus its first partition is mapped to drive B:. -g. Map partition 2 of slave device to drive B: (`C:MAPDRV B: 2 2 1`). Copy the MSXDOS.SYS and COMMAND.COM files to drive B:. +h. Map partition 2 of slave device to drive B: (`C:MAPDRV B: 2 2 1`). Copy the MSXDOS.SYS and COMMAND.COM files to drive B: (remember the floppy holding these files is now mapped in C:). -h. Reset the computer while keeping pressed the "1" key. You will boot in MSX-DOS 1 mode and in the `COMMAND.COM` prompt. Issue a `DIR` command, then a `DIR B:` command. Notice that in the first case you get 16M of free space, and in the second case you get 15M: +i. Reset the computer while keeping pressed the "1" key. You will boot in MSX-DOS 1 mode and in the `COMMAND.COM` prompt. Issue a `DIR` command, then a `DIR B:` command. Notice that in the first case you get 16M of free space, and in the second case you get 15M: ![](img/gsg/DirAAndDirBDos1Mode.png) ***What has happened?*** Drive A: has been mapped to the first available partition on the master device, and drive B: has been mapped to the first available partition on the slave device, as in the previous case. However, this time only the MSX-DOS 1 compatible partitions have been taken in account. These are partitions 3 and 4 in the master device (partition 3, 16M big, is selected) and partition 2 in the slave device (15M big). -i. Create an empty NEXTOR.DAT file in drive B:. +j. Go to BASIC, run FDISK and set the "active" flag of partition 2 (15M) in the device with number 2. -j. Reset the computer while keeping pressed the "1" key. You will boot in MSX-DOS 1 mode and in the `COMMAND.COM` prompt. Issue a `DIR` command, then a `DIR B:` command. Notice that the mapping is reversed relative to the previous case (A: is mapped to the 15M partition on slave device, B: is mapped to the 16M partition on master device): +k. Reset the computer while keeping pressed the "1" key. You will boot in MSX-DOS 1 mode and in the `COMMAND.COM` prompt. Issue a `DIR` command, then a `DIR B:` command. Notice that the mapping is reversed relative to the previous case (A: is mapped to the 15M partition on slave device, B: is mapped to the 16M partition on master device): ![](img/gsg/DirAAndDirBDos1ModeWithNextorDat.png) -***What has happened?*** You should have guessed it already: both devices have been scanned for partitions, only the MSX-DOS 1 partitions have been taken in account, and the partition having a NEXTOR.DAT file has been given priority in the mapping process and thus it has been mapped to drive A:. +***What has happened?*** You should have guessed it already: both devices have been scanned for partitions, only the MSX-DOS 1 partitions have been taken in account, and the partition having the "active" flag set has been given priority in the mapping process and thus it has been mapped to drive A:. -k. Delete the NEXTOR.DAT from drive A:. Reset your computer in normal mode, delete the NEXTOR.DAT from drive A: again, and reset once more. You should be in the COMMAND2 prompt and have the 50M partition mapped to drive A:. +l. Go to BASIC, run FDISK and reset the "active" flag from all partitions having it set in both devices. + +m. Reset your computer in normal mode, you should be in the COMMAND2 prompt and have the 50M partition mapped to drive A:. ## 7. Locking drives In this section we'll try the drive lock feature. -a. Execute the following command: `C:LOCK C: ON` +a. Create a small text file in the tools floppy disk. You can do that by executing `COPY CON C:TEST`, then writing something, then pressing CTRL+Z. + +b. Execute the following command: `C:LOCK C: ON` -b. Issue a `DIR C:` command. You will see a directory listing of the Nextor tools floppy disk. +c. Execute the following: `TYPE C:TEST`. You will see the contents of the text file you just created. -c. Remove the floppy disk from the drive (if you are using blueMSX, select the `File - Disk Drive A - Eject: nextor.dsk` menu option). +d. Remove the floppy disk from the drive (if you are using blueMSX, select the `File - Disk Drive A - Eject: nextor.dsk` menu option). -d. Issue a `DIR C:` command again. You will see the same directory listing again instead of getting a "Not Ready" error, even though the disk has been removed from the drive. +e. Execute `TYPE C:TEST` again. You will see the file contents again instead of getting a "Not Ready" error, even though the disk has been removed from the drive. ***What has happened?*** Whenever Nextor is about to access the contents of a drive (and the drive is not mapped to a fixed device on a device-based driver), it first asks the driver if the associated storage media has changed. If the answer is "Yes" or "Not sure", then it takes the appropriate actions: for devices on a device-based driver, it assigns the first available partition on the device to the drive; for other drivers (MSX-DOS legacy drivers and drive-based drivers), it simply clears sector buffers and creates again the disk parameters block for the drive. (The "Not sure" response gets actually a special treatment; see the Nextor user manual for more details) When a drive is locked, Nextor will never ask the driver for device change status when accessing that drive, and will instead assume that the device will never change. This improves performance as it saves both CPU processing and device access. -In this case, we have locked the floppy disk drive, whose change status would otherwise be checked on each disk access (floppy disk drives usually report a change status of "Not sure" always). When issuing the second DIR command, Nextor assumes that the disk has not changed, and since it still has the directory and FAT sectors cached in memory, it can display the disk contents even if the disk has been removed from the drive. +In this case, we have locked the floppy disk drive, whose change status would otherwise be checked on each disk access (floppy disk drives usually report a change status of "Not sure" always). When displaying the file contents the second time, Nextor assumes that the disk has not changed, and since it still has the file contents sector cached in memory, it can display it even if the disk has been removed from the drive. -Nextor will clear then cached sector for a drive at the moment of locking it, therefore if you had reversed the order of steps a and b you would have effectively got a "Not Ready" error. +Nextor will clear the cached sector for a drive at the moment of locking it, therefore if you had reversed the order of steps b and c you would have effectively got a "Not Ready" error. -e. Insert the Nextor tools floppy disk in its drive again. +f. Insert the Nextor tools floppy disk in its drive again. ## 8. The reduced/zero allocation information mode @@ -302,8 +322,6 @@ f. Issue again the `DIR` and `DIR B:` commands. Notice that this time the free s ***What has happened?*** When an environment item named ZALLOC exists and has the value ON (case insensitive), the reduced allocation information mode becomes the zero allocation information mode, causing the ALLOC function to return zero free space available for the drives that are in this mode. You can use this mode if you have a very large drive and/or are using a very slow device, to prevent the computer from hanging for a few seconds every time a DIR command is issued. -Note: the zero allocation information mode is available since Nextor 2.0.3. - ## 9. Using the boot keys We have seen that if key "1" is kept pressed while the computer is booting, Nextor starts in MSX-DOS 1 mode. Now we'll see other useful keys that can be used to alter the way Nextor boots; see the _[Nextor 2.1 User Manual](Nextor%202.1%20User%20Manual.md)_ for a full list of the available keys. @@ -316,15 +334,15 @@ b. Issue a `CALL SYSTEM` command. c. Copy the DRIVERS tool to drive A: with the following command: `COPY C:DRIVERS.COM A:` -d. Execute the DRIVERS tool. You will see that the IDE controller had been assigned two drives at boot time, and the same happens with the floppy disk controller: +d. Execute the DRIVERS tool. You will see that the IDE controller had been assigned two drives at boot time, and the floppy disk controller has been assigned one: ![](img/gsg/DriversTwoDrives.png) -e. Reset your computer while keeping the "CTRL" key pressed. Once in the COMMAND2.COM prompt, execute the DRIVERS tool again. You will see that both the IDE controller and the floppy disk drive have been assigned only one drive each: +e. Reset your computer while keeping the "5" key pressed. Once in the COMMAND2.COM prompt, execute the DRIVERS tool again. You will see that both the IDE controller and the floppy disk drive have been assigned only one drive each: ![](img/gsg/DriversOneDrive.png) -***What has happened?*** When the "CTRL" key is kept pressed at boot time, Nextor will assign one single drive to Nextor drivers, regardless of the number of attached devices (for device-based controllers only; see the _[Nextor 2.1 User Manual](Nextor%202.1%20User%20Manual.md)_ for details about the controller types). The same behavior is exhibited by the floppy disk controller as usual. +***What has happened?*** When the "5" key is kept pressed at boot time, Nextor will assign one single drive to Nextor drivers, regardless of the number of attached devices (for device-based controllers only; see the _[Nextor 2.1 User Manual](Nextor%202.1%20User%20Manual.md)_ for details about the controller types). f. Reset your computer while keeping the "SHIFT" key pressed. Once in the COMMAND2.COM prompt, execute the DRIVERS tool again. You will see that no drives have been assigned to the floppy disk drive: @@ -332,13 +350,13 @@ f. Reset your computer while keeping the "SHIFT" key pressed. Once in the COMMAN ***What has happened?*** When the "SHIFT" key is kept pressed at boot time, all the storage controllers with a MSX-DOS kernel (including the floppy disk drive controller) will disable themselves, but Nextor will not. This is useful to maximize the amount of available memory, especially in MSX-DOS 1 mode, as shown in the next step. (There are boot keys to selectively disable the Nextor kernels as well; see the _[Nextor 2.1 User Manual](Nextor%202.1%20User%20Manual.md)_ for details) -g. Reset your computer while keeping the "1" and "3" keys pressed simultaneously. Once in the BASIC prompt, issue a `PRINT FRE(0)` command. You will see that there are about 20K free for BASIC code. +g. Reset your computer while keeping the "1" and "3" keys pressed simultaneously. Once in the BASIC prompt, issue a `PRINT FRE(0)` command. You will see that there are about 23K free for BASIC code. -h. Reset your computer while keeping the "1", "3", "SHIFT" and "CTRL" keys pressed simultaneously. Once in the BASIC prompt, issue a `PRINT FRE(0)` command again. You will see that now the free memory is about 25K. Also, if you execute a `CALL DRVINFO` command, you will see that indeed, there is only one drive assigned: +h. Reset your computer while keeping the "1", "3", "5" and "SHIFT" keys pressed simultaneously. Once in the BASIC prompt, issue a `PRINT FRE(0)` command again. You will see that now the free memory is about 25K. Also, if you execute a `CALL DRVINFO` command, you will see that indeed, there is only one drive assigned: ![](img/gsg/DrvinfoInBasic.png) -**Note:** of course, you do not need to keep the "CTRL" key pressed while booting if you have only one device attached to your Nextor controller (unless you want to keep the floppy disk drive active but with only one drive assigned). +**Note:** of course, you do not need to keep the "5" key pressed while booting if you have only one device attached to your Nextor controller. ## 10. Change history diff --git a/docs/Nextor 2.1 Programmers Reference.md b/docs/Nextor 2.1 Programmers Reference.md index 5bf71e51..1def19f3 100644 --- a/docs/Nextor 2.1 Programmers Reference.md +++ b/docs/Nextor 2.1 Programmers Reference.md @@ -1,4 +1,4 @@ -# Nextor 2.0 Programmers Reference +# Nextor 2.1 Programmers Reference ## Index @@ -66,9 +66,21 @@ [6.2. Changing the NEXTOR.SYS version number](#62-changing-the-nextorsys-version-number) -[7. Change history](#7-change-history) +[7. Nextor internals](#7-nextor-internals) -[7.1. v2.1.0 beta 1](#71-v210-beta-1) +[7.1. One-time boot keys](#71-one-time-boot-keys) + +[7.2. Disk emulation mode](#72-disk-emulation-mode) + +[7.2.1. Disk emulation data file format](#721-disk-emulation-data-file-format) + +[7.2.2. Entering disk emulation mode](#722-entering-disk-emulation-mode) + +[8. Change history](#8-change-history) + +[8.1. v2.1.0 beta 2](#81-v210-beta-2) + +[8.2. v2.1.0 beta 1](#82-v210-beta-1) ## 1. Introduction @@ -299,7 +311,7 @@ Results: A = error code BC = extra space in bytes ``` -This function returns the total or free space for a drive. The space information is always returned in Kilobytes, regardless of the type and the cluster size of the filesystem mapped to the drive. +This function returns the total or free space for a drive. The space information in HL:DE is always returned in Kilobytes, regardless of the type and the cluster size of the filesystem mapped to the drive. The "extra free space in bytes" result will be different from zero only when the minimum allocation unit of the drive is not a whole number of kilobytes. In case of FAT drives, it will be non-zero (specifically, it will be 512) only when the drive uses one sector per cluster and the cluster count is odd. For example, for a drive having one sector per cluster and 15 free clusters, this function will return HL=0, DE=7 and BC=512 when called with A=0 for that drive. @@ -413,9 +425,9 @@ The information returned in the data buffer is as follows: 0 for drive-based drivers and MSX-DOS drivers) +5: Logical unit index (for device-based drivers only; 0 for drive-based drivers and MSX-DOS drivers) -+5..+8: First device sector number (for devices in device-based drivers only; ++6..+9: First device sector number (for devices in device-based drivers only; always zero for drive-based drivers and MSX-DOS drivers) -+9..+63: Reserved (currently always zero) ++10..+63: Reserved (currently always zero) ``` If a file is mounted in the drive, the information returned in the data buffer is insetad as follows: @@ -442,13 +454,20 @@ Parameters: C = 7AH (_GPART) D = Device index E = Logical unit index H = Primary partition number (1 to 4) + H:7 = 0: Get information about the partition + 1: Get the device sector number that holds + the partition table entry L = Extended partition number (0 for an entry in the primary partition table) Results: A = Error code - B = Partition type code, - 0 if the specified partition does not exist - HL:DE = Starting device absolute sector number of the partition + If partition information is requested: + B = Partition type code + C = Status byte of the partition + HL:DE = Starting device absolute sector number of the partition + IX:IY = Partition size in sectors + If the sector number of the partition table entry is requested: + HL:DE = Device sector number that holds the partition table entry ``` Returns information about a device partition. This function works in MSX-DOS 1 mode. @@ -464,7 +483,7 @@ The partition type code returns information about the filesystem that the partit 1: FAT12 4: FAT16, smaller than 32MB (obsolete) 5: Extended (see below) -6: FAT16 +6: FAT16 (CHS) 14: FAT16 (LBA) ``` @@ -474,11 +493,11 @@ A device can have up to four primary partitions, numbered 1 to 4. In order to ac In order to enumerate all the partitions existing in a device , the following procedure should be followed, to take in account the possible presence of extended partitions: - 1. Search partition 1-0 (primary number 1, extended number 0). +1. Search partition 1-0 (primary number 1, extended number 0). 2. Search partition 2-0. If it exists and is of type "Extended", search partitions 2-1, 2-2, 2-3, etc, until a partition code 0 is returned. -3. If partition 2-0 does not exist or is not of type "Extended", search partitions 3-0 and 3-4. +3. If partition 2-0 does not exist or is not of type "Extended", search partitions 3-0 and 4-0. Note that it is possible that a device has no partitions at all. In this case, it is still possible that the device contains a valid filesystem, mapped to the absolute device sector zero; this is indeed the case of floppy disks and devices with very small capacity. @@ -486,7 +505,16 @@ When a partition is mapped to a drive letter, the partition first sector will al Nextor needs to read the device in order to search for partitions. If there is any error when accessing the device (for example, not ready), an error code will be returned. The standard system error handling routine (or the user error handling routine, if one is defined with _DEFER) will NOT be invoked. -When the specified partition does not exist in the device (for example, when a primary partition number larger than 4 is specified, or when an extended partition number is specified for a non-extended primary partition), then B=0 and A=.IPART will be returned. +When the specified partition does not exist in the device (for example, when a primary partition number larger than 4 is specified, or when an extended partition number is specified for a non-extended primary partition), then A=.IPART will be returned. + +Starting with Nextor 2.1.0 beta 2, it is possible to request the device sector number that holds the partition table, instead of requesting information about the partition; this is useful for applications intended for modifying the partition table entries. The way to locate the partition table entry in the returned sector is as follows: + +* If a primary partition was requested (extended number was 0), then the sector number returned is always 0, and the offset for the partition table entry in the sector is 1BEh, 1CEh, 1DEh and 1EEh for primary partition numbers 1, 2, 3 and 4 respectively. + +* If an extended partition is requested (primary partition number is 2, extended partition number is not 0) then the partition table entry is the first one in the returned sector (at offset 1BEh). + +For more information on the partition table structure see [Master Boot Record on Wikipedia](https://en.wikipedia.org/wiki/Master_boot_record). + ### 3.11. Call a routine in a device driver (_CDRVR, 7Bh) @@ -583,8 +611,8 @@ Parameters: C = 7DH (_Z80MODE) A = Driver slot number B = 00H => get current Z80 access mode 01H => set Z80 access mode - D = 00H => disable Z80 access mode (only if A=01H) - FFH => enable Z80 access mode (only if A=01H) + D = 00H => disable Z80 access mode (only if B=01H) + FFH => enable Z80 access mode (only if B=01H) Results: A = Error code D = Current Z80 access mode for the specified driver, @@ -708,13 +736,101 @@ Of course this change is temporary and it will cease to have effect (that is, th All of this applies only if the loaded version of NEXTOR.SYS is 2.0 beta 2 or newer. -## 7. Change history +## 7. Nextor internals + +This section details how some of the Nextor features work internally. This may be useful to develop applications that make use of these features as an alternative to the supplied Nextor tools. + +## 7.1. One-time boot keys + +The [one-time boot keys mechanism](Nextor%202.1%20User%20Manual.md#292-one-time-boot-keys) kicks in at boot time when the zero-terminated signature string NEXTOR_BOOT_KEYS is found at address A100h. In that case, the status of the alphanumeric keys are taken from the bytes that follow the signature, instead of being read from the keyboard, as the following table shows; a bit set to 1 means that the key is considered to be pressed. + +| Address | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +|:-------:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| +| A111h | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | +| A112h | F | E | D | C | B | A | 9 | 8 | +| A113h | N | M | L | K | J | I | H | G | +| A114h | V | U | T | S | R | Q | P | O | +| A115h | | |CTRL|SHFT| Z | Y | X | W | + +Note that currently not all keys are actually used by Nextor at boot time (e.g. numbers 6 to 9); but if any future version of Nextor makes use of any of the currently unused keys in the table, the key status will be expected to be at the position defined in this table when using the one-time boot keys mechanism. + +## 7.2. Disk emulation mode + +This section explains some details about the [disk emulation mode](Nextor%202.1%20User%20Manual.md#39-disk-emulation-mode). + +### 7.2.1. Disk emulation data file format + +The disk emulation data file, used by Nextor to know which disk image files must be used during an emulation session, consists of a header followed by a table with information about each of the disk image files. The header has the following contents: + +| Offset | Meaning | +|:------:|---------| +| +0 | Signature string `NEXTOR_EMU_DATA`, zero terminated | +| +16 | Number of entries in the disk image files table | +| +17 | 1-based index of the file to mount at boot time | +| +18 | Address to use as work area during the emulation session, or 0 if this area must be allocated (2 bytes, little endian) | +| +20 | Reserved, must be zero (4 bytes) | + +Each entry in the disk image files table is as follows: + +| Offset | Meaning | +|:------:|---------| +| +0 | Number of the device that contains the file (0 = same as emulation data file) | +| +1 | Number of the logical unit that contains the file (if device number is not 0) | +| +2 | Absolute device sector number where the file starts (4 bytes, little endian) | +| +6 | Size of the file in sectors (2 bytes, little endian) | + +If the device number in a disk image files table entry is zero, then Nextor will assume that the disk image file is located at the same device and logical unit as the emulation data file (the logical unit number in the table entry is ignored in this case). The `EMUFILE.COM` tool sets the device number to 0 for all entries if all the disk image files are located in the same device and logical unit as the emulation data file that is being created. + +Any contents in the emulation data file past the last entry in the disk images file table is ignored by the Nextor kernel. The `EMUFILE.COM` tool places here a printable list of the disk image filenames, it can be displayed by executing `TYPE /B datafile` in the command prompt. + +### 7.2.2. Entering disk emulation mode + +At boot time Nextor will enter disk emulation mode if it finds a pointer to the disk emulation data file. This pointer consists simply of a device+logical unit number and an absolute device sector number. + +Note that although this documentation and [the user manual](Nextor%202.1%20User%20Manual.md) use the term "emulation data file", an actual file isn't required - the Nextor kernel is only concerned about the sector number where the emulation data is located, regardless of whether this sector is part of a file or not. Using a file is usually the most convenient way to store this information, but a tool could be developed to use e.g. a reserved sector right before the FAT for this purpose. + +Nextor will enter the one-time disk emulation mode if it finds the following information in RAM at boot time: + +| Address | Contents | +|:-------:|---------| +| A000h | Signature string `NEXTOR_EMU_DATA`, zero terminated | +| A010h | Number of the device that contains the emulation data | +| A011h | Number of the logical unit that contains the emulation data | +| A012h | Absolute device sector number that contains the emulation data (4 bytes, little endian) | + +If the above information is not found, Nextor will enter the persistent disk emulation mode if it finds the following information in the first partition table entry of any of the available devices in the primary Nextor controller: + +| Sector offset | Partition table entry offset | Partition table meaning | Nextor meaning | +|:-------------:|:----------------------------:|-------------------------|----------------| +| 1BEh | +0 | Status byte | Bit 0 set = enter disk emulation mode | +| 1BFh | +1 | Start CHS | Number of the device that contains the emulation data | +| 1C0h | +2 | Start CHS | Number of the logical unit that contains the emulation data | +| 1C1h | +3 | Start CHS | MSB of the absolute device sector number that contains the emulation data | +| 1C2h | +4 | Partition type | Must be non zero | +| 1C3h | +5 | End CHS | 3rd byte of the absolute device sector number that contains the emulation data | +| 1C4h | +6 | End CHS | 2nd byte of the absolute device sector number that contains the emulation data | +| 1C5h | +7 | End CHS | LSB of the absolute device sector number that contains the emulation data | + +For example, if the emulation data is located at device 1, logical unit 2, sector 33445566h, and the partition is FAT16 (partition type 0Eh) and has the "active" flag set in the status byte, then the start of the partition table entry set for persistent emulation would look like this (in hexadecimal): + + 81 01 02 33 0E 44 55 66 + +Note that the condition for Nextor entering emulation mode is that bit 0 of the status byte must be set **and** the partition type code must be non-zero (but can be any other value, not necessarily FAT). Also note that the device and logical unit information here refers to the emulation data file only - the disk image files themselves can be located at a different device. + +Also worth noting: Nextor will check that the emulation data actually starts with the `NEXTOR_EMU_DATA` signature, and if that's not the case then it will boot normally without entering disk emulation mode. + + +## 8. Change history This section contains the change history for the different versions of Nextor. Only the changes that are meaningful from the application developer point of view are listed. For information on changes in general, please look at the _[Nextor 2.1 User Manual](Nextor%202.1%20User%20Manual.md)_ document. For information on changes related to driver development, please look at the _[Nextor 2.1 Driver Development Guide](Nextor%202.1%20Driver%20Development%20Guide.md)_ document. This list contains the changes for the 2.1 branch only. For the change history of the 2.0 branch see the _[Nextor 2.0 Programmers Reference](../../../blob/v2.0/docs/Nextor%202.0%20Programmers%20Reference.md#7-change-history)_ document. -### 7.1. v2.1.0 beta 1 +### 8.1. v2.1.0 beta 2 + +* [_GPART](#310-get-information-about-a-device-partition-_gpart-7ah) now returns the status byte of the partition, and allows to retrieve the device sector number that holds the partition table entry instead of information about the partition. + +### 8.2. v2.1.0 beta 1 * [_GDRVR](#38-get-information-about-a-device-driver-_gdrvr-78h) now returns an extra flag that tells if the driver implements the DRV_CONFIG routine. diff --git a/docs/Nextor 2.1 User Manual.md b/docs/Nextor 2.1 User Manual.md index d167472d..b3131fbf 100644 --- a/docs/Nextor 2.1 User Manual.md +++ b/docs/Nextor 2.1 User Manual.md @@ -30,6 +30,10 @@ [2.9. Boot keys](#29-boot-keys) +[2.9.1. Boot key inverters](#291-boot-key-inverters) + +[2.9.2. One-time boot keys](#292-one-time-boot-keys) + [2.10. Built-in partitioning tool](#210-built-in-partitioning-tool) [2.11. Embedded MSX-DOS 1](#211-embedded-msx-dos-1) @@ -74,6 +78,10 @@ [3.4.10. NSYSVER: the NEXTOR.SYS version changer](#3410-nsysver-the-nextorsys-version-changer) +[3.4.11. NEXBOOT: the one-time boot keys configuration tool](#3411-nexboot-the-one-time-boot-keys-configuration-tool) + +[3.4.12. EMUFILE: the disk emulation mode tool](#3412-emufile-the-disk-emulation-mode-tool) + [3.5. The built-in partitioning tool](#35-the-built-in-partitioning-tool) [3.6. Extensions to Disk BASIC](#36-extensions-to-disk-basic) @@ -126,7 +134,9 @@ [5. Change history](#5-change-history) -[5.1. v2.1.0 beta 1](#51-v210-beta-1) +[5.1. v2.1.0 beta 2](#51-v210-beta-2) + +[5.2. v2.1.0 beta 1](#52-v210-beta-1) ## 1. Introduction @@ -239,6 +249,8 @@ MSX-DOS 2 provides a set mapper support routines, which allow applications to al The boot time configuration of Nextor can be modified by keeping pressed some special keys while the system is booting. These keys and their behavior are: +* **0**: Disable permanent disk emulation mode by deleting the emulation data file pointer from the partition table. See _[3.9. Disk emulation mode](#39-disk-emulation-mode)_. + * **1**: Force boot in MSX-DOS 1 mode. If the computer is a MSX Turbo-R, switches CPU to Z80 mode. * **2**: Force boot in MSX-DOS 1 mode. If the computer is a MSX Turbo-R, switches CPU to R800-ROM mode. Note that in MSX-DOS 1 mode, the active CPU is never changed when accessing disk drives; this may cause some storage devices to not work properly, especially those mapped to MSX-DOS drivers such as floppy disk drives. @@ -249,7 +261,7 @@ The boot time configuration of Nextor can be modified by keeping pressed some sp * **5**: Assign only one drive to each Nextor kernel with a device-based driver regardless of the number of devices controlled by the driver. This overrides the normal behavior, in which Nextor assigns one drive per device found (see _[3.2. Booting Nextor](#32-booting-nextor)_). This is just the default behavior, though - drivers can override it they implement [the DRV_CONFIG routine](Nextor%202.1%20Driver%20Development%20Guide.md#448-drv_config-4151h)). -* **CTRL**: The state of this key is passed to MSX-DOS kernels on initialization. Typically this will cause the internal floppy disk drive to disable it second "ghost" drive, allowing to free some extra memory, especially in MSX-DOS 1 mode. +* **CTRL**: The state of this key is passed to MSX-DOS kernels on initialization. Typically this will cause the internal floppy disk drive to disable it second "ghost" drive, allowing to free some extra memory, especially in MSX-DOS 1 mode. Note that this key is inverted by default so you'll get the opposite behavior unless you customize the Nextor ROM (see _[2.9.1. Boot key inverters](#291-boot-key-inverters)_). * **SHIFT**: Prevent MSX-DOS kernels from booting, but allow Nextor kernels to boot normally. This is useful to disable the internal floppy disk drive in order to get some extra TPA memory, especially in MSX-DOS 1 mode. @@ -264,6 +276,47 @@ The boot time configuration of Nextor can be modified by keeping pressed some sp Example: if your Nextor kernel is in primary slot 1, press Q to prevent it from booting. If you have it in slot 2-3, press F. +#### 2.9.1. Boot key inverters + +The Nextor kernel has two bytes, at offsets 512 and 513 in the ROM that act as _boot key inverters_. There's one bit assigned to each of the keys that affect the booting process (not including the slot keys), and when that bit it set, then the meaning of the key is inverted. For example, if the bit for the SHIFT key is pressed, then MSX-DOS drivers will be disabled unless SHIFT is pressed while booting. + +Being hardcoded values, the only way to customize them is to modify the Nextor ROM file before flashing it into your device. The MKNEXROM.EXE tool can be used for that, or you can do it manually using a hexadecimal editor. + +Here's how bits are assigned to each key: + +* First byte (offset 512): + + * Bits 1 to 5: keys 1 to 5 + +* Second byte (offset 513): + + * Bit 5: CTRL key + * Bit 4: SHIFT key + +All other bits are currently unused and should always be 0 to ensure compatibility with possible future extensions. + +If you use MKNEXROM.EXE you need to supply a 16 bit hexadecimal value with the `/k` parameter. You should build that number by adding the values for each key as follows: + + * 1: 0002 + * 2: 0004 + * 3: 0008 + * 4: 0010 + * 5: 0020 + * CTRL: 2000 + * SHIFT: 1000 + +e.g. `/k:3002` to invert the 1, CTRL and SHIFT keys. + +By default (when using the "official" ROM files) only the CTRL key is inverted, so that by default internal floppy disk drives will boot with only one drive letter assigned. + +#### 2.9.2. One-time boot keys + +There's an alternative way to modify the Nextor booting procedure: the _one-time boot keys_. If at boot time Nextor finds a certain signature at a certain position in RAM, it will read a handful of bytes following that signature and use them as the values for the boot keys (including the slot keys), ignoring the keyboard. The RAM area used is at page 2, therefore this only works on computers with at least 32K RAM. + +Being a RAM based mechanism, it's "one-time" in the sense that it won't work again on the next computer reset unless the signature and the key data is put on memory again. The signature is explicitly erased by Nextor after being read to make this behavior consistent. + +The [NEXBOOT.COM tool](#3411-nexboot-the-one-time-boot-keys-configuration-tool) can be used to easily set this data and reset the computer, but all the tool does is writing to RAM, and thus any other tool could be used instead. The details on the location and format of the data used by this mechanism are in the _[Nextor 2.1 Programmers Reference](Nextor%202.1%20Programmers%20Reference.md)_ document. + ### 2.10. Built-in partitioning tool The Nextor kernel has a built-in device partitioning tool that can be started by just executing CALL FDISK in the BASIC prompt. It can be used to create partitions of any size between 100KB and 4GB on devices controlled by Nextor device based drivers. See _[3.5. The built-in partitioning tool](#35-the-built-in-partitioning-tool)_. @@ -301,6 +354,8 @@ Nextor consists of the following components: **Note:** two variants of the NEXTOR.SYS file exist. See _[4.3. Reduced NEXTOR.SYS without Japanese error messages](#43-reduced-nextorsys-without-japanese-error-messages)_. +**Note:** starting with Nextor 2.1.0 beta 2, the kernel will try to load MSXDOS2.SYS if NEXTOR.SYS is not found. However in this case the Nextor command line tools won't work. + In order to boot in the MSX-DOS 1 prompt, you need the usual MSXDOS.SYS and COMMAND.COM files. Also, if you have just the kernel and no NEXTOR.SYS or MSXDOS.SYS files, Nextor will boot in the BASIC prompt (running AUTOEXEC.BAS if present). Therefore, in order to "install" Nextor, you have two options: @@ -325,7 +380,7 @@ Also, note that the Sunrise IDE driver supplied with Nextor 2.0 is an experiment The Nextor booting procedure is similar to the one performed by MSX-DOS 2. However, if Nextor device-based drivers are present, things are a little different since it is necessary to perform a drive to device and partition mapping for all the drives attached to Nextor drivers (if you are not using any Nextor kernel with a device-based driver attached, then the booting procedure is identical to MSX-DOS 2). -At boot time, Nextor will perform a query to all the available device-based drivers to find out how many devices are being controlled by these drivers (actually, how many logical units, but devices will usually have one single logical unit), and will assign to each driver as many drives as devices are controlled by the driver. If CTRL is pressed at boot time, only one drive is assigned to each driver instead (see _[2.9. Boot keys](#29-boot-keys)_). +At boot time, Nextor will perform a query to all the available device-based drivers to find out how many devices are being controlled by these drivers (actually, how many logical units, but devices will usually have one single logical unit), and will assign to each driver as many drives as devices are controlled by the driver. If 5 is pressed at boot time, only one drive is assigned to each driver instead (see _[2.9. Boot keys](#29-boot-keys)_). For example, assume that you have two Nextor kernels with a device-based driver attached. The kernel in slot 1 controls one device, while the kernel in slot 2 controls three devices. Then the initial drive assignment would be as follows: @@ -335,37 +390,25 @@ B:, C:, D: for driver on slot 2 E:, F: for the internal disk drive ``` -If you boot while pressing CTRL, the assignment will be: +If you boot while pressing 5, the assignment will be: ``` A: for driver on slot 1 B: for driver on slot 2 -C: for the internal disk drive (which is affected by CTRL as well) +C:, D: for the internal disk drive ``` The internal disk drive would not have any drives attached if you pressed SHIFT while booting (see _[2.9. Boot keys](#29-boot-keys)_). -After all drives have been assigned to drivers, a device and partition to drive automatic mapping procedure will be run for each of these drives. The procedure is repeated for each driver and is as follows: - -1. Start with the first drive associated to the first Nextor device-based driver found. - -2. Start with the first logical unit on the first device available. - -3. Scan all the existing primary partitions. If one of them has a FAT12 or FAT16 filesystem which has a file named NEXTOR.DAT in the root directory, map it to the drive. (If the drive has no valid partition table, search for one single filesystem at device sector zero) - -4. If step 3 fails, repeat it with the next logical unit available in the device. +After all drives have been assigned to drivers, a device and partition to drive automatic mapping procedure will be run for each of these drives. Each drive is mapped to the first partition found that meets the following conditions: -5. If step 3 fails for all the logical units on the device, repeat it with the next device. +1. Is a valid FAT12 or FAT16 partition (only FAT12 when booting in MSX-DOS 1 mode) +2. Has the "active" flag set in the partition table (this can be set using [FDISK](#35-the-built-in-partitioning-tool)) +3. No drives have been already mapped to partitions in the same device -6. If step 3 fails for all the devices, repeat from step 1 but this time do not search a NEXTOR.DAT file (that is, map the first FAT12 or FAT16 partition available). +If no partitions are found that meet all three conditions, then the search is started over, but this time skipping the "active" flag check. If this fails again, absolute sector 0 of the device is checked (to see if the device doesn't have partitions but holds a valid FAT filesystem) as a last resort before leaving the drive unmapped. -7. If step 6 fails (there are no usable partitions available), leave the drive unmapped. - -8. Repeat steps 2-7 for the other drives assigned to the driver (if any), but skipping the logical units already assigned to a drive. - -9. Go to the next device-based driver (if any), and repeat from step 2. - -In short: available devices having a FAT12 or FAT16 partition are assigned to the available drives in device and logical unit number order, but the first partition having a NEXTOR.DAT file in the root directory has preference. Note that the contents of the NEXTOR.DAT file is irrelevant, it may even be an empty file (in future versions of Nextor this file is likely to contain some system configuration information). Also, note that only primary partitions are examined in the automatic mapping procedure. +Note that in order to speed up the botting procedure, only the first 9 partitions of each device are scanned during this procedure; consequently, [FDISK](#35-the-built-in-partitioning-tool) allows to change the "active" flag on these first 9 partitions only. Starting with Nextor 2.0.5, device-based drivers can tell Nextor how many drives they want at boot time and which devices should be mapped to these drivers, bypassing part of this automatic procedure (partitions are still selected automatically). This feature is optional, and must be implemented by the driver developer. @@ -373,7 +416,7 @@ After the automatic mapping is finished, the boot procedure will continue with t 1. If the "3" key is being pressed, the system displays the BASIC prompt. -2. Otherwise, if the NEXTOR.SYS and COMMAND2.COM files are present in the boot drive (the first drive that is not unmapped), the DOS prompt is shown after AUTOEXEC.BAT is executed (if present). +2. Otherwise, if the NEXTOR.SYS (or MSXDOS2.SYS) and COMMAND2.COM files are present in the boot drive (the first drive that is not unmapped), the DOS prompt is shown after AUTOEXEC.BAT is executed (if present). 3. Otherwise, if the boot drive has a MSX-DOS 1 or MSX-DOS 2 boot sector, its boot code is executed as in the case of MSX-DOS: first in the BASIC environment with the carry flag reset, then in the DOS environment with the carry flag set. This will usually cause MSXDOS.SYS and COMMAND.COM to be loaded if present. @@ -381,6 +424,8 @@ After the automatic mapping is finished, the boot procedure will continue with t Note that step 3 will not be done if the disk has a standard boot sector (not created by MSX-DOS 1 or MSX-DOS 2). The built-in disk partitioning tool will create MSX-DOS 2 boot sectors for all partitions of 32MB or less, and standard boot sectors for larger partitions. +Starting with Nextor 2.1.0 beta 2, the Nextor kernel will load MSXDOS2.SYS if present when NEXTOR.SYS is not found, thus allowing booting from old MSX-DOS 2 disks. Note however that in this case the Nextor command line tools won't work. + #### 3.2.1. Booting in DOS 1 mode Nextor kernel can boot in MSX-DOS 1 mode. This will happen if anything of the following conditions is met: @@ -598,6 +643,45 @@ Note: the version number change performed by this tool is temporary and it will Note: do not use this tool with NEXTOR.SYS versions older than 2.0 beta 2. +#### 3.4.11. NEXBOOT: the one-time boot keys configuration tool + +The NEXBOOT.COM tool allows to easily configure the keys to be used as [one-time boot keys](#292-one-time-boot-keys) in the next reset. The syntax is: + +``` +NEXBOOT |. [ [... ]] +``` + +where the boot keys are the numeric keys, C for CTRL and S for shift, and `` are the slot numbers of the Nextor kernels to be disabled. For example `NEXBOOT 1C` will invert CTRL and 1 keys, `NEXBOOT S 1 23` will invert the SHIFT keys and disable the Nextor kernels in slots 1 and 2-3, and `NEXBOOT . 2` will just disable the Nextor kernel in slot 2. + +In all cases, the tool resets the computer immediately after apporpriately setting the keys information in RAM. + +#### 3.4.12. EMUFILE: the disk emulation mode tool + +The EMUFILE.COM tool allows to create disk emulation mode data files and to enter disk emulation mode. The syntax for creating an emulation data file is: + +``` +emufile [] [ ...] +``` + +`` is the name of the emulation data file that will be created (default extension is .EMU), and `` are the disk image files that will be used for the emulation (these can contain wildcards). Numbers (for disk change) are assigned to the disk image files in the same order as they are specified; when using wildcards, in the order they are found in the storage device that contains them (the same order that you see when you do run the DIR command). + +The `-b ` option allows you to specify the number of the disk image file that will be used to boot when the emulation session starts, default is 1. + +The `-a
` option allows you to specify the page 3 address that Nextor will use as work area (about 16 bytes) during the emulation session, must be a hexadecimal number in page 3 (C000 or higher). If not specified, this area will be allocated by Nextor before starting the emulation session. + +The `-p` option will print all the filenames and associated keys after creating the data file. Note however that you can see this same information afterwards if you `TYPE /B` the emulation data file. + +The syntax for starting a disk emulation session is as follows: + +``` +emufile set [o|p[[]]] +``` + +`o` will start the emulation using the one-time variant (this is the default), and `p` will start the emulation using the persistent variant. For the later, by default the emulation file data pointer will be written to the device where `` is stored, but you can specify a different `` and also optionally a ``. The default LUN index is 1 (i.e. `p3` is the same as `p31`). + +Note that in both variants the computer will reset immediately after `EMUFILE.COM` writes the emulation data file pointer to the appropriate place. + + ### 3.5. The built-in partitioning tool The Nextor kernel has an embedded utility for partitioning storage devices attached to Nextor device-based drivers. To start it, just invoke CALL FDISK from the BASIC prompt. It works properly on both 40 columns and 80 columns mode. Please note that starting the FDISK tool will delete the current BASIC program from memory. @@ -614,12 +698,12 @@ The tool has a user interface based on menus, so anyone should be able to use it * Partitions up to 32MB will have a MSX-DOS 2 boot sector, partitions of 33MB and more will have a standard boot sector. -* If four partitions or less are defined, they will be created as primary partitions. If five partitions or more are defined, then the first one will be primary and the others will be extended partitions contained within the second primary partition. Remember that Nextor only scans primary partitions during the automatic drive to device and partition mapping process. - * To get an optimum cluster size, it is recommended to define the partition sizes as powers of two (that is: 1M, 2M, 4M, 8M, 16M or 32M for FAT12 partitions; 64M, 128M, 256M, 512M, 1G, 2G or 4G for FAT16 partitions). If this is not possible, it is better to select the partition size as slightly smaller than the closest power of two than slightly higher (that is, for example 31M is better than 33M). Remember that Nextor can handle devices with FAT16 partitions and standard boot sectors; if you use a factory-partitioned device of 2GB or less you probably don't need to partition it, unless you want to create MSX-DOS 1 compatible partitions (4GB devices are usually shipped with a FAT32 partition, so you will need to partition it with FDISK anyway). +When creating new partitions you can choose which one(s) will have the "active" flag set, thus being eligible for automatic mapping at boot time (see _[3.2. Booting Nextor](#32-booting-nextor)_); it is also possible change the flag on already existing partitions. + The partitioning tool works in MSX-DOS 1 mode too. Note however that the tool will always allow you to create partitions larger than 16M, which are not compatible with MSX-DOS 1. ### 3.6. Extensions to Disk BASIC @@ -927,16 +1011,22 @@ ATTRIB +R TOOLS.DSK --> Error ### 3.9. Disk emulation mode -Since version 2.1 Nextor allows to boot in disk emulation mode. In this mode the usies a disk image file (or a set of swappable files) as the boot device instead of a regular device. This is ideal for playing disks that were released in floppy disk and can't be run from a modern storage device, because they don't have a filesystem or because they need to run in MSX-DOS 1 mode. +Since version 2.1 Nextor allows to boot in disk emulation mode. In this mode Nextor uses a disk image file (or a set of swappable files) as the boot device instead of a regular device. This is ideal for playing disks that were released in floppy disk and can't be run from a modern storage device, because they don't have a filesystem or because they need to run in MSX-DOS 1 mode. + +The technical details about how the disk emulation mode works are in the _[Nextor 2.1 Programmers Reference](Nextor%202.1%20Programmers%20Reference.md)_ document in case you are interested in building your own tool instead of using `EMUFILE.COM`. #### 3.9.1. Entering and exiting the disk emulation mode -Nextor will boot in disk emulation mode if it finds a file named `NEXT_DSK.DAT` in the root directory of a primary partition in a device controlled by the primary Nextor controller. This file contains information about the disk image files to be used for the emulation. +First of all, the data needed during a disk emulation mode session (which disk image files will be used and where are they located) must exist in a file with a certain format, the _disk emulation data file_. You can create these files using [the `EMUFILE.COM` tool](#3412-emufile-the-disk-emulation-mode-tool). These files can have any name and will typically have the .EMU extension, but that's not mandatory. + +Second, in order to tell Nextor to boot in disk emulation mode, a pointer to the appropriate disk emulation data file must exist at a special location while the computer boots. There are two variants of the emulation mode, each requiring a different location for the emulation data file pointer: + +* **One-time:** Nextor will enter disk emulation mode only once, that is, after resetting the computer again Nextor will boot normally. In this mode the pointer to the emulation data file is set in RAM. -The `NEXT_DSK.DAT` file is created by using the supplied `EMUFILE.COM` tool. Most times it's as easy as doing just `EMUFILE file1.dsk file2.dsk file3.dsk` (or `EMUFILE game\*.dsk`, or just `EMUFILE game\`). There are additional options, run the program without parameters to get more information. +* **Persistent:** Nextor will enter disk emulation mode on every computer reset, until that mode is manually disabled by pressing 0 while booting. In this mode the pointer to the emulation data file is set in the partition table of one of the devices controlled by Nextor (usually the same device that contains the emulation data file and the disk image files, but that's not mandatory). -To disable the disk emulation mode (that is, to boot normally even if a `NEXT_DSK.DAT` file exists), keep the 0 (zero) key pressed while the computer boots. You will have to manually delete or rename the `NEXT_DSK.DAT` file to prevent the disk emulation mode to be entered again in the next system boot. +Both variants of disk emulation mode can be entered by using the `EMUFILE.COM` tool with the `set` parameter, being the one-time variant the default one. #### 3.9.2. Changing the image file @@ -945,7 +1035,7 @@ Up to 32 disk image files can be specified for an emulation session, but only on For example, assume that you are playing a two disks game. You boot with disk 1 and at some point the game asks you to insert disk 2 and press space key. Just press 2 (they key assigned to the second image file) and the space key at the same time and you're good to go. -Alternatively, you can also press the GRAPH key when the computer is trying to read the file. The caps led will lit and the computer will freeze until you release GRAPH and press the appropriate file key. This is useful when having to directly press an alphanumeric key while disk access is performed is a problem (for example, you are in the BASIC prompt and you want to trigger a file change when executing a FILES command: the pressed key would be added to "FILES" causing a Syntax Error). +Alternatively, you can also press the GRAPH key when the computer is trying to read the file. The CAPS led will lit and the computer will freeze until you release GRAPH and press the appropriate file key (or you can press GRAPH again if you change your mind and want to keep using the same disk). This is useful when having to directly press an alphanumeric key while disk access is performed is a problem (for example, you are in the BASIC prompt and you want to trigger a file change when executing a FILES command: the pressed key would be added to "FILES" causing a Syntax Error). #### 3.9.3. Rules and restrictions @@ -954,9 +1044,9 @@ The following rules and restrictions apply to the disk emulation mode: - The primary controller must be a Nextor kernel with a device-based driver. -- The `NEXT_DSK.DAT` file and all the disk image files must be placed in devices controlled by the primary controller (but they can be in different partitions and even in different devices). +- The emulation data file and all the disk image files must be placed in devices controlled by the primary controller (but they can be in different partitions and even in different devices). -- The `NEXT_DSK.DAT` file stores information about absolute device sectors, therefore it will be unusable if the disk image files are moved and file renames will have no effect. It is recommended to generate the file immediately before using it. +- The emulation data file stores information about absolute device sectors, therefore it will be unusable if the disk image files are moved and file renames will have no effect. It is recommended to either generate the file immediately before using it, or have a partition reserved only for disk image files and their corresponding emulation data files (that is, a partition where you usually don' create or move files around). - The disk image files must have a size of at least 512 bytes and at most 32 MBytes, must not contain partitions (the contained filesystem is expected to start right at the beginning of the file), and must contain a proper FAT12 filesystem (the FORMAT command will not work in disk emulation mode). @@ -966,8 +1056,6 @@ The following rules and restrictions apply to the disk emulation mode: - All Nextor controllers but the primary one will be disabled when disk emulation mode is entered. MSX-DOS kernels (such as the internal floppy disk drive) will not, but you can force them to disable themselves by pressing SHIFT while booting; this is useful to free some memory. -- If you are using a `NEXTOR.DAT` file to alter the device mappings priority, Nextor needs the `NEXT_DSK.DAT` to be found before NEXTOR.DAT in order to start emulation mode. This means that `NEXT_DSK.DAT` must be placed either 1. In the same partition of NEXTOR.DAT (relative position in the root directory is irrelevant); 2. In a primary partition with a smaller number in the same device; or 3. In a device with a smaller device number. - #### 3.9.4 How to free some memory @@ -980,7 +1068,7 @@ Some games will not work "out of the box" because they assume that only the flop #### 3.9.5. Known bugs -* The current version of the EMUFILE.COM tool does not verify that the disk image files are not fragmented. +* The current version of the `EMUFILE.COM` tool does not verify that the disk image files are not fragmented. * If you have more than one device in the primary Nextor controller (for example, for the MegaFlashROM SCC+ SD this means two SD cards, or one or two cards plus the ROM disk), Nextor will allocate one dummy drive letter for each extra device. MSX-DOS devices (if any) will then have drive letters assigned after these. For example, if you have three devices, A: is where the emulated disk image file is mounted, B: and C: are dummy, and D: is the internal floppy disk drive. These dummy drives will NOT have memory allocated for FAT buffers. @@ -1011,7 +1099,56 @@ This section contains the change history for the different versions of Nextor. C This list contains the changes for the 2.1 branch only. For the change history of the 2.0 branch see the _[Nextor 2.0 User Manual](../../../blob/v2.0/docs/Nextor%202.0%20User%20Manual.md#5-change-history)_ document. -### 5.1. v2.1.0 beta 1 +### 5.1. v2.1.0 beta 2 + +- Nextor will now try to load `MSXDOS2.SYS` if `NEXTOR.SYS` is not found in the boot drive. + +- The method for selecting partitions for automatic mapping has changed from requiring a `NEXTOR.DAT` file in the root directory to having the "active" flag set in the partition table. + +- Now the first 9 partitions of a device will be scanned during the automatic mapping procedure, this includes extended partitions. + +- FDISK allows to change the "active" flag of new and existing partitions. + +- FDISK now always creates extended partitions, even if 4 or less partitions are defined. + +- FDISK now creates FAT16 partitions with a partition type code of 14 (FAT16 LBA) instead of 6 (FAT16 CHS). + +- The numeric keyboard can now be used both when booting and when changing disks in disk emulation mode. + +- Russian keyboard is now properly recognized (numeric keys only). + +- Introduced the [boot key inverters](#291-boot-key-inverters). + +- Introduced the [one-time boot keys](#292-one-time-boot-keys). + +- Introduced the [NEXBOOT.COM tool](#3411-nexboot-the-one-time-boot-keys-configuration-tool) to set the RAM based one-time boot keys. + +- Introduced the RAM based one-time [disk emulation mode](#39-disk-emulation-mode). + +- The method to enter the old disk emulation mode (now named "persistent") has changed from requiring a `NEXT_DSK.DAT` file in the root directory to storing a pointer to the emulation data file in the partition table of the device. + +- Pressing the 0 key at boot time will delete the pointer to the emulation data file in the partition table, thus permanently disabling the emulation mode - no need to manually do anything else. + +- When Nextor is waiting for a disk key press after having pressed GRAPH in disk emulation mode, now you can press GRAPH again to cancel the disk change. + +- The first Nextor kernel to boot now clears the screen before invoking the driver initialization. + +- ARG is no longer used as temporary work area by the Nextor kernel, this should improve the compatibility of games in disk emulation mode. + +- Fix: drive was remapped in case of error (even if it was retried successfully). + +- Fix: boot sector checksum calculation had a bug that caused "Wrong disk" errors. + +- Fix: [#1 pressing CTRL+STOP while Nextor was trying to load NEXTOR.SYS hanged the computer](https://github.com/Konamiman/Nextor/issues/1). + +- Fix: [#23 computer hanged when booting with one single drive letter (e.g. when using single-device controller in a computer without internal disk drive)](https://github.com/Konamiman/Nextor/issues/23). + +- Fix: [#29 wrong stack management hangedd the computer when a file handle was read or written to a number of times](https://github.com/Konamiman/Nextor/issues/29). + +- Fix: computer crashing when more than one Nextor kernel was present as soon as the extended BIOS hook was called (for example, when loading COMMAND2.COM). + + +### 5.2. v2.1.0 beta 1 - All the changes and fixes of [Nextor 2.0.5](../../../blob/v2.0/docs/Nextor%202.0%20User%20Manual.md#51-v205-beta-1). diff --git a/docs/img/gsg/DirAAndDirB.png b/docs/img/gsg/DirAAndDirB.png index 582128e2177e40b3f1e48adbdae19b03592938c1..836363a6abfec408e43cee6125d3c9e76b8d976f 100644 GIT binary patch literal 26580 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

J2^32i$A_NP5>^WAfomHdX?o!= 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 Z5n34^3E345z|UnGV*_*jYSiWE{{TM|UYGy? diff --git a/docs/img/gsg/DirAAndDirBDos1Mode.png b/docs/img/gsg/DirAAndDirBDos1Mode.png index 41f4d5b5e8d42efe4b7182347a5f7d1e48c9f4e9..acc89d4061c20aff4f8f1af8ae8c834cade7339b 100644 GIT binary patch literal 24633 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 SivDvU_Pg!5Gv%lKZ~h0(evKpm diff --git a/docs/img/gsg/DirAAndDirBWithFiles.png b/docs/img/gsg/DirAAndDirBWithFiles.png index 8d0c2044e4cd8e6d0624b3fd5d2de86f89124b96..639ccbfb2818531d1d4b819d56c30fbd86e008fc 100644 GIT binary patch literal 31078 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 diff --git a/docs/img/gsg/DirInDos1Mode.png b/docs/img/gsg/DirInDos1Mode.png index 0daf23b8877d4245309a65c2100468be33eb9bb6..3aedc7610ba039c791dec8a709eb826f9601d6f5 100644 GIT binary patch literal 11633 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 S0$h{kGQ4w7x8#{3 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 diff --git a/docs/img/gsg/DirInDos1ModeWithNextorDat.png b/docs/img/gsg/DirInDos1ModeWithNextorDat.png index 5f55d8a35039083e5e86ab51d6892f4db1a49cce..6f3b2d7df3a32c319c6afe7897f1af9067d06257 100644 GIT binary patch literal 11382 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 diff --git a/docs/img/gsg/DirTwoSystemFiles.png b/docs/img/gsg/DirTwoSystemFiles.png index dca923337978166357506cc0af4dfb7cc4bca057..f9f056bdbf22d3def7a3b79d962eddf0f4bb344f 100644 GIT binary patch literal 13180 zcmd73dpwi>|39u*Nu?-64C@st39l)WoI8mXQ8~@2IfadwoK2DBlqjqm%PBDon;b{Z zjEOLWGHv8Iv!${5UcKJm&-eSeeQ&ql@4w&o_WNVkw(Gi{&&T6=xE_!DARr)c$mIGJO96phP~aoHZ!d7>w#|nL;AasU0gYTr_&}|?qvknYfWZ{SKXhP2`y6WrGiO|{zc0%9<`sl+l=H*? z?~XUjkmjM5V@`fo$9CGyH>-rzm$=r=>&HE^AQVZ5fWb7`2sUkesCL3TE2PL5o>1r7 zuo~<#sflKskwSa=?l~p;Qhd^v?>=U*{a|c|OhNYX7fE}^o%n8JK~qMUonN)=&WU#k zBK4{H6&PJO*DCB#crcNGg%P)&YY`pJ1(o|lGC0>BtRIe3{abAEJMcwSsur8v;W>>( zvP&Hzr$a!mp&-yt-s&p1dSHScXTG6Tn3f$lk+(H57RXab4&VtpR^mIxiuFg>lt_LN z#k%p`A~-m25xf&Tvzi?w0*1}0bTv$mu(hVv6T7qb+o6op4ADT>em5uYZ)Vnu_`>A!AY$Fza!`Eskr2ILFI>Mgu6a8ViaRqkRezj!kZ zmlksC+i1)YbE`AYV96nO8dTehiOvZtXJ(UC+sC%k*XV^0lh*pir=vwjf9-W?_>mqR z+RD{VZQnbemvAU_zWCz8HB?Fn(C3@fX$cbU3!*4;`+l=0jQvc>L6jo7bfNO5oAx9G z(}n1Qf8ySBF>@=#3of1%%Y0j))#0l`z%GCd-uO;f>LE_2Lcmk@Kk1c zC1x0V+tw4=TK_tY+RVnitz11y9e<>|^GOOie`5Eo_jCniVtCEBsK?7-JE-p&*0!Y~ z{ZsS?`tWX{Xu@4`_?4p5H~s8T?d9*ndWcVhZox+V@lTjy2@?eQ9962YAX!?3n8B zG@LL2OpjsJD09NblqjzW&MBL-u7KyMa|?Vc^o(KQF7)FzQVEJgkk2t_it3jteDn5? zauV(Np)BQY#~4qwW6oi%f|I<6-QKReBvxhUX7?&boy0aPU8OD<(q>#tJ^hD?GT!SbMlqd#!AiBaVE-1 z%S1o#J$0Ms9XUrU^qQP`XH%)c{ZHv~UwyWRP8th2aE(NHce*BDX};bL4ZXeA`8ia8 z^0}HeD4nMyS3x+Mqsq;h{t{vZdWA4CqC9UKR!&JUr_F_!soNN&P|uLHA2H^~{pOts z1vCQjQ}xxE;mnH^uV~A&%E0O1i%R}X&n#Wag5VbGhwcZ$)~df{j6f64VhL_GoG| zcYE%^Q|Iq;p#wz)-Qioy4w3zunfl6-Xvvm_8om3$Nm+s0C-T*~8zM3ed+@`)!Q=6f4QJB7kaaDgqh@YUm2iZG9l zS;|p_YN+WpUX4+Fq;84oD@4vYiqc@Uehd;8hjWL=YhMU?*6zL`@R}=#xc*QVJcxiJ zN|*<@)yx9ot@w}u-3&ttSE4GZU6SnPkI?z?>bna$nMWliChzG!{VX?vV}#*&)UtIa zQx66w*+j38kUp+ANget1u7bJcakZKE+sLb6Q!w+tuDT5+)HVS`nUBWO@6g2>l37a0f` zuDeterDX$NFNON%z&kTpI&M>qb?dIi9r_(&vib>%&=EaONlr?sb=q;hWzuzaCZ13& z5nh0fx$*Gt`?!buH-_JMm=3JIddQ;pzLYz{V|c?EIqi^$XKNYH=lsah;^kXtS-a9#*5>ei`+3M7QO!FI}rNb60{oq>nuwpi!#}B4+;)%Vgv$vgqg2 z-gdpVSH^#KT0r_P)sJH{uo=f~QhVZ(f-dt_PdCAGz?;Jk(^(Lvn%ag)FU>9EP>j#O zmHRY{h_D!^9xvi?(oi+3@tRrK1XxHVsD1b(lDvKY@1O?sm=3CBMr^&0vQRK{?HgRU z&R46zBo@n5mxknZ*=A=@%VsLVJIs;wE;}O?(}}fDXD@?w8bn(L&=;+B$G#S`z9Lj! zZ}<~8Uxb(87_}1UN+-ba%05ullpBdLT%G4Q{}3>tC}u6Kk+ip7D@Jm|Ezto{edJi9h_3^QXQH?CI0vO@YU_t@NbeH3}}P&H(TEx zf4(dld13o6m0xb3J82QW4#nI@otVs>vQdHu{C?Jwkvm=h)jz=G)+sK{uX;O8njyE> zakGLQ*uOpaY<1tg&Bc7Yf?S_2kGESoyXR@ zj)s{g-tc)MDJzlx>>e1fstcv%GHTt8s}Y&_w-mtykgx0jRjp3Z0IH7fNpD_l3c?!G zUxuW~C(40XpE~v-Ot<GX({IGjZTI9NC%wQ08tgPqMz23nlT?U}<{?(a zK@}QXY06Bu4`dP zk?4V~jgpVH`Co_x19STLg!bwGsW3K+nzzv(4FM$tU6aSDg%X0iN^?_(X`23AtH|5p zaPPC}Z;~Y_#%Ad!i4x)8RMIGNLV<)3eASR_Fl`M9-(tBE_yq>hFQ++B3*S@Bxwr@E%g_K@LPgy&6UA=55X z>`ewk&sU*MXePK4Eog5jpmy?sg^~Ya2Ij>$vv-s$xINp~i!D{Ab@#(yqciQ7N;b1U$xTUY3RWy6>krKanGUGWe|pNj zscuJ2#=Us?+4thK)jVb514-idNQ_WV7uC*^q-`rqEzmD3lVlx(UmxpUiN<5#C_U28 zK8}Z5E2i=~0tAC0XxW3!XasE`Nh!kmWKT$_(P3Gq=ZbiX_Yst^-VUz=TR~HVT_AJc zvzzU;+=zbf@TTMYo~s+DQlpOV3p7zA9^YqW{D0-xbs}zgo0YL;{#PC;qX`+jF>!md zIB$lF`%dwPRUO}FCL(Eqgzb<{@REKDDX%(J*zxzP?2CFR7N@!|Y6PN!*IV&(h+J)Q z*y*(viCa$QcaMSkhI2;QLDS>xncoA029f?t3;WgM^f-8j$Whz2+$p=MUR1k zeI9RlCXg3Inq+Hz{fGMgkj_#?W7T3L+gkJ_RLynJYJDqzF zTW5Q8&|YaFfVTmy+50b58V|g7m~dJ_Qhp}kXo5x$!k@KE0wc2O8W0Cv-L9rgtIaCt z_`O?PC6N|$*=0$(f_nO?m_@k5j`_|PwzY%iyh|)EgmK6u5xV%x#QZ0BhUZ{_=dHy$ z?EIz#@k$*vsVu7h;}iR$Xl(=HaFKw)j!ti>p-gn3yW4!!_B!^t0&ockk~mGPhhlgc z%>m!CS9P&B{ImQ`$7cLtV>7|D2fJE^-%`zY>KCzB_W?yXj$&KH7fry`SIc4}vXNH=|55j?f)-+y4i&d6P!S62RIU22F$o{KmLL_SZor^|4z&j7POc6_Gy>?X8P{+^V%lrVgMjQFr-B7 zQuoKHHZ8wnzcVa#G?U!Z%B6-Nyp;#g*ElOdzL6@Asv7~Qk*CU=^6Of|38~qhmk5qxb1 zGBUsAB>{n|%WLV_C$9&@&{r7@%u1e&1xnaP(iu2c(5r@l|NSp3lA|K5z4tci!vu)Q|m zFQUn_Iu)=n)nqT(*7|4d(8mA-JAoJ6>YfI+lRzUgY3nr=^E;z~&xoA%g~#LLl7tl) zIbk2Au5FHXZOs@cD$J_#_S{tg=2(e3*}fN+dr0|dkpbke@10chh{aTq{~z(Be~(u`5Z}-b{T5r)4t{}wQRUTlg+!jDjLB> zW!yApAnnvk-2J52$9(Eb{=`xJ=C_(Sgx`QQ7c0{?h<(UoXJY+nY=pagB86Ct{swW+ z>A=>VSx!3dzBtx-qRDFVJ6JPdSCWf)pV9^7Im9`o9WzL$2=SRAS7fUS9Lfy9EkpRl!7rZgHqSG|Cm4KqjOnZoYfuu zP0N{eZ?^6C4%&XrXhK|}#FCuY5d{%MfqF+-kV{Vf@Wtm@ju+LvqLm>Tt}dQ(u~#wPp-Ppie>#2V zB#%4mvG^O;qYIy8^mGo0fv&op%ndqnAZvT_73R(Rhemd;n`_X-k!lT0?|l6tw8IKB zeZQogBf9fXVnYGr9{Y6rOsMzR4kOYBL64N-&#Kq+6VL6HlmCo2U_6rJf z*g4qZiS+x@LNUP<_0R=w)y^05{m9`EGsYRYNi17+`H&nqew-ilY@^Ypk@@`hOp0c8 zb^G2M`Ux$H=f=W< z-CWy#m(d${oA>Je>(T&Z4msZ)wzG-%E5rA`oJ-S{*AdChD{Txf^096nOd^4z7eS2r*=`}y>R>YpG)Gl53VdFz= zt*dlk_}uj)6i40bjF#O^=l@4Z0zzp7|2!-opNzuPpNZ9?SP{Q)0oyS9GIxoapf=HtB>5@msY|-TmKd7; zLrTONlJa|!vW94>F|xf|XBCV6%o@-g0WWXFsuKvEjL#RR@%oK^RPAGnF68aPQ1rH) zDG`V9)|d>cq_ubI^n^{HYji>POh}SKlD60TgdACK{;(T2jk5k?>P$lOma>6ouFJ_NEjy9*E3F4+1rOij{KLpnZ<-aGlS z%&k5MbyjH-vK7+5bRPe>_THnh?z>XXc%+VSF*FZMf!5CFoF&A3@r_Hxu`N=67$)n( zXlqM`#7_fh-5o=SMMzMi_L`F^veC?Cuj_oFKf=;L$r7A{v_@YA7CoY`Vgm{EKgul6 zzK&FYUg{a;p6>C_GtMpa3l2OEzsE40LwMrZSeQ$-I1>mfdD^!8u?HvgkF zc}~;+sP3@3>FpMxphegz0)ZFfMCBM6Xxn-T1A(Iwd@*0K?=3UE^ZU4wXZaPibV+z} z9j*U+l2%$FB$|FEP5dQS8PcJ?Jfv!oslx3_UWQ`|JzSK>iO++Umvr%h0Q`dLz>pG< zyMuS`85DQ@+TTQU$P*U8U0sie4w_RIoNdct9KT=+_=wH2+)-iwP*2{yjQ1x$+kwZm z0Q~y!)qk#^z{{NjoP$wzwh~ldBVzt?8>QvNl?#=do|5M3s%0ywv@Ghzur@Aec=yG5 z#AQUjsJZ&S(RMR+`S~S8ZfcL88S>)d3C@shWykZNpW}{)Wwk_<@P1>zmTQA}Nm@P! zs1i)|=8uc&4NJ}z@E9Kv(}`C3_EE_p#6_Z4HBr|Q-M@y~yRsthonRjB@^a#gd(%LV z|J=6SE9!tQ8cUg&+Sq7ySO_l`2d$(siu2Ell#ZPcj-q{fs|alxecXc>3}uLL7#8aZ$zdzf$9?EA3{@#n zFZ7Rbn}E-;x%?3Ba76ZTsxb$OFVtvlwYwOtJpL)G-O6;|sFnV+Qi+7qfYCSoLhr3+ z9$VDf_x#Oui|Fu#)0b$4YKOD!?DX5jHDmGAu{nKR)JWCKOY zng*#@;|jffoTSSpNKXxXqTVC#{Y9frGQ!E+du^$xe)T*L$}>}1pacy&a-~Xw7b(bLqMkUpiox@jUq#nLMPS}! z9PhCd>y_U#ZKBZw?9y4h#RD_pEn@aqcVToh;ikFmxDZw~7M+7sIYJdIh%nyiO{MwMYF@T&VdFlyL+VR*%TQEdu; zAaCja&7%uIX|lhRljh$o8&IwW&bA*98?An7Fn%*+Vwm`U@h~4O@RE?J1+URc6 ztq(_$jW+ahUp04_XAbPF91E-YMh2Z^8@DWEFwZ4zHIy4LvXXARG_MSrnPN-XS00Mo zTvSa>%f@i?w$f_@c(tS{c7{_kke)iF|Cy~G`nibWUB19g#?&l=e_fba{bM%MtbM|l zqiUNU+9>`zIq*f=g-=vI+lklTXIB+TH73W-B}Xh(=9Hem-xjTS3U>bwhI0AGrQbv2J^8bE!4Bw53L<9n;z1j z_$sFtp8h>Gh85l2*((1Xf^rcV(%bXJ9}7|uM>7uSZKsU_{_3$v{l=8oj2HwyFDfVB z6qxMLp?l32NyY&{H;jHRHqngZA%5Gi@%z*Aofe^|LEZ}lAL5&t(YTyw1}({Vi3?ND zmaInNmM$=92Ko{WGh5T;0REHjygx~x|C*U$?`)CU!jF3xG;S2O@tt#RK$R>+L=E}q z)t{L@Ke?2M^5%+XtINIy?-@qqB{xKo?r>E)F04x8+!wlbmnB4e=5}tq>g8mEgN&$M z_#^qKTp89efTP$2c&_Lit&aiKgl=6D!6rR#&c&46CD+-pd91j$In`EgPPd3KDO-X% z)L)$)Mkv(SpiTl{n1FKV!-qPOTfFCL@?)D(6#N~s_G|yPR7f(AnY{EW{6^gGk8K~1 zfoU6~)*7X;SzSP+WeV9{kuv;To=emNRARVxUBpK)bQ~f(jygn6qT0G*1FB9R)ZhHJ z*TMBsmu}HwE-R}w{r2*?0qP1E8Hv-NtP+4MraEuvTBOurg9KNeS7UPI_5(XUGue0I zm=?`L-jvvN1mRJZ_!?iFnK5REZs_r(r6lan{Y`dP8_d96k0@A{-*f?g;k=mLUD{== z)o`t)xr;QK>KDrV3(_~RViLaz{@oo&YP{wcUk9Zq(L2vdIGt%&`?PC0jQbX4Ms~rb zQ8xxY#Nl5i->`)b=5TJmx#J7*uCgLEJo1~{76U;(s5+2Sm;DqR@&i~Cnq!Uk8+9i_ z9tD&aWUNG6>B3cRhnG0kU(55`r$dy`f#$%biGTVeRYqDPxiQUN^G+Ji(!PQ#Qz!OOuDFK1%qW#WfKb-ziy4FWhl z9mjaunKFNix#v1hwH5T~Wh0!At)UN~k?fJSW$|BMhuKcsvz60jI^Itbp#g(#tN%D6 z2|jOxInR)|g45k>ButU4;kf0Y9y$FTekwIrz?5u^*=7zdFB*a1A7B^A6eya zhAsmnJ{-?MIN3$#Z65)fKU$t!V&(&ZY5Znyh=6=WyjUmf*qkGD$JKSohHH)uqpCRk z$f$jll|N5eB!{u#wd57y4S{o%+!K%)@pab}iE^|3MkvQCrPKPKz7~VDra*rhiA@@L z{qMUvQxu8Slof7r1oF0F!DhF^G?>4}ahR^_INLLqfdSIBn=e<&TTaEes<7w)u`nSo zg$+BJ{P-bnn^CKt{yqr+QVmZoHO0>vr%|6p2R}0?wsx^zTsfDvy*EGb@(ghz&P+Jt zr;F75U-5FK@q<>B$$dCtSK1KW4Yk}^fvZ?*Y_fh&m64kMqHGk-juc69YAIo%5NEjV@o)N89+kB!{%XBa~+vP3$^m3_KJ7P3i^WU_&&s;P* zOEkDg%lt20w9Edd9za^i=V>E3(6+60mC5ykkl&*pZr z4ws&ag3Lb%b(cLy_;he9iHQl!k|gYx(TmR`^3PirG6(QK>ImX4^aD-{{AfF}5NH3z8r)0Zd#j+<4DI3kq7ZVdxoFpQc30kPYaxdDHu_^j4$hSY;H{lgM zo-rzErqiE%PHD!)2G9w9JNORTp=Z%M0WTw5fmRZ%G z?eD`f(~;h_NBUn&Azx2ghAX``9!4y7YvsYHZFFLnC}!=OmcSF&gQ>Yize`CnD=YNuzj>p787#N?zU%7(kbrY0_eZ(M zMzHbQTMIYSlVbSH%LhwTgDji^$2-*ssz$qB`3=Up{-jJIt*m4!HhuvMIUbQm3}{@S zmMv!orK9R#ISArtKj-!(Z`WUMCWbWMy`SRd3e_>yQmCdZ-BWZKT-RUdcqf(JuCkM| zG>(C)p_BxNV<0*dWCintEJu-3N@ng4L6ls49ff>Af``WXEV32Dy}0KMFAO z?lwm01t(2QfTQ^7*OBsde&nROPORVY{G?`2!Yg|8bsfvQZ^q0zK_K)!R%MQi?k0u1{`maU z?|WF?_0iH4sqAs=qCzKXHLs0mLNxL#(s8~DM0b*LE^mbWKg&S>&k z&TvkPQ}swt1N^@l+*h{5@zA0|N9Syh7i3kZunr-+AbtKHXm&_kK%+Js5}4Hfifve| z7xM$(&Cz<#dhD@f^xr(MbyC?;7q;KeO>t78U$iK%Y)>*0* z!B@we{Cip^r|FaH<_3-VnD4@wHiIUoCZ0#XI~9S5)#IJ!i%kc|$Yq{VNgCr+`vMSZ zF>JM|&3t-o%IN5pEqd-#gH3AnQL;EoljBk1zxXyHh7@4_?q%n}GnL{Xhz2+@nmSVJ z;oVgV6nAX=bpTxoO{!I*Yu}GhCxvh0*E}MjQ~(C}Cl)~fsM7_2DD;K(_9CcC>G(tt z^!xaqvX7EPOmOz|-FlPYD#=D{M;6m=ycyzN-l$!fm~GHUt?R|ba>OX;Q0+mZu@!%2ktN$hQ}NJnKnLFGNVDP*eT#Jhm>6MoCp;&pE10YITy+w1m>}EDvcN z>pJ$J<1A1UBXn_oqR9#|!0iq6A#1J~&78W6$X_$wHOMa(NS2UBgA13Uf$-| z68C=-%neumC@G%NJ0F{Tt9E*VO^H}}AX7H05@ES1hxQ_?KS992sZ3cgy3^Zj>xyUj zlKu;F=59lwsl{?o{2&^Mg2#Ogz3;TZ2=T|<^@)o0rm{zv zDZ?-t&89`aa+k|V z+B8B{#5)NmRHM~cdF;l}xhGbWR*if+H+fv>KT!J6G*%p)G|ICcE=`hxbJr&5|ES=z z{d;fCHS)RTq|Mpy7FQ`+q>z0wK)%7`?<(SPwB+!Fm=Kfdt7`vnWKG1M)!)`|$j=Te zaSlaZdsU1KFum32mRL0$tXz-T$Ztav#_P@i=73s4=X7!Jy z>+4^LPm#7^9D%UMV>k%Id1sveMD-b?6P_O++aFhVZ4qx6zFDi$hrfZ0YPq0dx?Ayn z#M8Zpd~W!QrS=mD%-~R>Ua|Ej?zg%*J7>ao7^)D9L*~Bkzw6ofNPay)^(}i$Pj^xb z?J|(EqJqD&Ea|FZ_iIGf3q2A)TMa}Wz9m@I6snlsWX`b4y$B%nrCK?$R!FoYTM^B_ z&_A4aG!zY~Pd^-o0*%LyMrg)P*c0AuBFU0m_!;+qlcnF|#D#Vc35dV_nZpKp-61!G zQ?0HUm}Az94k>1Od()U3$S|{tC+t=HFWh9Ckf0tI|%6z5ufddn2IurBp$ zwJJo5F1yeyMhTlf**p~NJ@;Gz3!tL^64*(+Lr%Z?C;V>J#}Bs`MU@P$=CJPnxYS`4 z-{_e#^fIlbYbfa4uvEkuN5uMu*FWkxC^h%RAhIm^E%BOFh2%LZbNwqv`8@H>^4F$a z>qgs-VGkO|JrR8)d;K-{kAOGH*_iZSu1af=!W;`kN$9om@)rr?T)A^X==Zpkk;*I%{^Ej-YG$Z@KXuXt*QPO`AS-4AU7=+JAJhPmV!!a*lu_87qetU6xii zg}R~ver8Cg^p~2i+i0NEv@L*^r^E`i-+%94D8C<$Q}MO49D8AuZ8#DhP+) z)0F{Gm8;KPQ75J$085T0UizMqi%7WfD-TCGcN*Q#UEBnhTW1Bf>K*7(*aJr7gXI zhtl}|JVafR{^K&Zm%;*;fM~EhoZbW^qu{^pR)PZUTwpzN*zWto-V1o6q39w(q_>CI z=JiD_m)BxW|BBIs8`*mSRcbZMs*vGWf(b8u^mJOG%kWqDYos1BQt3~*rd7DET?2%b zHL*7qrbv_qJunR~)LugnzaXzJJc>@oF0@S)U|`;_dWZ0yE4Uj(c_Jxw#>xw#qA!n| z!iJckqT7Dl5(9x%_#5W2xn3p-jlLm$mG_pq_Cq_yNc!6aFPg#{j)pg~aeVrZiWWZI z_ook?!n7FKS6uUlk&xdGe1X99NrdQ@^^N(dgRH zq~xyeZVL+k23y{^NhT=1-CUwp-X*nPOAO?xF6dImLG7O!(MPUrJsR75znp|;={|H4 z?0axJE~%efL|lFFNyjFoKVqy;?!iKXYO+h@b={}k>IZ8W39@-k65-n`;yg4XjI(pTz>o8#848UW>ALhS{Mvrg4cH~9Os zg)e)zQL1%!e$yz_Vv+{RbEa-MwEKzo-8~Bnv)Sf_eZ8_ zOz_*uOThzzk1|N%!|6KbJ{Ucof{SuD=(ZUAXXz9zXeUK?4XtxAQ@#HjExTT8UMMUZ zj~5L_QK(DP-z>b(2j=X269xElC7qkdvlmw%-4?MzVN+52DbQ2iQ;+7ID}qAIi=S#a zT7Z0g$^(k-ecmqg-@x&Xb&^ZAnYzUuc$aFed4OM{n(~08gnfd!OVu1*8t70ig({zR z72)kd&gumN9#T?=2&7x>0V@B(GQ(w0f+M%vSu5a7{v!wOG5EWOtP|ejk2X(<%(k9v zswh3`+xRJglA5W)mpKF%Wpj zn6k(&TnmX#%pH+*7mqkxfB@WIsMHlmoXUbaett0|xd9SPkU7f|rYuXAMP{jF(evHl zP17HB+NhLWf51-DP^c_@x{_>L`)v&{P_P8ti|Li`sADRu_&&{Gslwn%|ItTfns`-a zd6tf$KV&zL7K_kCdr@v(I9Fr)#p^E{S8wF!pJH7%coT;QUq#cpI}UPBe}HoDszY*+Nd%bE)|{{xs5=0v zIYDsR`?oTQ*2Uk>J3TxoI&nJ_sA^IBlf|jL=&nS(Z6=KoOm`wF;hEkAIny?qY>Sn# zSz+3A#c1gM|GYn7g%}RvUO%Y_T|MZ1roLvyA>I7tYo$NZUjo%4p<4=%!!uq)Zkz15 z?QfE_J-}m%UjI5WV4$?{&hSqSj~5V>D!$n0v~pF|(ht=T-57e}<|aQR9QAGP-%d(h z7;(${&F8to>Rb3F`76f77Gmk`i_YO~2mhuxfTQM8HUdmJUI+ zV`~rzu>EyI`9GyUGCHK-Z#|aRkqfnwFH+t&@`qgA;{Y{VfdU#2S1|tpKk?AV(+?JL z4w3xdZK%H~;dEyfK(V3}07Y&ABgP%|?i&Z0^lq(q{x>~oz%MBhTDVdbKjfsfNHd1J%2orik zvLP~MDfHqkEtSe^QQ}$OA7O3XWmLcoAc#2YrgY~~*Rum?Oy&=z z>Nf988q+;qp;#Dsd#;T00qQQ?MYqpOJx9=b#%5pnv6iFdG#t31G5&B2eZ%mUqhH#Jg|;8 zgG2Jthm~rlwq;#se6(`+xMSn=R;sY_(CyfM1IsDevE|e7gI5ZCOLsPLQD+JRZa9WA zu}7%hI5ub9%-3Bb^d+lVhcqPo4r6S0mOlIlfWEs<5nxD{{4V(z{K+hlJopapP*-qd z7W{39Hm{tzDD@Ig4PSTiOY1WMXEJ%u&R#zg^7ggQ1_I~#9L{1Md$*Qx8k31FR@zC7 zwG839PhICWhUaU%l^TAsGK&3Z^=(R7kGV^;R@4oO)3OsF)Jc-JT)y}CRJWHEplwOv zustotJH2@E7bxc1q7=6Cxv3MVkm|hvcqrF=@$wniFWuo~!I_H=Q|4hu9xrWzCf<^J}(gHS($JixGb zDWH8j^kb8TF_Q**+!{?f-Tn3c;PVCHz^`lAH*Adl?T8y`gZXhB|9=>|E$HDl@)cSb zqpuQD%v{7fmdFdG#OmTh`Nyf}qzZ!_rtCR*D3D&NCqoYYrTEGN z48{@7j!*g8GiB!_)@A|8s*;@d{>KwmIrDxLC*Y%wEx#hb^>4>&5PfiNcpsE>vvv$E z;S)LL{ZrfSFUoWDYcWdh^((g*g_A4iq1Wtb!!s!f@4BZ525y=SfgEQ87*PdUS%KAS z4@l>~x65T9%#Fg47~o*ffJtqiEfc$@?zm$Uo9%8f#9i0(_E(H-375W*g5`InMcj34 zX5{r>=y<;zI1;6Q^_S|1&Y!FgCBTa5Fclyf;>X;5v!5LYV@s(wj-N!`qX8ecrcI@d zW_^oO1~+j}b=uR!5OjEq)}?(K!dzfx{wGUw`1U-Kp9$C2ajhrb2M4dk>J#~=XcxzS zA}3Ge7DP0Ft^5L)&~Z^SxC{JIg=TfolgBc?pbyACwCJNc!3_IWn}p$?-dSXGPq5U{UANtHxgn@3MU3++hJtLG&|^yDQqb+=`*A%~Y%R{BIn7KUX&(PFzi0 z6p8eA%_;|xi+T|;KtC&LForw&#%s$_smLI_!7&^uyv`W2{4u(85)@?Ua-a<{|Nh~B zh9HZ?Vt_Lq)>yFiPE9=JxWj~HW^hyz=3&=VbpPe%pJUpew$t`DpP(A3Ca_Lf(UuSQ z6*&)t+c_VrwjSQuI@#{1oqN?1|Lxf0RtMbaj_@u!qjt{a?nKk24W{AUXhWh!_{1F0xy4t~ge?f7GquYcqDqet!M!jZcQnJ)RDb z5Yn7fjp6KC)J*N0smhI+2m5uIM)k7^L$OsUSy zX(QA2sea?$TKh9eiam+Qk@+<)hyL(}w zixg6631k**zL#2`wFi8R@8oRs)z%-xJ`1F#I6#PJ;q@mPWzz>j(INeV1Y1bBMM-%Jf(+VF_ z<>H&+pj+o8`*~Ew-e|s)bpv)+QoiBu!tNs={=KaE18(?AK0nU#zC{`~n~BW3R&tn; z-nl(UXK#GYqjuBNp5d`G2hJng9fv;elp6gY$5VDYc%3o4e~_M=@3WYf`H)ZG zC)N-+R{)ibBYL6f%>`Gwp&T{tD;TW&@Sn8t#<5H^Q_YdR*DA*4@W9)wQ&vhXvS99{ zo&UJH52|v_+tWOI+20X68_fPBK!5W3+rb_U?pdsi&hJRz+fy0@`?vcSQ?6uV_g+7v@A zg93aP4*L$kmiq3tq6r6b*c0+>v29gC%B)VZrHnG9(noSln;JMv8#hOQK&dGPiKb3; z;C`HM`FoAqOY4*M)e;r_tE7ctG)_aSP6&4LE=)wn9`gcW(M67JZR_~1&=;5Jc_A;>$G z)nLE|2_#4TDK+Msn4x!ZA;_aB9u%H>(|AM=V+fmAxrg`lJPqb+vtJJ@e{k(=B{B+{JXtLdd_nO1B+X@z&c}%^c z$or~43L`?p_7HCoYO^-lKMthceT_ay=iS1m9WM7F_9J5nPd!xX`OKm)S#LT&%}R_@ z!pt$`4KR~EEfvgm$MTBzSd5t@Tu>LEJAD%5<{sWg>=SvU#sdQs+s47JYUI0{WD@5B zrbJli`i%8tCC)*F_cx6jjnwC$)~Gwq={|E-dxD2O866mp4`NVDOSTe(o_M&+EMpGx zQxtN;q*ro4_I8$!9{=sSsxuwV(Up!(@?7#sr5<5TI4UDX5IUq_md-CBM~^5ZXN^V# z-jzyo7_E?<{R~+lhZ-Qd4Hr7uD1oB!lWMfRdD||Tyv6J81F`bENG9A>nzlk3u|F~> zl)8{ZLp`eTm-j6Vc2*v_*NTPm3nCx4R$H7#q$BZ_XlANuG`^Y-XQ!cGk~q{T>|DTrUB#DCZk>m*`QCK! zw-NW2ChcrK+qs%zf-^%h8%7F&nJ8m5aakIc;G*=bt6##8CX;LxI$Aavvz zi`nen&)brBf3MTkrH-kt#;>whoalcJM$P%QY%0@Hc&g)bbdp~gr!YTNq!D< zjm{OH+P0Jo@|F_wY7TZBl!qr!t|-z~%*i20k%zhOkB+Sgff-{O$L3pXe-M!ggEZ@h z&b@?91n>bM9XA|AUr=ywq>&G9L%%8capxwZqw`J)wYNio889o_H6ZTDxODGBBn&4A zDrd!2p~LAnfZndk1_-y@%?EVPQjYix>1=m=qGZelU8u3WiUdK_Zi#M=8p>Qv{8w8v zuLaM((x<>Aj2XK1g$oSLtzHtmLZr zy42-oYPDUzdpvN88}K^_ubmVSpjmiyxn&~lRJ)0XsUWn~g1KYb{)axStUoExlzgKY z>9(iwDIZW)TLpOlZj#~;Y3h#;CgiTssj+w}UfZV3Sh^gffXR`{(fP zEE}BEgZBQXBQGn z25_(@cx)wHj{*^_icKe{02*4)`s{QU1cy|7*l-ipJ`Tn!+FUghi5yiWU0{Na9Z&j8yiP0H&uiBVCSIKA6qdgG zdt|M&$AklXV!L_YKORv)`PiAG2Y?tNX-@br&6kzh!8h;S{b+q*0D^0*^2*AekrQ zSIo5ZKMX!39~o!$lUlyy7OE>}TpqswpfZbP2=o#6b%OA2rPju(_1L=Y@6KHwod!Vd zh%h#RQj$NFgESVKM74{mN*R$-1G?6sE@gF)9aIalUQRm{SPcx6H}}SVTTJh~?>c1G zeBOGQDeFYSlp)X)8qNSFW=ZYzKf2vC64xwv$|__ZL}I)z7cG-FV#8mAf?5wE{=p)G z!`;}NRQQk_lU&7KWpQ^kq_bKl2;5C0{e1D)4=LMyo4 zu^EglnFF9UPro@0Cw~G-_nc3Grd)g7U5zny*?!#2*|s z98zUTKUtR41z)Ma%zFuRJ0X%N(?~`#gj>*Rc7*!Pfm0z4uuF3~ApsK<_U6Fe1h>F}t(OQ9Frq znW*^%XKrnv>a@ih4WL^9gGwl&sO*`AVYD}-yg#W^z+e+*bf@Pn1)GWD7af12IyaNt zDJx{!gqzhY%&Oza2T7vM*-BfHr=K^(C0c7XUCqO^e#eReN;M)AnTHqGvO00+*P+yG zp3BH+i24kV3XJVEJ7|aAF@62+VvEOqoXax{{mut&#!og_L5alOfs!IUWDv5iFwuNC zXsd^5)Q800rbKrL@4>UR-G_AFa=9khL#rf`MwBBo7KOD#qjgQBj8B(?8VIIjpYLbu zGRZi5n!gJ)Wk1f`M&wa~9lZ$z*`~g6tO`5d(}IWN2%g5-y0BkSVL$=tnYpplEq7I( zbk3X=kY{LBiEOMAxw;uh-AJT?_dKK2>Bqxpb8Iz1P;;6j$LwXxX8ni;(E4;ChCqH3 zAGnXF(c~oP({7^FR#E&z?e|2rU!llbb{JpeIl9yl_1Eq8l*Q=&yZ4Z$L+1;??VlAY z87$WaI|N#?6Oa9y3jL_Zu3COO1UeryGSAc=Zj`^_9aU)@^KKbHojU-|a_z{Vn8?VO zeo1va1u?e>3579#+DNAoio-k&N#iWBs-mL qDg9sN=HH#z{#BLC#SSaK^(6yK7}fPXCbA#ba)cebovUzxN&f-llCZ4+ diff --git a/docs/img/gsg/DirWithNextorDat.png b/docs/img/gsg/DirWithNextorDat.png index 14bf31a7f91af6844b53b39a1f0a1ef5286012d2..c536e95a5991a514a79c9f0c90a781ab47dca685 100644 GIT binary patch literal 19864 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 literal 6359 zcmb7JdpML^+jnLh8jZ89%+$;zMh-J_$f+61I7CN8$`A$-%3+9zVPt2TVH(Gb!;Vek ztP~M5Win0^QAyY}QOdc9^gVt1{jT?Y|M;%=`~G;Ywbpa3XRUSr*6;q^_gW9d?Z{yT zSxs3H5fKHvgWWL^5m9-d{zXO%s9_+*;Xp$)>eykd2)kcv7HCKW9&|Y7TN`2>-Rp6f$$ICij5lMLogH4I}dqQBIGS!ApaWBZH=WR6(_$wh)FlA zd-5=TOY4nQI?J?4vRma4Z{qN>Sc$&+ncsg}i3e*!lv2I@;x2yC0P*}=v_aG~X_>pZ zpAU=Kg|EYq(!UQptE)4oFAr=4`E*=7-fdI;DJCmnTEo?CVC;9&o{gz_iIgGggrkE? zsApskgd~*PTya$^N4Ch5UyUeEl;8bSI7WZCb6wHq$Me++`3auT=IArmc~B1gL?{tk z<{@U%=b8AUu+jr59GtT0t)1tYE4!p0m9@BCZsMNFsiLS z=()A+y3Lu}q*l=7>2GBdyu{7rBT!ApKnH=bj$HEzs2o_Q_u$`F1&$d%=R82gOJT80 z4x{1Go;zljl^mS&%Bqu zX2qhw^}94Q`@oOU($q9u;!5E{x8ZEo&6vQeHI^K^+4s`F$3*r#!xh4E-h;Hrs3C6( zp1x|uLfuXsB{XkR$>_})a~SVVslKLoN_{Hg#~J6(pxpG2Q97j0?1=A0gLU=;f-a`* z3cq&Y(+3GR#yrnv9{%VHGt>#NA(&BsHrvy&eB@CEz__FTy^YG*N4*+$G$UUBqquni zwAE(pN$^WQO69Dg(C%Cf z*<=L$4_07Y2Jg9iV*72<-u;$w`cEN#(D}=|m+1!#tq~t#df;D#@F*Qg70+pz0olEE zaub61r<^Z<R-QfpH=gx2L}>&Qc2=;r%Rb7pYkKW{ z(kOe&M>Ui#ev@U;m(zqufaa$Uh5Tt*KWsnyE~DF{N3~pBQ7MJ0#})n5(4_j}53^0hMz5}00*vm3?S1tS zM|$y)09&H3BHh%R8x%y?!T>fTm|zSRgpFUPIBIIvP`05nO|=~H;OcpF_NRfyM+o`7 za0!q<$kC||@(in=MB^IlV|Ma`D-QJD*pjKQF)>MqXd_CgAqj!KM(XoiG{Ntd=t%KCUYLwjMd z7l;J?k0(NUCPxp1OLyn~@zUZ_EIG6Jl9i;vtcEPBWtiHmia#BwaT}6fJeGN@lERW* z-y5r5YnZ?LU`8|V;yK!LFNgvcugTC9*yazE-5T6;$mtA)@dBHo7{Xc7 z`7HGQF&&(b6M~%7&wOA_YW$f@HB6t}~I0JhZ!*eSUOeSR@K_E z1!2&U18x{OV08~cO}keTLr(SxF7?G4XGsL-gB#YkDipMHDPDb>7A7!YpG1Ul$Nu?= z{&P-qBewbD_H9wlkZCx5Y?opdg7Zwx>>k2g-8!CEwGKnaTt}nb+nqi`g= zg=wecD_4y$l!a8@GQ9VW_(w~5Ed4;oeG(=-Me!JpdG5ynf3L{Vz=)65^zJ)f*3T4f zox$P&u*6*fkL*)iIjz`^3^o&SEqimt?At^5qhz61gJFLVYn#`Fj!sQ=c${WLqDfHFvPiF7& ziuiKBFKYc$L;qb->+d60pH4>kdx?3RjG<^oi{|Ws3*CzOoz+3R?wmG?%lIwvmhv~_ z4eoh-*HX4%Db41ILWfhVS? z5(Qwqc5sapl;Zpqctb)f< zU`8+LQC_s=o8S29#iZ|5Q@2{bb90+^MVKK2r`{VT=|9 z2u$dzIDgyHhRJ^4cmJkU(ub8WfsO0RpzecCDi#3c(iG%M~-#k%})uVZbz*5lZy zOyNleCs_tV%!l8-;$ef>=xDDUyV^6WKilrw7mvPa2CAYMW(Pp{xZvn>(N1$Jd%{az zHYf`GAwDJ;6iA|MJ&eD#ul}7m)Z~?*fyb9m9-iyGx3zETc^S-TT{gg#x9}N(M&IQq zB0b{Ci8ATL=yN}El)->EZswJa>F%Rlz%O~C?*O&P)zJeLcc*1PwAk5@Vl(3+ZUVFs zZ_>G-;%@eXo922u-j;=8H?BQQjkm2o>Fxhx^gs#9fYJH@!TtQdG56njeE0(XsC*^v zn6mgssxtSg1>D}KWZQpw#l@BW-1x1H7cz{wgILX_#Mv!DR0gz+oD;dS`blTDiNRFf>*5Z3zbMKat6pqxt&!Wuup+issIk z(7Ovlr7BUb3C{Vps=5{;;zY=h)47g-&?}Y7jaSR-p865>I z5uM(I(WcAT4UC+V=@zsJdXp&C>8TULg_NBL&M_~{O1@UZprb=~hJqXFB>~H=yEVvk zch-y~^H^}B!4ym?)36CbsASe`{D#^|D_uL_Z2=#+68G-jh3I7`<)U($1S^+{TyZ&~ zV6eckk^}I&uQwm=x=f)P;GULdgXG(VlNwwbtzljd^f`}TVA zrc2Q8%uYA{WuU7pju`eRWBjWr$jJ$Mfi-MGFz0CLd09QTdl=C$YV~RN+##IJ?HSq9 zY`qzTefBCYQp7VZ1L3v(QUN;Wy|hg8d7s{$g+`ucHrG-g;iH%h-tC#KY>RHeDRsxF zW&3vm7>}5^lJnj?=e_-+82A@*3jdL=_b)m0Z;e{@U`y}%*XZ~J{Gd*LSetW2`@?2{ zQ9M<_lr7tVSjkMpDHo3?bvizO32_7*a<*tXJ$8t-)JS z*T=5r#)Uo7nfUNBDQr96Ha{dI7vQL&{o;02F#hP~j<5sp?^kXoe8Z_uaB~lQ81-pw zjQnaHV|DL-*X#6m(D}qnH6N9o5g!lUAzx3A{YrHUg=P6DSe{Y<8&SqYEIEc5UN1Wq4%rP^l9V21 z@_;i6%}1pd`6?wFUv6GT2&?|+@Th3s3?8H~#4C1Z;_}rQW&RHI610^zg>H0|AcjfL z#>4wpX!o}uF*|AE8&@lR#h!cnLUUYn7_UlAq3Ud@^8k&>nJqMpom>_o9RApT`p%GN-@YUk1nM2pOo0y)H+L5~eo{s@9ajTP~5iUB}U)*-kqxv~&_F z8(@kCNk}ET85~8RX#7C)9g1`=%Sl&**oZIG=Aea5qrL>}%3~JY4^rZr+yi#AhwV>dH zYrgN|8Nfd(;pImw;l4rdVT@3F+P?EF203~eZ-_oV$1m!@M_+4b(>b!(n_jLH#`-@= zW!kn0jCmO=H=T;Y{VkOnoI4>{1U?nGC-C4r$RSJR!d)(Pax4jF9J}K^ZQu!>hA2RR ztdSv{4L*Ecd=;Yk9Z=9LB#6pzspaG`G09D#BymB*?EL%3xX8g!qQ({H7a60$Vzs=( z83wzNoYRVJkF`q8Q`0>a4K9ST&_a=(s*Q1#EAY7~- zQ9h$M&fqA(D`1|)k(Y4*SCS0CJ0UJYE2Vssm8Hh5^V4N{aQ$URW54ru(j*@W+GuwB z!$5j*$E|#3R~9o;~%iJuTt(i!p$6 z&q*9dHIFz4SaRFc4uz5lRr=r4OW1Ja4f`4=Vvrji!lL<0JzH`p%xewKTg7$VlI%W4 zXC;4l6*}ah(f(Lf-pPe;nLeStMWTriU#>V7QUF$S{K@OpC6=wXe%nG)K%1Mg%uYih zaDPU1?RvVpW4e(V#P(5g^pbjDfdd=OCuA|=sOBpnD+e*`Q^3;_OtNG9nswF(0B-~-#|YblpK zgW1-M?K@`TDsE{zw@msO$=Hh)>I^F4{q%9;^rLk=uX!pwtOnzF2sy$g}*49Z*WN2fDdyR-!UwDsyGp5-W;gc#U+ z;Z1)~O`h2YD-2i?+3%k#-7Bn$Rcz^v%%n!r8Y*zSJ5 zcQb#a0}pk{32^G2x!f)jF6M{5{w7?sG>~n(;%!0{19tkRPt4Yz#imfXg9aV_*V66i zaRaFV8so{|SoqB?e%q3n(yv^Ea;Czx3Q&c@#Y2Jz{UbPRcyPa6Hslx08r|~cf4JLv zvfc0mCh8s2w}I+M=3#GWAYCraMgJWNzF5L@aup#>{KHFOO3#)u`ZxlbiH;tNXNO}L z3Jc_=Gc|x{@j!b4kBw3zb#Dr1fW;r27pVoA6?CFmv&qR*9!BqO0`@0Gl_s{ERQ3@x~IsW7LJ6c^7UzVtfg@Z2&HLf0Gsbpo4M;xc*zqZ SCxD+3B6#~Fc5Ljql>Y+X&d(13 diff --git a/docs/img/gsg/DriversOneController.png b/docs/img/gsg/DriversOneController.png index 951e50509864675217889d1cc7dd0d6caeca0e49..d2f08c669a2e2e0a773328e5e11c1f0e97d192f5 100644 GIT binary patch literal 7371 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 Uchfs0e+0mJM^}diyQ^vc1IXA9^Z)<= diff --git a/docs/img/gsg/DriversOneDrive.png b/docs/img/gsg/DriversOneDrive.png index f3ccd2307e412fab22442d3f5829eb390d69fb5f..736c06156c8da3aad54db913a2e4b5f10880bf1e 100644 GIT binary patch literal 9506 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 diff --git a/docs/img/gsg/DriversTwoDrives.png b/docs/img/gsg/DriversTwoDrives.png index 922fe2220c9cb4783065f34a4c0b93def4d977ea..a88c08935c4e483c1cc9b91b2b48debe658d78d1 100644 GIT binary patch literal 10215 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 literal 4527 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 diff --git a/docs/img/gsg/DrvinfoInBasic.png b/docs/img/gsg/DrvinfoInBasic.png index 6a270735133189bf4ee4eb836ba4127981467557..acebe30c0549c24e6909c60a5798f34d6859feee 100644 GIT binary patch literal 12110 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 literal 5464 zcma)A2{e>#`?qBY*`hJLmWD|oG^3K;XtIV-t^4-*w;TNwz+JPH;bXKN}mH zps9)R1>o7j#>Rexmjk$SMrnru26pU)b4F}sz0$M5fXmy^(vXdQsM);lmb>XO2U7k08oUrk zs$%_^c$*riCvJChx~cw$_{Nzc#o4L$rVS?lyaztN_WOj(&@IiR4;XOYSp=2O-30q# zUhRZ7)eECC{;c+~#DFh4YyqctTINQNv{9Upr(#uskuQK zto&%_#|vRMT_YeSmO@P;;RqFazj9aFVSmPry^kgkOS$fh{u@?;(fP8cnCBFE<>_hb zX>x+{q>M4wKR2{iexyCjr8SYq@SblLB-u?euZ8O~mJ`w^kt?!G6UZnBi}v|^M%WJW zd%c|ddDLh)MKV~eeqt|(1}ED)^6x|*2BwUhYIzFv^h8?9L{l~$RwL)r%2pbr0w(Y3 zWd6ZJN{7PoMg;1x%xJ-d?)Pqe4m-KMh$(`rueeE{c4t(1K)8 z{?_nki73cgBduR>g5ESq=up$xb>x}FUEH~&75hgVw6jGB7M8DPfjUo$$^W=yVO5at zbGt+LqOLU(xF+IPbxnm@L+(^<3yp|h%Js(-xZJ{gN&Fe(hr3d%Cla&-R5nBV_ z)`~6p_TIYZNIcvWYAkF-K1Y@kHu4=hOo5@D3}HH{WLK>;%8Jf&Oa!u zf5P)7a-DPS02phMd9mlpyXytH%6umgqyhzv$QczckVC-fH>T#=@tTN z_Roup6*Jy?nnvb%R8<(i!kzT7lHa(`<%fgod&3Cj1_U4DWP^m&L=6fO0gkq=;` zzxAF81Pc`r#WOo=qDhnS1{MpbRfBXz^;M19&R?0X8At-jsy<#myawrxTqg=JCs+O+ zQNF=ng=(LWnTa1Dg!m%0G%0yxn_dhO7N>NTlXhixDk8YU+wwl7(@5A!BiEgEhn1hp zuNJZv5x^3ekm+nuo^QNovq;ICj74{Wzw0Gv3pt8(w(M&^r4@1eOCverWqB=+fhD3e z56wEpi^NW>Y8egr#}9%1^*|9qHS%M%JwJL=7lFT5$2d>E(k4EM2tQ9(dhC^T5%xxs zj#;`*&=SMfGP|kRkN1V{NIDo5RCNi!?y8Kg@1L9Qbi8~rIa-dNTD}ojFn&(!BCKxW z)=Fy5ea5{GTiBZ?8#cY~BpW}+q%3dkGxjxggO&wMS*f_CidCRRd9Gd+NyVAm)-8L2J7ca# z!IZ~iIH=E9(XVyC^LCleeln#ZK+5*R(iPn!mv>Ua-Sr9WV)+*AXhdt_LbOS1#AbzofZ8=YDg?M=zuNZxmp0c3x&iOsTX1%@7 zh(9nxZw1p!*rvUz=ioofF4pcz8%l6YUX49Xi8%R+O)!RfHr;?MoF$=`%OI39;dY2N zQRssEa-T7D28b~MZ1XF2%M^+9;`r8JU&&&%{TY=T zB`YXkQ%F!25Yx1Jqz%#0Z9-HjD9OXFUebs=(M6cC@wh}$M0ZVYp_j47tw1{IEVj>) zu_vk)A(5rNyv51nny1%JP$b0*{_23gbKvh9)rKhHNXFdJUdM?RF3-bPBzJqYwnhj_ zBziUmf61LgQ$XMlZ(A12P)$a_2znw8G<=F znhYh`*s2WQWL&YM^O<)a>g;1+Yjy($L39i&m$hL4zg1(Hd@X1?C-)h2Q3qf}lt_Ko zr+myXxAKwPTHoc~E<#W9+toS~JXF{mXYW&8tcWO8-;XGT3yZQytDSL!kq{F6Mf(Lr z6rRs0;Exn%WqH!b1*%`sU8yc@sfRBWa0gGx*;0X7aQ`(kAb1t`(6rSMNSy3zxEOBL zQI!8)G@E1HQ--L=6HM7Nvez(V&p9D}CWBI)j+2YW9JtEa@~BYQF;y8$;%pUVmYXiu zUzR3ZALNF~RGS0|VL>KXx2Z$5-=)`HDg0w#>Xpdz?N7^Arf7>aH}gvCk@P;^zNgSK zc!yc3LXW#`=ksl@M_$JA6_;KXqDvIr4{-V%DBU@{xm~hZ%3Iq468O^(K)QT66@Zb^ zCq?SFFt;<%*gU+cb?l#;?!UEKBrK})L9Od!ZHPcgd#JiLgna12w34?k(%#klJ|%B~ za3ItmNaj5TxexTS%#hTS{-1jIn51~oe<9K@^RbiG9VJ5se^5L)!w4yY0~-IqP#!{9 z-6Iw}Ryjp2QF$o}RuIsvC929AI|LR<1!`-uA~{Jmh-n(<|>gl)|Kc#vsl8Sz*%>+c@n6+N&D&x`Nc5VwtN&9CjgpfqQ?_e zFkUs$@*`v+2&zslfWwJ0Omy>_pq1N)k4TMp_u)imkeH)!X8xkc#yx)_YX`k04Id5% zQ10+b*t#?&w}{V4U4_SV)zPu6piL0208I(+(1T`p9cb&n!&CV!00`Q}MuTx&ut*ip zhp;^SBHp7*LhKl>F|obDgBjc~om(nRd8q!L$cSw^Jn`XV{e(F_fWi&9W*Pe3aCx^P z>o#~!O$Ks(GP}=(vY8AcvitbxK_yO_o`S~@#K^=P*T3%-|13^QBt;QnIe<-aH#fJe zxlqS$Bx-1W%2@w=)RH3z%24hMODY`v3j=$Zl&->YnZ&P0aVzs$NOCi9dL7`xbu}Z% zC4<2?0xmi*KL|693z)C$4{_F9yw)k2Md!kB1To)(T~8y^p*YrRI`pfibpHq3mHI{n z(GB(ZPl9ys9SaUBGiDxjEk!p@s-l{UDPiUeAt8DyD&N5@$J}3A?QS69Oc4w2A((U!#*m!g6(iE^)I+>QxX5W z!EFj;qw$iKGi=}xs0cR!`G&~W>nSw~d2U8H#7KSi%lml(wq4sn$VO3%r>wXutr-iE z)3<6v2|fLO92y#86}l?-k{@0RA~Hv!>7HVNH#7>*!e=*St~Pb8 zvt>_l%4W*=+?B%QH}^KB{gSx-N%upzDY;}9^KS9#ns^+|n6WU_QFJRzUiIGYT&Xm~ zSNLftQ4-N+Tn|rwAqN%EOdjG+QFO8>0j-OIS5p20(WI4H_2cBR{hmK%HBH2}z67Z3 zQY0F2Z6Ai>2$+Cl%caym1Sj2rnEI^|)=^?GfLG zqA^+x$Z*|mOjJ%zdG{qTeuuASr799b;RI_i`BWp0Gt{YpMoX8nK2hjHYU9w}vq{B_ zuQK3_z)?xDf=z-N$w41EF?j=!>6+t7h9I48+w%@V?muKVge9chtqLKKtu^d~?wh4d zS51Rvt;TfB!CSdSKg9i`r9^grxR=`MXC7?2N$Qh@RhrU;F{dem>yWHJPrclIr?;SHB|lP-P@R$#N$3Wd*R<<8!TF z0_OFR@V4lo7=pb7)ni)Yq1rgIF)c+9&@rc(7_2SYUI%%$a5R!oaP@@S^&>f>aqBPI z1U6o!ed+VxeSEqJD>J%sTe~Umew>t{g|P3ig#a(o4g_V%cgy2?o+rXpB!Ci}+4up= zSws#c4U~6>%saH?e7U~m5&x_MUji>$R7?r~tjSIu{hYdQy&=s*G*-=KC<$&uR#m0` z@QD8zC-sNfhI(>vLYYYSQPPNSR8~5!jU%3F zF~K!1>g3Mm$tQp~D~^EjK5w`e(7}szdO|csdsz|Z2HT%`aKInm0x~-R6^@}fIy%l} z&c{fdg%ihVWge9apfRck$fm6_R~_iZiQ@yKZ~x)5`2pWvF0F_lv)4VIj$U2wnY`L} zy5cxZTG@%j1{KC8sDenGd+e8Qixl(e7OGT>GOZc!-F|fq;SFQk3V$g0ggo!_vsOO* zitlBBBY93te%nhM4P508wQ`pTMsIS|2XbhdTgtJHW=$dM+z+KEA?w&J0`Iwhmwoc&A}aTG^uwyHU==TzZ% zKGe2qfXhRs;<#sW_Cag{Ahf8n;;n`))?#hwv3+H`l*NqyzvmnP?9zg)Nc zgkqvbW98@eO0NFYNl!xkGRa$#4J2OWnRj#wplhS>TA7Fh8jx$D=_r*?r^uA+8g<)o zT^d44K(}`kb<{{DZ)?UA{fJjLlKi!i$HvrWb4yB}5$ZE)T*V>*QUHM_%>(5|8e&vc zDT8Q>QLR_u4YK)sTp!WE(#jopGT)zx=M{0L*e!gQ5lNjTo*Cxa{pG`q&w$lx{Z0nT zHs2W+O)KL6w;ej{oTHd=rt7Ln=f@Di4whF`BHxHkD&WdqlNN#?+ioVa`)> z>LBDWHmsa&&I}vlcYB`S_xt+({`kIL-`^kG?)!e-*LB_3{du3RYfl|6T8jxE5(WT3 z?EE=PM*!GC29IAtc7xw9P{$5|KRfO@TAKrf-+!9|Pj-5ru{#3*B{-1{&t2fT(A{%a z?*YKR;O)Ky93HKRGV_#sQC`qfKs}aSXw$=A zZGo?gpnJ_`Sg#ng1+6Gut~|mrH!Vcfc_OuxPEi{_g%phxNP5dX@#}Dc{C$^_ zEl_+EH6oY8Tdl7VVN)+EA`BN>o$7vx<^46NPogPz)QQh>$uVN*I}HZetULEUxG)%n^vJ?h>XkeTJSwWS7<%DH*YmWLXx_!9ZiJ-jqt_(~?7;9-&f#2} zt%lr$0Pg3lvMxvD)H{wf(^~GwdpU~XEV>}@CKj&|Fq+psS7+dCZ&Jn5990YN$C-qB zdeB_r+YA?_FU3Qa%4Mmo>#0@>E)P9<0~3zOO>Q2w^V(-}ReztIpL7%aYlyG}IO4*( zAn(_#rY$${OJ~>1=A^;m(~vno^byxaC&UqtQY-54{3pNg{w4FuXGOAvd!w2pS;=v> z7rw~d^}8}o6NMR?MKAqvEE)y(ufObu(3maH-DssXulV&y(}K?8ft5352>u7b9HaGVC;6ar{7>@I zM2PhBExwL3?)1xCIKvV7>r)%8l~Jw{D#ZtA+T& zN>*mu3b_(awU&R8%LuUPIf6TeD%U=+{z%Xf*&u`ra|dfWb1g4}eQap0c}!Mv$b~7$ zbAPzdWMsNk=jo*}`~3~Ja<6G>ZdTg0(Jb1Rt6mjtE=(^YpG-q~pFWdZ*@;5_Y?zq# z$`@?d2|ZFJI~fxe3mvPU;VqDuH`)$xzTWdCX$A~=tjW4j(Y=RL2(oO(ZT6R{qpwUJ zdL+Elm2Mdx_tPMRUnr?Hwp(h2v+{5u_1oRnq?xxof$sPgi}~phdeqs){dKO5_ErBO z203WdtMvh`(22h>kz=&d7u6;sk&uNDOL!wgq&$(zz+B$Rsp_vS((fePJ;;R zT+C{X6($rOqezk+B1h;SIxNvU;q{KYDIb#SM&fuai@dUdPt z1RN{bpEAtjt{e=M2hn(NN<$zKCn>EG2rG$grVJ;^r1;cAh@~b5gw>vhCge#u3w|=J z`?j8R!{3t$gw>-8DcWwqO>HgGko|zaMvOvAF3jF7y=~oE(XQvIS}%e2&mKD-Vo(`& z+*+daTZ({pHgl<+7I<)q{5VD-*Yw(V`foIFgz;{JXx>q^u!04D3#N}oq!*guf9d-W z*+K?WXwFV-Ntj09iG;_GCw^xuZWpj6^ep7;M($@~| zS^lzNj3TfixcsR=aU)wREARRpFV~U&-IQXx5cn`N)GxQNQrX#H&}p@Xl{;nuu^ZJb z`!#FOnOWJHA!16luFug_Tk4shWCR-Q^D*X=)0pR=y#`O8@FTp!(r}<2;3%c8d zf*ctiMMU|dQBl0t#PIqGgPtn01c-`pf6Xqqn0)-2}L-` z{_5dt-!~p>eZV}zR4yrZSh{@d_R~BZtph5|}iwZ8Sy)7=;L@qZ~lI*;tZrTaT zj3uS8^5yY{oyCgj5khoZ96hLPAvG{^LO)@`ptvUh-D8cuCAY64MvQ%!NLmxzEq_EVW5My-?>NaO zw-(yTiPR{f363ZF5jPPs{@MxjxIycxwSQ|XLH?%SOPe>pAy6WYG2Yv-6Ij>CjGB6z z44zxZYre zae8t>e?>XL2M?|5kD>Z+<{ zn2ffX8^o6oU-$7&GqqjKA(B9G$M``gK^?97+z1z2%^)Wj*|Go$JB%4=aw?<3S+ z5{WG`_4r&7?a4Gb;KRVT_bsDO<2H=S60%6sM4$Ma$Q&G87=?+;Fr3URcOCFi0L435 zyrFCd_&g5cnNgqh8Jq{l@2{N+OdPytUr$hsrwkX!!k%T3@?E7&789M`AkMa(piN)( zrmPyf3jHD(iJ0VQrJ=VFz(h296=Zd$29w#U*2+4REwhV zjBA3!ldcE6gmOM#MW6|&Z_FzX3Y5Y8V7G+7@n#30FY+%Ws5HDyST(3O48V54cY|Yl z$?+2HJ?KG~28^2}TwT8NR%NMnCgVkdzZtb=2r9Gloktl`6}}2pf9rtit;(vZHcd6ZOX;%QZ& zk70)Y2jhx|5@FQ>4DQj#vCyfrF>g-6%5T}^em5>XyOrTALlmzXQ!euu%71c@6Xr6L3GRLn#%A%!Xh8%-ZsJZ`+^{U>s=Y>me#aZJ;2ng0&#~BK+ ziz>Sl3$TT1vFc};ro|^*JwCoR$15-XF`bhQS9odj7bVT``u-ru%?zcKZ0X6gGmpWP zLQVYHQ{-Nb%n;aE?#kiK1j?j7yfN6TauOZ+dE&?KCykQt(%e1;hD=&eFB=svY_8HK zA2p&^o0hCV;|k1xcshP``V~(HYcws?;Glci)hYQF`-p9tw&!!=hSqFyS-}hbNV5+W z9Cuplo2o7SE$!oOINcBC9gV9x#U8DSW6aQwrrSbE zanv#H+6X5@m{>ZT(w1of(T|orVhi^}E`Amvq&3b~X1W{v{f52tJr~1_o27Q$D+QC0 zcT)m=>5pazOfNvHV$L{74lp}^*j7#-j0@?%-Ii1xB+WnGo4-h16{{Ij8t(HV?1iWY zD0sydXl=LDk^%WPWzP=3+IjzxlJ~iRl5HP&dNtBF+;W?@o%?ON#R1?%sZf&sZ299r zxm9{2jwjZnxO;vyMxtBieF8`NeTb<%zF1%WXU7@wQ+Q}Jxw1j=dvPTXuc-di9{_&W zB|!W4N6z4Uid0wz$;g$^-UYBteGc(i%CK;~%q>JF|7|NshkX#(?Z0IJtmTKh+s}Uc z?p$4t(bh&&bDj9E$-5u^bX8DxszpA|P4Kgfk#HKV=k-Jt$*Zh=abd|RYg13Ipl7R` zA9tL5&&Bgrr7QwMd`Mb_4x&x(D~*00uCer4ops`Gu5wcHm`V1^wt$0vDWvQ6rYdvA zNlA}7te(cp2_MQjDznrBJFjpgj`70AgFYNb30cch=X6cL@{a=_ZtG&9{R!gLj5hy7 z*}k*<$9uH>-O8RmZtj9bq-7^ZY>G9m%;f2&1nGM4>l_qDSa~qyuc)uvl+`R0x14-t z(zJR%BcygCC|BWO`lgF4YjrYn8@p}(VYY^evX&HWdSm+0<_=Ta8O@V02+U=Gx>Szo z8~}g|0-p3@aJ3JNL2IBnS2o8Da(F|lj!3$1UWL>sMce5S5mT+u^)E~2{!zWtI!1c7 z_P8^VYnwZ?__EU8qk4Gdjm|b`MM_1Igvt7&9NjyLaS0Qb{>4)T&BaTEKew6cWQkb+ zPD9mzS_L%#Z`Yqe25*cLV94I9pTvzUvwAwQU+3b`9M( zvEz?Ho0{M7AEkEX;1*Qa^Q)2PV+58}-m2|6 z6`3x!?i%Pu6*K1txyrz!!sR`Gh>5;rkKnRcvo-AYnGezbB%{w)9THf<6F$c5Bf)>Z zok|B+RKPn>XOo08h2PFBWnZ`EN58+?ph6g9m0;rJ$|tHsrODe%{sk0hum&mC0skjq zfl~Ephmp$l7>Q@6v}X;Z61svJ=D|sg68~)Ps%`Wkqe6!>ryo7AyHnZ)t(O*+lTzQdO*%Z*S zHyoe4TI=1Pwby8LK4Y&|a~myJtFSY<)KmAHiz0{4Y?SN=05Tck`9tAza+ocqzG9rf)>Dbl+ zuII+70|}WHyF`javXaqa(1WIIlCc%# zO*3DvPMSpq46bpCV4TITCD5s#k!fF~G*|Zk_>}(0^SkV$>~}frI=+vbt^S}>b$92( z_Z+^UYbi%M^|X>Lwa62(K6;Em@3uyd9a+b71pwO}4P~Adc$NuEQ?bA0n+$MW7*xFa zj3NRg|KvEoTR*teZDeDK$Z>^559bu*w60335^Y>ER`wj5{@Hj%%7y)w^PX$G(0B)9 z9ZHs z3)=MkjmR`5%DAv{lQ$K4evgnIS^T$wkcmoAoR?LC8E`CjV*&S-dvyS-6Yz|oVtXx& zd&jO!|JvS!tP>rckkc7ccP$wOk^lhv2LZ}uZYJpKPTC~-#F8svLP`FI0^>r;5+}S7 zOCb+aB0m>JWME9rGQc2gE4H1)%i?(;)Sxn8cG4f?C|(hR_nEF-sk=1C{L+=NtK5#O z=+C+TB0#sek98^vIwkSg|Il%w^-z1jE!hZE{raGlsN!n;@syFXhHTTF3?m=#!C09Q z;ux`R`}<9cn*c!gc&s5gla$r)no+Y;nPh`sT)0Uv$J2*Hc`JU(9(g&#cM4NV#|vrP zL!$^VDq~4e=Lu`{W#Zyf-+buQfv9`!1)XQamf`S8fy;2*!iHE7Df)j5j8<8BUePZlgO?^mQ=7Zj*-xry`%Oj z03ZTEdoVC!WB}eglkD4K?sBpARHUJJG0Z>ot^#Tn|Yt_dcWs+-)H8# z>+g%$t8bM-IzOR(PNjEuNo99a3u7pn z9}q#&szbpS2?F7MWduJ%zhNB->FJJj>uKD9Yxw!fismHBka7ZIxU`kf6_1R`-Db?T z#7!fM3=?x3tmgXcBZHsH3Z?cvp02Im#O3LZ=;gB>{AMXBbZ`q-K8}3Y0OPp`3=v7{ zYs$Bj(uvKn<-(z~RtoFkjIFr+s$p%PZB4iPa;gIZ{mQh*8^XgU6q}D9a}BgY3e&-~ zymgmK9)6DzrhcN*$BkFgIz7U-KuV7}(T-S|3orbGd+ zSNS|a#pRM%5A5A*Z2eR3O_3f}IHTQf1?RL<=b$irKXQj-?~h@-q` zZ3$*Wnj6D1&5sbHHaM?XQ@Q$<+-*ycSrghz<}%4uuFB{z4|JxraMwrd%rlN5_R6ZF znbMRCNtU&&er1!(Vhm?j+baG|{x~Qn^Q3X%sEF!Ey~Rd+2P0hSgwn2acnn-M^$8?P zXCr&b^WG(A^~^L(piZ<5SF+k=Y9im3D^2q!a2Mgr{z*Ys#D7 zvD%FfNcR@6eoWSD`!_m&fL)I!EH+-dZn8lzOYn&FpfD6P9v*gt?-L&#_tTRXNna17 z{%zcSodT)*_>;lr7)OD(2zPC>$7$F6#G(kttL=3bB63DMn-#IJwNUlMLYT{Pw3Uic zoh$9N=T{$o(M)I|;*JlvHti&xUE>Ye?(A-Zn(GQP=%JE@ed4x9{M`xqkFq{W4XH{b zhfJUF!YGb%(re_!j%CUg|CBp+MFjMz~}eK^PCWgJWc`n~z#8*+2HIafx^E^t=9yhzF~+Eo1IK3WzOH#oenBElGGgc$10t;dNqLec`)j zlr^VE<(aBnx><96SEO7k23hbVZ3P;IH67uXl)E`t39c*kM=5yv>!xWK2I*BEDj?su zJj*W7PBbpn&HbJ_Ff~0V?bsM%l5=Q@Aq*L-GR zo)s&mH29f6R=fhQ7BN)kx}s3+@L^q&M*{@>@>moJe^7>YA_t@f=cAZmL;$|yf3}E0 z+iu{w9)3UY)jl&D;MFHizCgBDG*O{PTFyGXB=#%1qT2e@mcd;U)1P03o7uc0C0oyO zSea!)HD*ymZmCyfsMCg+aQyzb?zi0)5$gO3oTT^HyUp{IQkkP5@v|jfRj9+WQd#MJ zmYjB-wMRvTCkmY&-Jm1Frf@i(bIK0wr6w&p$he&?sh1I_X%A1eVMt(n7)VTWxo+%a<6%N8ibm)hhGo=HRRFreW z1Y?3kue51(-zT^7kYKzycYd2*S|^{J%t0K(fP-B9>jssD4*q0Z#^bf15aeLU@Gp^V z)}v>PoJJ-47}fHbU}!C;+jdmn$rrmF?D}om3v=3HBdJ&UM(hzicX2=-TA$oTo++{M z_Hs9t37yNUDp)=kt_CX26kesXY>K%9zz71sx^NdSh9{|26X)WYPgzydFh{bb&e+iU zrOE2V4y9Sh+AKRbitHjI(ejJh0EG|iCb1SDmArA7zEq`I>Twokei5+?nCno)6MZG- z0X3M6L&-0Q^t;5EgA{kDloM+SKnYYE{uiEL-RzM)<|yd(jK1tdLM+2B8OlIMm!uTN zf`m?{T5o+|uuc`j_3q=VHAJ|Zr+L{z{cd|26PFPTD82Rp>~q|S3QLuoLjH-1K2eK*x`;Ou2$T4SLA;fLTAU@I*pr9v?@YI*CD8?MeEmd8W+5w9 zO#W4sItsuZI==-;L_{Nj=VdcobmkwpsP%XoP2uK%VLxx0R8?avMePBxf5tAi6fGop41O6GUko^vD65YXegn_^JJT`#Mt*4Vg@OSkZd8#kTfKWee5F{ z49e1IEMv(ogOHiQOnl@0&iC*4o%6lt{o}swbD#S<*Y!KUYq{?$?w+}^5dRr|E-o&i z+a^YqoPCS4{QltONZHTkxtxs~X=!|u3)e66gL63QZeV7>#Z{Fgzeb{1fW1hUqDV-52}V2JUF`-6h-H)YOUxpXP&jq1^0*L(Md6W=5>x5$J2;&C_}a=meq8O*#+nKf?1 zLCGb^(pYqT^Favlgqifw_Qi{5K!030`|k>;R}lTR+M?Fqj3T`~566e}Z)VNNC1q&6 zs#}7p&T_m=#OB=CEc7KaaDSKJ>(~#X26scLkQ$G2OVCn(;`nK7N<}lyGxB$xr-eSs zj?t%vS&bIS#(TP<_I`M_7T}lPM&n3BlHfcQ!a}G#al?m&=pVyfpBmTBzU7_X3kvZY zhG-&UJmwcf6I-qoYHhV0Xs?A#Ypq?#ybHI4@rQoDL3Rje*DTJR^^eNHJVF<ncd zj9-F^JO{2MW>`QMXzItNZi<1@x=KgsN*zJWEk+UYPAU8Uxb3N8w04+OeXWRSG zWTIf1zBm}@+i#Ttg$li(klGHWgxP)quW~@7%vHrn4)nP9?*5>TaB!j~;LHt_Fc(_V=K zVu}m#O5K;4Z#Upr+PB7eAH6;2&}ta0(UD^(&i`jKeeq%y=lc_H`6=Qd^wDT z%-FRP@3zwD2#3IFa_O@n=`5Dd*`z^qAu=akxM}AwVspMX^Y6~0(Z9Zz7j8ebH?pWO z%$w1A*g9^t;WNbCUM#PXiH504Y;Wu6Vq{9#a10yswe*?CJhw99lj_^z5e3EKE}S)$ zKTl;ZZ>l9Y!zH<|Gb+y^wm1!to?n*M_BXn&atq>?{K?eOVQ~|YKGUhk)Ld(iCR=}h zr>&%z*09qF4%{9*en5P1+LceE#Rp&gRSZ8&nR}t3qZe-SXxK1D2R4a!>4v{Q3dINU zl)?nP-uODL>h!5!vR9)W;*|%_Jl&Q%Uc!E7Ri=lv7Etn^AHMiPfgISFlsorU35clM zP0!0sAX&cQgl-I4;btPZT(iVgfb305U)xin>c}aWC-xV&y;9I=oz|UMxXF2IccGG+}zMiJCT{l>)caC5W7o7E6M^l1?HWCTTb6|&T%QD z^Y4&%ZJ?xu784BeO|c8VbB_1CJ{8tqcOo%-l(NG8e`rf5!n!UchObsl_Ei_Y%+A<6 z$tT5=>q~V5(T6?t2DBA<)&Y|F#8elynP7Q^>o~_E&&B^8K;MQ^opA)dG1uGW6+}47 zsqV!T3HW%>@b&$U!9_gP4V;}B%|>Z5Uvd*RZ1)0NPqn00)!n?vb7oNeJWl4<3aonS zp9vJ>OKG|yRGjvz52B6+^szF6(cn~cTUIn1`Ezsr_sAfVAmKb}r;x@BzPIOa|HgE` zvT{kouhkrDB@6r&%H_<&bDVxMy=V-u*zj8DvFg-WsQ!!7GZ4pwh4}Ekf{k?Tq%~1{CpLtE-ahvYZqhB z@qtU%7r7H--}feH1D_>Tp0Y4~6yc1#zHJ+Tv4H@>)DggnBC8m=f#F6-m*e_a_%h)~ zZufiBKXd;&lVyCJ@MX~98IiAP;mVo36R1}b^CwcNQ2#Yv4PA1;3+U#W&=n(!yTD27 z?QQjSz)}OfyQfFoSVk>0y`b$ zr_d?XI!`@+a1d@ebL15&>Etn z=2qzL@!5gWbbR`pj-Mt%%G47cqof?pVjQn%n-U7B{JoUFE`4#Q?NWEc?~M+>fOEIV z`#}mw{PI?6Y{J6WDU5tHV0Y*I!yVR4><`Fdj^264YHM5ktUcMEI9B!srAzUMQU|FzPwz60ULWZ z@Jc1@>0M_J=+;NhkKi}*JyBcyYUZyiHg^Cu0Ts!l%DN=4iQb;Z=jF?pq>WhlNm5Az zJF!1G&HisMZ+cLF6E9kpI`V z9+Z^N2Z$S2V4upQ1^KzkbSJ(4I@u5(!72iODEf_s?*L+hJ>a~TLngloi8@9ES8H!e zRj!SZ^#IcWhG<_0K!OTkI;^4;K!1mO%V#(Ou|J)cl19($wSYUbHagPgrt;D>S~fn_ zmgn+WT_lu&l}yJNonIDO__gl?kn*4=XC?G_eJ8mF$SyYpn5sJTH`;mXRit!Ux%d{S zffJ@o)iQI-D*73E)%{}$)TIH=b3O4hfwoJoc0HLGZW9A$LjcSr_o1*K3#n=JZ=f@c zFF3h9bG+loqv+TfUZ9_Ct{@-c8Qg=Y(h*xhSn=B}m*W+7$9(&t&<$>50y+d*j~@a6 zxQEY(O~cGOtttIf61sJ~D>}GJUkbnM!cNMBskQ`I@_>rGZ|$F}@iugmmWl}H7j%DL znAooKuK#4ANJ#>&B$uy*ZIn@}p?}(F=I<@Hq%z+Uu*Kro%9;6D^nR^R7AL!to2$J| z6j1YXRw)x=kj+!B|gc{XCSmILjpnKP@Hby~D z%c#FkHb^2IF-CON&s&a@8tGm+GM1T2xYwlT?c%OYRv$kKoPMN!RIKr3f;=4E>RdW^ zBrp!^I_#Af{BFfE6^ZK~MWnyR%K}%wcKqe#Ma!+GBN(&sYHJpK89g3}%9U>>YChcH zPRZ0PycKWdoD)xLulfq10NLa8j3}_L(!TP^%n6$sQtYUg&%~>;qdq=@DzrY3dow9) zKD7ahcYtkTe|wGr;~-W6%4bk^R!6k8V>0LqxiyIpRhMmu+qKSs$554}3*~~sXRnr3 z1#}AXTz4=r3*jNS{@CMF~2#;;|1(@_~c#lB&_iM{{YD{2Kuj0a=mv?oU_1yW` z)iqd6$c-J1ngm412_{0lXr1DYRm!&NIBRq9@Xo8GZ2|Gw{~ghyH(%0PgHrFy+ukIWD05W&&pQD5 z5Ezqnmu>ky&EjF3TRqa9=`wzy&HVM;YEARB+umG~Z6pWup!#^F64U#IRmi2SV|0q6 zCPFkwxh_RYe=;1&R6>EW7P_Q!7&Qagi~(@YL*{yqs1j#b(#aSnVSyssKG9xTvCGE{ z){Hnz9OFEz(~;A)j^RVKe8QS*c;Cs2kvL&PbqlmovYm}jtw>*>2ZF7i$V=F&$s@A{tTP=%07pXe>sPN&ze$ix2vFCu^ z$jF0_oo^DJNUHlaUFN`fiX|AYN4swhR}g4L-_(QV?2Od@@KQXS>YPdvKmSRa3?W;G zVUXq{qyb$G75B={#|Z|KY9&cvLYgrLdAFtXSemT|{Q4zBhzok(=a<*pl;{I~4#m;$ z?VFnnhNoK1!n$QAzsGY+L@N(bt6iw6t0xMK zVsu*c{)^22X67qNFkiJb=nSuQp5O5uDxtOch#>g#{{+BW{7|dA$Zx(J+FVMq449}9 uh#DUq=0wuKn8U_DH~#;^2c6A0_{3ZF_~pfVbI!=kb^DgN5$>i_)PDikdi#X{ delta 1461 zcmV;m1xot8AIJ+KiBL{Q4GJ0x0000DNk~Le0002b0000m2m$~A0Zt%^QjsAie-6U{ z01m?e$8V@)000GDNklA%wr5ZniN9qh_=FX7yO}e4uz;e)!hw?(nqNA&kO6GlKtL zxBh&y3Ek@u#`A{m?8>(&ET>QVf2a6{6d$fUlNnk@o@AO)$)^t&9`;t=LvN8M?lEc? zDL$NDfy$9k(vRHxsORs8LuwV4Eh>#r+nAnr`+@jAyw8X8JAtQ`W(9vrew{xbPEVeC z1 zK=PZF$Y}I%4o=M>RFz@s9)m~(NvIh2R2f9#c!)<~^l;*-xfHrle?^Rhl5D(1r2)LE z4AYXVu<$@`-L)Z21)-0!57NlJR~e>Iwn*)hxchqz@O=#^3{%=rWk!YURb`kygXyVB zo`<#Bs5Bysymjx!t8(OdHc#TyscjaCr*`UJDJ(BOtF>%quyD90);F(F+_lSJvVV}N zs*GxB%J$1Cey_Plf1w@n9nXi)5w#^E$fQ=Kr^Z4_e&uFtkG?C6Zbn$smoM%0s@8 z6mmyulDFgFw&{Drs1=^9`_a6IsPwcs1iF6+K^=L(kLUHN&-H@mkGub+JNWTBTpKd z1x9^+N0$C>L!LP0$lL6_uHc)qr&e-&P}l)i$Qz%N5)?wm7cj_^cjWGE^JLvCk->-d zvJWuQf{e(CfBvaJp8D68)BX|1H>D;a^cFlU7o1be7kI`yU&+C3 z)3^8f@3Z`hiyy<+vd;-dUgR*e0Zse0f0ot1+k~W6p(pNDF&cU6iK^rah@_;MGSULd zIh0|Ue+WilK~k%bMD38b7!nUdOZ9L_twNHo<=k!a1dl>O>j_3lL|x3`C6WM+mI&#&*hOP?me85cTm~NWbabW$XkbzFJzw+ zjHKKvWbYLtc^>>%aqjOnwIM-1qV<{yIZ{s5e`sb(e400BQ}-f-<&Mxa8~OFbD`cN5 z%#yF=;I<7=Xou8llwn%#NFg5(`Y3pBXJ{uVgw2jdr7tO$rI5RKDfj9-YD2|Ho(KO` z9N)H{@_Ud%-Xn#4^JBPs+cukZ_HEm|j(yuUuVde~&Fk2=ZSyKVe*FgA&BjX(>$U;_ P3jhEBNkvXXu0mjf!YJbP diff --git a/docs/img/gsg/Partitions2And4Active.PNG b/docs/img/gsg/Partitions2And4Active.PNG new file mode 100644 index 0000000000000000000000000000000000000000..7d0cb2ff8d0b11b2c53c161ee6626282fc2433a4 GIT binary patch literal 5264 zcmbW5c{r5c-^WSF)|e(+VvMntVkEL<8-@%L60%K}WJ^g#jO;VABw>(UgF=>xvM;x7 zX1*xdE3%9&#h|{UDbMt~e$W5U_55+pxz73HT-W`%&inm&y>G&0Ym^ZG34RU^4j~J3 zJnY#gxK)6?aNfOwGUliqKDox;9QHM`GUDK+cp>bY+Tzc_W#N1kM*|vS=C)~$R4&&Yj!C4LsdN9wM<^Wn; z?id2XLqO8vjby>+JRkqRkHilnK-zLtkj|iue{39Rm?3Ye0B$nsxZEH8N(I{+S%RLr z-K)|$A6xp-T9=7k_lOf}V6k=-NB9ETLNa_?H~W`$zw4cP@EKbc>G69{U|JzR#ml5u z2G1OXJK^S{aLy3D-OJg&({j?`9(r?eAZyCM-?N@u=YRk6OVPWhw$+E(c_6wxtUozo z$J_e#$#V38KGxdfd;253iUQ5EE8T`ijSlutQ-4nT+CxDC4N*U(h7uF8iu6)br$19S zK0$Vhq8nHv1_L4A+spLG0(>y>fhU%PNZVVi55shiO>aI_S|_}KNWRS}aNYaQ{2sdBKK^NnE9o+2ok zAEZOs`FPg}_a(sz_s+DherXBzJ!HU}8GYc*+#ayWj`}gJa=`R0BBG?SmZ{kyUZo!+ zHmvAX0^l70f|``AZV$_LzvqxWcX#9s>&I*(Ykva;T(6g<+FXE9K?Zu%PA2J16OwjB zhOSt29BwxWkm1jgKn5yi=ek0O!<9Y%%-%>JB7-g}4Nt@AxxPNk0jSudDCv9xzRFMc za2cyCJ&h`JN*!!B)>^=TAfy7wwunz3!(6hXw@sfBm�RmD)l<-axtZj5qR2KSx@| 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 U^8F(UgF=>xvM;x7 zX1*xdE3%9&#h|{UDbMt~e$W5U_55+pxz73HT-W`%&inm&y>G&0Ym^ZG34RU^4j~J3 zJnY#gxK)6?aNfOwGUliqKDox;9QHM`GUDK+cp>bY+Tzc_W#N1kM*|vS=C)~$R4&&Yj!C4LsdN9wM<^Wn; z?id2XLqO8vjby>+JRkqRkHilnK-zLtkj|iue{39Rm?3Ye0B$nsxZEH8N(I{+S%RLr z-K)|$A6xp-T9=7k_lOf}V6k=-NB9ETLNa_?H~W`$zw4cP@EKbc>G69{U|JzR#ml5u z2G1OXJK^S{aLy3D-OJg&({j?`9(r?eAZyCM-?N@u=YRk6OVPWhw$+E(c_6wxtUozo z$J_e#$#V38KGxdfd;253iUQ5EE8T`ijSlutQ-4nT+CxDC4N*U(h7uF8iu6)br$19S zK0$Vhq8nHv1_L4A+spLG0(>y>fhU%PNZVVi55shiO>aI_S|_}KNWRS}aNYaQ{2sdBKK^NnE9o+2ok zAEZOs`FPg}_a(sz_s+DherXBzJ!HU}8GYc*+#ayWj`}gJa=`R0BBG?SmZ{kyUZo!+ zHmvAX0^l70f|``AZV$_LzvqxWcX#9s>&I*(Ykva;T(6g<+FXE9K?Zu%PA2J16OwjB zhOSt29BwxWkm1jgKn5yi=ek0O!<9Y%%-%>JB7-g}4Nt@AxxPNk0jSudDCv9xzRFMc za2cyCJ&h`JN*!!B)>^=TAfy7wwunz3!(6hXw@sfBm�RmD)l<-axtZj5qR2KSx@| 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 U^8F0 if the driver provides configuration ;Calculate how many work area space can be allocated, it will be: @@ -1315,8 +1686,18 @@ endif ; REBOOT:: ld a,(BOOT_DRV##) + push af + xor a + jr DO_BOOT ; FIRST_BOOT: + push af + ld a,0FFh + +DO_BOOT: + ld (IS_FIRST_BOOT##),a + pop af + ld sp,BOOTAD+512 ;Must have stack in safe place. push hl ld hl,BASIC ;Set jump address when MSXDOS cannot @@ -1352,17 +1733,12 @@ endif call SET_XFER ; then call the boot sector with scf ; carry flag set to boot up MSXDOS. ; -JP_BOOT_SEC: - ld hl,DISKVECT## ;Jump into the MSX-DOS boot code - ld de,$DOSON## ; with necessary parameters in hand. - ld a,(NOTFIRST##) - jp BOOTAD+1Eh -; + jp JP_BOOT_SEC subttl Set up for disk BASIC IPLSTR: - defb 'RUN"\AUTOEXEC.BAS' + defb 'RUN',34,'\AUTOEXEC.BAS' NULL_CMD: defb 0 NEW_CMD: @@ -2119,6 +2495,42 @@ GSLT_SLTTBL: PRINTL INIT,%($-$$INIT) + + ;Scan and store boot keys and check if keyboard is Russian if that hasn't been done yet + +DO_KEYS_INIT: + ld a,(HAVE_KEYS##) + or a + ret nz + + call CHECK_IS_RUSSIAN + ld (I_AM_RUSSIAN##),a + + call SCANKEYS_RAM + jr z,DO_KEYS_INIT2 + call SCANKEYS + + ld a,(KEYS_INV_0) + and 00111110b + xor b + ld b,a + + ld a,(KEYS_INV_1) + and 00110000b + xor h + ld h,a + +DO_KEYS_INIT2: + ld a,b + ld (BOOTKEYS##),a + ld (BOOTKEYS##+1),de + ld (BOOTKEYS##+3),hl + + ld a,0FFh + ld (HAVE_KEYS##),a + ret + + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ; End of hole. @@ -2176,6 +2588,21 @@ SETDEFDPB: ALIGN 5006h SNEXT: CALLDOS 12h ;;Search for next (FCB) ; + +; Compare zero terminated strings pointed by HL and DE +; Return Z if they are equal, NZ if not +; Modifies AF, HL, DE + +STRCOMP: + ld a,(de) + cp (hl) + ret nz + or a + ret z + inc hl + inc de + jr STRCOMP + ALIGN 501Eh FSIZE: CALLDOS 23h ;;Get file size (FCB) ; @@ -2190,6 +2617,14 @@ COUNTDRV: call ?C4PBK## ret +JP_BOOT_SEC: + call SBDAVEC## + + ld hl,DISKVECT## ;Jump into the MSX-DOS boot code + ld de,$DOSON## ; with necessary parameters in hand. + ld a,(NOTFIRST##) + jp BOOTAD+1Eh + ALIGN 504Eh LOGIN: CALLDOS 18h ;Get login vector ; @@ -2270,14 +2705,12 @@ CRLF: ld e,CR if HYBRID ; CHECK_1KEY: - xor a ;If "1" or "2" key is pressed at THIS (oops) moment - call SNSMAT ; force MSX-DOS1 - and 00000110b - cp 00000110b ; + ld a,(BOOTKEYS##) ;If "1" or "2" key is pressed at THIS (oops) moment, force MSX-DOS1 + and 00000110b ;===== start mod DOS2.50 (build type) jr nz,OLDDOS ;OLDDOS will do the rest of work. - ld a,(PROCNM+9) ;If in disk emulation mode (set by AUTODRV from DOSINIT), + ld a,(IN_EMU##) ;If in disk emulation mode (set by AUTODRV from DOSINIT), or a ;switch to DOS 1 mode jr nz,OLDDOS @@ -2285,7 +2718,7 @@ if STURBO ld a,(VERSION) cp 3 ;MSXturboR? ret c ;no - ld a,(NUMKEYS) ;4 key pressed? + ld a,(BOOTKEYS##) ;4 key pressed? and 00010000b ld a,81h jp nz,CHGCPU @@ -2325,7 +2758,7 @@ if STURBO cp 3 ;MSXturboR? jr c,NOCHCPU - ld a,(NUMKEYS) + ld a,(BOOTKEYS##) ;2 key pressed? and 00000100b ld a,81h jr nz,DOCHCPU @@ -2371,7 +2804,7 @@ endif ;the work area is already created in BUF_1, ;so just jump to area relocation procedure. - ld a,(PROCNM+9) + ld a,(IN_EMU##) or a jr nz,MK_EMU_TBL @@ -2395,9 +2828,7 @@ MK_EMU_TBL: ;then just copy from BUF_1 to it. ;Otherwise allocate space in page 3. - ld ix,0F980h ;BUF_1## - ld l,(ix+16) - ld h,(ix+17) + ld hl,(EMU_WK_AREA##) ld a,h or l jr nz,OK_EMU_WK @@ -2408,7 +2839,7 @@ MK_EMU_TBL: OK_EMU_WK: push hl ex de,hl - ld hl,0F980h ;BUF_1## + ld hl,EMU_TMP## ld bc,16 call MEMCPY @@ -2416,17 +2847,6 @@ OK_EMU_WK: set 7,(hl) ;Disk emulation mode flag ld (DVB_TABLE##),hl - - ld hl,NXT7## - ld de,NXT7##+1 - ld bc,6 - ld (hl),0 - ldir - ld hl,TMP_FROOT## - ld de,TMP_FROOT##+1 - ld bc,11 - ld (hl),0 - ldir jr END_DVB_TBL @@ -2574,10 +2994,8 @@ else if STURBO ; CHECK_1KEY: - xor a ;If "1" key is pressed at THIS (oops) moment - call SNSMAT ; no change mode. - bit 1,a - ret z + ld a,(BOOTKEYS##) ;If "1" key is pressed at THIS (oops) moment, no change mode. + ret nz ld a,(VERSION) cp 3 ;MSXturboR? ret c ;no @@ -2749,13 +3167,6 @@ GTIME: CALLDOS 2Ch ;Get time STIME: CALLDOS 2Dh ;Set time ; -SCAN_5_KEY: - xor a - call SNSMAT - and 00100000b - xor 00100000b ;A=00100000b if "5" key pressed, 0 if not - ret - ALIGN 55FFh VERIFY: CALLDOS 2Eh ;Set/reset verify flag ; @@ -3190,17 +3601,13 @@ GO_DOS2: ;(so don't run NEXTOR.SYS, AUTOEXEC.BAS or the boot sector code) TO_BASIC_REQUIRED:: - push bc - push ix - push iy - ld ix,SNSMAT - ld iy,(0FCC1h-1) - ld a,0 ;Do not try to boot from disk if "3" key is pressed - call CALSLT - and 8 - pop iy - pop ix - pop bc + ld a,(IS_FIRST_BOOT##) + inc a + ret nz + + ld a,(BOOTKEYS##) + and 00001000b + xor 00001000b ret GET_DISKID_HL: @@ -3246,7 +3653,8 @@ DO_LDIR: CALL_DV_INIT: push af push bc - call SCAN_5_KEY + ld a,(BOOTKEYS##) + and 00100000b pop bc ld c,a pop af diff --git a/source/kernel/bank1/dosinit.mac b/source/kernel/bank1/dosinit.mac index fdc2d834..de6730e8 100644 --- a/source/kernel/bank1/dosinit.mac +++ b/source/kernel/bank1/dosinit.mac @@ -449,7 +449,16 @@ map_jump_loop: ld e,(hl) ;Get next offset from table inc bc jr map_jump_loop ;Loop for next one. ; -map_jumps_done: pop de ;Get RAM code address back +map_jumps_done: + ld hl,_IRQ + pop de ;Get RAM code address back + add hl,de + ld a,0C3h + ld ($IRQ##),a + ld a,l + ld ($IRQ##+1),a + ld a,h + ld ($IRQ##+2),a ; ; +++++ ADJUST ALL ABSOLUTE REFERENCES +++++ ; @@ -2022,7 +2031,7 @@ P3_OFFSET_TAB: defw _GO_DRV defw _JP_VECT ; - defw _IRQ + ;defw _IRQ ;We set this one manually ; defw _RDSLT defw _WRSLT diff --git a/source/kernel/bank1/mapinit.mac b/source/kernel/bank1/mapinit.mac index 253fe858..d4a03d42 100644 --- a/source/kernel/bank1/mapinit.mac +++ b/source/kernel/bank1/mapinit.mac @@ -13,7 +13,6 @@ P2_REG equ 0FEh P3_REG equ 0FFh MSXVER equ 002Dh -SNSMAT equ 0141h ; ; ;----------------------------------------------------------------------------- @@ -147,8 +146,8 @@ if (BUILTIN AND STURBO) ld a,b jr nz,NOTR2 ld b,a - ld a,(NUMKEYS) - and 00010000b + ld a,(BOOTKEYS##) + and 00010000b ;4 key pressed? ld a,b jr nz,NOTR2 sub 4 @@ -183,7 +182,7 @@ if (BUILTIN AND STURBO) ;;if 1 ;;HYBRID ;===== end mod DOS2.50 - ld a,(NUMKEYS) + ld a,(BOOTKEYS##) and 00010000b ld a,6 jr nz,SYSSEGSCOUNT @@ -251,13 +250,13 @@ if (BUILTIN AND STURBO) jr nz,NOTURBOR ;ld d,a - ld a,(NUMKEYS) + ld a,(BOOTKEYS##) and 00010000b - ;ld a,d ;On Turbo-R, the "6" key causes - jr nz,NOTURBOR ;the bigger mapper to be used as primary + ;ld a,d ;On Turbo-R, the "4" key causes + jr nz,NOTURBOR ;the bigger mapper to be used as primary dec hl ;Always mark last 4 - dec (hl) ; segments as allocated + dec (hl) ; segments as allocated dec hl ; to system. dec (hl) dec hl @@ -312,13 +311,6 @@ MAP_SCAN:: ; ; ***** LOOP TO FIND MAPPERS AND BUILD UP TEMPORARY MAPPER RECORDS ***** ; - ld d,a - xor a - call SNSMAT - cpl - ld (NUMKEYS),a - ld a,d - di ;Remember current page-2 slot push af ; for fail safe. ; @@ -353,9 +345,9 @@ sec_slot_loop: push hl jr nz,NO_PRIM_INTERNAL ld d,a - ld a,(NUMKEYS) + ld a,(BOOTKEYS##) and 00010000b - ld a,d ;On Turbo-R, the "5" key causes + ld a,d ;On Turbo-R, the "4" key causes jr nz,NO_PRIM_INTERNAL ;the bigger mapper to be used as primary ;===== start mod DOS2.50 (build type) @@ -745,7 +737,8 @@ MAPBIO3: EXB_NEX: ;WIP... ; -; Call the EXTBIO routine of Nextor kernels other than the master one +; Call the EXTBIO routine of Nextor kernels other than the master one +; Out: D'=1 if system hook must be called, 0 otherwise ; exx ex af,af' @@ -774,8 +767,6 @@ EXB_LOOP: cp c jr z,EXB_DJNZ ;Skip master kernel as we have processed it already - ld a,c - ld h,40h push ix push iy ex af,af' @@ -784,11 +775,14 @@ EXB_LOOP: push bc push de push hl + ld a,(ix) + and 10001111b + ld h,40h call ENASLT ld hl,DV_EXTBIO## ld (BK4_ADD##),hl exx - ld de,0100h + ld de,0100h ;Pass D'=1 by default exx pop hl pop de @@ -816,6 +810,7 @@ EXB_DJNZ: jr EXB_LOOP EXB_RAM_FIN: + set 0,d ;System hook must be called ex af,af' exx push af diff --git a/source/kernel/bank2/err.mac b/source/kernel/bank2/err.mac index abf1449b..cf493a3d 100644 --- a/source/kernel/bank2/err.mac +++ b/source/kernel/bank2/err.mac @@ -86,18 +86,18 @@ read_error: ;===== end add DOS2.50 set 3,c sector_invalid: - push hl - push bc - ld bc,UD_PHYS## ;Get physical unit number from - add hl,bc ; the unit descriptor into - pop bc ; register B. - ld b,(hl) - inc hl - ld a,(hl) ;If UD_TIME is non-zero (UPB - or a ; is defined) then set it to - jr z,err_no_upb ; one to force a BUILD UPB - ld (hl),1 ; before next access. -err_no_upb: pop hl + push ix + push hl + pop ix + ld b,(ix+UD_PHYS##) + bit UF_DBD,(ix+UD_DFLAGS##) + jr nz,err_no_upb + ld a,(ix+UD_TIME##) ;If UD_TIME is non-zero (UPB is defined) then set it to + or a ; one to force a BUILD UPB before next access. + jr z,err_no_upb + ld (ix+UD_TIME##),1 +err_no_upb: + pop ix ; pop af cp .STOP## ;If STOP key pressed then abort diff --git a/source/kernel/bank2/files.mac b/source/kernel/bank2/files.mac index 91277283..8191cd3c 100644 --- a/source/kernel/bank2/files.mac +++ b/source/kernel/bank2/files.mac @@ -59,6 +59,8 @@ ; PROC RDWR_FAB ; + if 1 + ex af,af' ld a,(RW_LEVEL##) cp 1 @@ -84,14 +86,14 @@ push hl ld hl,(RW_OVER##+18) push hl - ;ld hl,(PHYS_UNIT##) - ;push hl OKLEVEL: inc a ld (RW_LEVEL##),a ex af,af' + endif + bit MD_DEV,(ix+FAB_MODE##) ;Jump to handle device reads jp nz,rdwr_device ; and writes separately. ; @@ -139,15 +141,13 @@ rdwr_error: or a rdwr_ret_ok: xor a ; of file error. RDWR_END: + if 1 + ex af,af' ld a,(RW_LEVEL##) cp 2 jr nz,OKLEVEL2 - ;ex af,af' - ;pop hl - ;ld a,l - ;ld (PHYS_UNIT##),a pop hl ld (RW_OVER##+18),hl pop hl @@ -168,30 +168,27 @@ RDWR_END: ld (RW_OVER##+2),hl pop hl ld (RW_OVER##),hl - ;ex af,af' OKLEVEL2: dec a ld (RW_LEVEL##),a ex af,af' + endif + RDWR_END2: ret ; ; ---------------------------------------- ; rdwr_device: - call rdwrdev2 - jp RDWR_END - -rdwrdev2: ld h,a ;Store the paging mode and RFM_PG ; flag in the FAB ready for ld (ix+FAB_PG##),a ; passing to GET_SEGMENT ; ld a,b ;Do nothing if zero bytes or c ; requested - ret z + jr z,RDWR_END ; bit RF_READ,h jr nz,read_device ;Skip if read. diff --git a/source/kernel/bank2/rw.mac b/source/kernel/bank2/rw.mac index 9e43ee65..ee46c20d 100644 --- a/source/kernel/bank2/rw.mac +++ b/source/kernel/bank2/rw.mac @@ -140,11 +140,17 @@ abs_rw_dorw: pcall INV_UD ; buffers for this drive ;If the disk has actually a FAT12 or FAT16 filesystem, - ;set unit descriptor as having UPB but needing validation; - ;otherwise, set unit descriptor as not having UPB. + ;and it's NOT a device-based driver, + ;set unit descriptor as having UPB + ;but needing validation; otherwise (no FAT filesystem), + ;set unit descriptor as not having UPB. - ld de,UD_FLAGS## + ld de,UD_DFLAGS## add hl,de + bit UF_DBD,(hl) + jr nz,abs_common_end + + dec hl ;UD_FLAGS ld a,(hl) and UFM_F2+UFM_F6 ld a,0 diff --git a/source/kernel/bank2/val.mac b/source/kernel/bank2/val.mac index 65b55968..3b22b0e1 100644 --- a/source/kernel/bank2/val.mac +++ b/source/kernel/bank2/val.mac @@ -619,20 +619,26 @@ NEW_BOOT_SZ equ $-NEW_BOOT ; --------------------------------- ; pop hl - call CHECK_LOCK ;Skip all if disk is locked + push hl + push hl + ld bc,UD_TIME## ; unit descriptor and skip if + add hl,bc ; it is zero since this means + ld a,(hl) ; that there is no current + pop hl + or a ; UPB for this unit. + jr z,valfib2 + call IS_FIXED_OR_LOCKED ;Skip all if disk is fixed or locked ld a,0 - ret nz - push hl + pop hl + ret c + push hl +valfib2: dec b ;Skip if B<>1 jr nz,not_opened ; pop hl - - ;ld a,(MFLAGS##) - ;and 2 - ;ld a,0 - ;ret nz ;Skip if "no check media change" flag is set + push hl wfile_loop: push ix @@ -755,9 +761,9 @@ if 1 dec a ;If timeout >2 then assume jr nz,got_old_volid ; same UPB. Otherwise 2. endif - call CHECK_LOCK ;Assume disk unchanged - jr nz,got_old_volid ;if drive is locked - call CHECK_MNT ;or mounted + call IS_FIXED_OR_LOCKED ;Assume disk unchanged + jr c,got_old_volid ;if drive is locked + call CHECK_MNT ;or has a file mounted jr nz,got_old_volid call MEDIA_CHECK ;Do a media check call. @@ -805,22 +811,37 @@ no_dos_disk: pop ix ;Restore FIB pointer ret -; This subroutine will check if a disk is locked. -; If so, and if there is no UPB for the drive, it will generate a new UPB. -; Otherwise (drive not locked, or UPB already exists), it will do nothing. +; This subroutine will check if a device is either fixed, or removable but locked. ; ; Entry: HL = Unit descriptor -; Returns: NZ set it drive is locked, Z otherwise +; Returns: C it drive is fixed or locked, NC otherwise ; Corrupts: none -CHECK_LOCK: +IS_FIXED_OR_LOCKED: push hl ex (sp),ix - bit UF_LCK,(ix+UD_FLAGS##) + push bc + ld b,a + + ld a,(ix+UD_DFLAGS##) + and UFM_DB+UFM_RM + cp UFM_DB ;Device-based + not removable? + scf + jr z,CHKLCK2 + + bit UF_LCK,(ix+UD_FLAGS##) + scf + jr nz,CHKLCK2 + or a + +CHKLCK2: + ld a,b + pop bc ex (sp),ix pop hl ret + CHECK_MNT: push hl ex (sp),ix @@ -890,26 +911,34 @@ VAL_SAME: ; push af - call CHECK_LOCK - jr nz,pop_af_ret -if 1 - call UD_TICK ;Make UD_TIME up to date. -endif push de push hl ld de,UD_TIME## ;HL -> UD_TIME byte of unit add hl,de ; descriptor. - ld a,2 - cp (hl) ;If UD_TIME>2 then the timeout - pop hl ; has not expired so return - jr c,pop_deaf_ret ; without further checking. -; - push bc ;If UD_TIME=2 then do a media + ld a,(hl) + cp 2 + pop hl + push bc + jr c,chk_same_do ;If UD_TIME=0 or 1 there's no UPB so build one + + call IS_FIXED_OR_LOCKED ;If fixed or locked media do nothing more + jr c,not_changed + + call UD_TICK ;Make UD_TIME up to date. + cp 3 ;If UD_TIME>2 then the timeout + jr nc,not_changed ; has not expired so return without further checking. + + cp 2 ;If UD_TIME=2 then do a media call z,MEDIA_CHECK ; check call, otherwise assume jr z,not_changed ; that disk has changed. ; +chk_same_do: push ix ;Get a new UPB for this unit chk_same_loop: call DO_MEDIA_CHANGE ; from the unit handler. + + ld ix,UPB_BUF## + call NEW_UPB + call TEST_SAME_DISK ;Test whether volume-id's are jr z,same_disk ; the same and jump if so. ; @@ -996,7 +1025,7 @@ MCHK2: pop hl bit UF_DBD,a jr nz,MCHECK2 - ld a,1 ;Return C & NZ + ld a,1 ;Return C & NZ (not sure, assume changed) if not a device-based driver or a scf ret @@ -1030,7 +1059,12 @@ MCHECK2: xor a jr MCHECKEND ;are reported as "changed" MCHECK_NOERR: + ld a,(ix+26h) + and 28h + cp 28h + jr z,MCHK_NODIRTYFLAG ld (ix+26h),0 ;Clear dirty disk flag for the checksum +MCHK_NODIRTYFLAG: ld b,0 ld hl,0 ld ix,UPB_BUF## @@ -1256,23 +1290,14 @@ DO_MEDIA_CHANGE: push de push hl push iy - ex af,af' - push af - ex af,af' ld b,(ix+UD_SLOT##) ld c,(ix+UD_SEG##) ld d,(ix+UD_DI##) ld e,(ix+UD_LI##) ld ix,UNMAPALL## - ld (BK4_ADD##),ix - ld ix,?CALL4## - ld iy,(MASTER_SLOT##-1) - call CALSLT## + call CALL4_PRESERVE_ALT - ex af,af' - pop af - ex af,af' pop iy pop hl pop de @@ -1395,22 +1420,22 @@ build_upb_do_findpart: push ix push iy + ld d,0 ld ix,AUTO_ASPART## - ld (BK4_ADD##),ix - ld ix,?CALL4## - ld iy,(MASTER_SLOT##-1) - call CALSLT## + call CALL4_PRESERVE_ALT pop iy pop ix + pop hl ;Restore unit desciptor or a jp nz,build_upb_notfind + push hl ex (sp),ix set UF_FOK,(ix+UD_DFLAGS##) ex (sp),ix - pop hl ;Restore unit desciptor + pop hl ;Read boot sector in UPB_BUF, it will be needed later @@ -1427,8 +1452,8 @@ build_upb_do_findpart: pop hl jr nz,build_upb_err - jp found_upb - + push hl + build_upb_dof2: ex (sp),ix set UF_FOK,(ix+UD_DFLAGS##) @@ -1605,8 +1630,6 @@ MKDPB_DEVBASED: push iy ex af,af' push af - ld de,MKDPB## - ld (BK4_ADD##),de push ix ex (sp),hl pop ix @@ -1614,9 +1637,8 @@ MKDPB_DEVBASED: ld d,(ix+UD_DPB##+1) inc de - ld iy,(MASTER_SLOT##-1) - ld ix,?C4PBK## - call CALSLT## ;Since we don't know state of page 1 when KBDOS is called. + ld ix,MKDPB## + call CALL4_PRESERVE_ALT ;Since we don't know state of page 1 when KBDOS is called. pop af ex af,af' @@ -1867,6 +1889,10 @@ endif push hl ld hl,0 + ld a,(ix+26h) + and 28h + cp 28h + jr z,NUPBL ld (ix+26h),0 ;Clear dirty disk flag for the checksum NUPBL: ld e,(ix) ld d,(ix+1) @@ -3365,6 +3391,35 @@ COMP16: sub e ret + ;Call a routine in bank 4 of master slot, preserving alternate registers. + ;Input: IX=Routine to call +CALL4_PRESERVE_ALT: + exx + ex af,af' + push af + push bc + push de + push hl + ex af,af' + exx + + ld (BK4_ADD##),ix + ld ix,?C4PBK## + ld iy,(MASTER_SLOT##-1) + call CALSLT## + + exx + ex af,af' + pop hl + pop de + pop bc + pop af + ex af,af' + exx + + ret + + FAT16_S: db "FAT16" finish diff --git a/source/kernel/bank3/dos1ker.mac b/source/kernel/bank3/dos1ker.mac index 257636ee..7b406314 100644 --- a/source/kernel/bank3/dos1ker.mac +++ b/source/kernel/bank3/dos1ker.mac @@ -4191,8 +4191,7 @@ T5696: defb 080H,09AH,"E" ,"A" ,08EH,"A" ,08FH,080H ; Inputs ; Outputs ________________________ -A56D0: - jp NODOS1F +A56D0: ;xor a ;ld b,a ;ret @@ -4202,20 +4201,21 @@ A56D0: ; Outputs ________________________ A56D3: - call DO_BDOS - ;ei - ;ld a,1 - ld (YF306),a ; assume CP/M compatible call + ei + ld (YF306),a ; save A (required for extra functions) ld a,c cp 031H ; valid BDOS function ? - jr nc,A56D0 ; nope, unsupported BDOS call + jp nc,NODOS1F ; nope, unsupported BDOS call sub 011H ; Search First BDOS function ? jr nz,A56E6 ld (YF307),de ; yep, save address FCB for Search Next A56E6: dec a ; Search Next BDOS function ? jr nz,A56ED ld de,(YF307) ; yep, get saved address FCB Search First -A56ED: push hl +A56ED: + ld a,1 + ld (YF306),a ; assume CP/M compatible call + push hl ld hl,T5700 ex (sp),hl ; after BDOS routine, fill HL in a CP/M compatible manner push hl @@ -4947,7 +4947,7 @@ I5B0F: DEFB LOW RDSLT,C63F4-C63F4 T5B1A: defb 0,"AUTOEXECBAS",0 -T5B27: defb 'RUN"AUTOEXEC.BAS',0 +T5B27: defb 'RUN',34,'AUTOEXEC.BAS',0 T5B38: defw A5B92 ; start DiskBASIC in direct mode @@ -8719,7 +8719,13 @@ A738E: add hl,sp ; Outputs ________________________ ; Remark is copied to 0F1C9H -A7397: call XF36B ; enable ram on page 1 +A7397: + call XF368 ; enable system diskrom + jp KSTROUT + ds 16-6 + + if 0 + call XF36B ; enable ram on page 1 ld a,(de) call XF368 ; enable system diskrom inc de @@ -8727,6 +8733,7 @@ A7397: call XF36B ; enable ram on page 1 ret z ; end of string, quit call A53A8 ; console output jr A7397 ; next + endif ; Subroutine XFER (transfer) ; Inputs HL = source address, DE = destition address, BC = size @@ -8789,29 +8796,18 @@ A7397: call XF36B ; enable ram on page 1 defb 31,28,31,30,31,30,31,31,30,31,30,31 +BOOTKEYS equ 0F992h ;Defined in kvar.mac + TO_BASIC_REQUIRED: LD A,0FFH LD (YF246),A ; dirsector buffer is invalid - push bc - push ix - push iy - ld ix,SNSMAT - ld iy,(0FCC1h-1) - ld a,0 ;Do not try to boot from disk if "3" key is pressed - call CALSLT - and 8 - pop iy - pop ix - pop bc + ld a,(BOOTKEYS) + and 00001000b ;Do not try to boot from disk if "3" key is pressed LD A,(DEFDPB##+1) LD C,A - jr nz,TBR2 - - scf - ret - -TBR2: - or a + scf + ret nz + or a ret TOBASREQ2: @@ -8824,6 +8820,7 @@ TOBASREQ2: NEWCMD: db 'NEW',0 ; Entry point for non DOS 1 function call +; The value of A is in (YF306) NODOS1F: push hl @@ -8841,7 +8838,7 @@ NODOS1F_LOOP: ld h,(hl) ld l,a ld (BK4_ADD##),hl - ld a,(BUF9##) + ld a,(YF306) ld c,a pop hl jp ?C4PBK## @@ -8857,15 +8854,6 @@ NODOS1F_ERR: ld b,a ret -; Save register A on BDOS call (it is normally corrupted), -; this is needed for the additional function calls. - -DO_BDOS: - ld (BUF9##),a - ei - ld a,1 - ret - ; Entries for additional function calls, ; they are all in bank 4 @@ -9090,6 +9078,7 @@ NEW_ERRS: defb 'Partition already in use', 0 defb 'Illegal in emulation', 0 + ;Allocate page 3 memory for the FAT buffer of a drive. ;Input: IX = pointer to DPB ; HL = Amount of memory to allocate @@ -9102,7 +9091,7 @@ NEW_ERRS: ;many games to not work) ALLFBUF: - ld a,(PROCNM+9) + ld a,(IN_EMU##) or a jp z,A5EC8 ;Jump to actual allocation if not in emulation mode... @@ -9134,6 +9123,34 @@ TRRAMEND: ld a,(H.STKE+0) ret + + ;STROUT routine residing in kernel ROM, borrowed from the DOS 2 kernel. + ;Replacing the original 16 bytes code with a simple call to this routine + ;gives us 10 precious bytes in page 3 that we can use for Nextor specific + ;functionality. + +KSTROUT: + ld hl,1Ah+0C9h*256 ;"LD A,(DE)" then "RET" + push hl + call RD_MEM + pop hl + cp "$" + ret z + push de + ld e,a + call A53A8 ; console output + pop de + inc de + jr KSTROUT +; +RD_MEM: + ld hl,XF368 ; enable system diskrom + push hl + ld hl,4 + add hl,sp + push hl + jp XF36B ; enable system diskrom + ; DRV.MAC is to be placed here. KER1_END:: diff --git a/source/kernel/bank4/partit.mac b/source/kernel/bank4/partit.mac index 202a7dd9..4e39e744 100644 --- a/source/kernel/bank4/partit.mac +++ b/source/kernel/bank4/partit.mac @@ -8,12 +8,16 @@ INCLUDE b0labels.inc ; +EMU_RAM_ADDRESS equ 0A000h + DISKID equ 0FD99h -SNSMAT equ 0141h ;sense key matrix MBR_PSTART equ 01BEh ;Start of partition table in MBR MBR_PSIZE equ 16 ;Size of partition table entry +POFF_STATUS equ 0 ;Offset of status byte in p. table entry +POFF_CHS_START equ 1 POFF_TYPE equ 4 ;Offset of partition type in p. table entry +POFF_CHS_END equ 5 POFF_PSTART equ 8 ;Offset of partition start in p. table entry POFF_PSIZE equ 12 ;Offset of partition size in p. table entry PT_FAT12 equ 1 ;Partition type code for FAT12 @@ -72,11 +76,18 @@ CHPUT: ; D = Device index, 1 to 7 ; E = LUN index, 1 to 7 ; H = Primary partition number (1 to 4) +; bit 7: 0 = Get partition information +; 1 = Get partition table absolute sector ; L = Extended partition number (0 for primary entry in MBR) ; Returns: A = Error from DEV_RW or F_GDRVR, or .IPART; 0 if no error -; B = Partition type, 0 for non existing partition -; HLDE = Starting sector of partition -; IXIY = Partition size +; If "Get partition information": +; B = Partition type, 0 for non existing partition +; C = 80h if bootable partition +; HLDE = Starting sector of partition +; IXIY = Partition size +; If "Get partition table absolute sector": +; HLDE = Absolute sector that holds the partition table entry +; (0 for primary partitions) ; ; In case of disk error when reading the device, an error code will ; be returned. We cannot invoke the standard disk error handling routine, @@ -122,8 +133,9 @@ CHPUT: jp nc,UNEX_DEVL ld a,h - or a - ret z + and 01111111b + ;or a + jp z,UNEX_PART cp 5 jp nc,UNEX_PART @@ -146,6 +158,7 @@ CHPUT: ld bc,MBR_PSIZE ld a,h + and 01111111b PTENTRY_LOOP: dec a jr z,OK_PENTRY @@ -160,22 +173,30 @@ OK_PENTRY: or a jr nz,DO_EXTPAR + ld a,(ix+POFF_TYPE) + or a + jp z,UNEX_PART + ld b,a + + bit 7,h ;Partition table entry sector requested: it's always 0 for primary partitions + ld hl,0 + ld de,0 + ld a,0 + ret nz + ld e,(ix+POFF_PSIZE) ld d,(ix+POFF_PSIZE+1) ld l,(ix+POFF_PSIZE+2) ld h,(ix+POFF_PSIZE+3) push de push hl - ld b,(ix+POFF_TYPE) + ld c,(ix+POFF_STATUS) ld e,(ix+POFF_PSTART) ld d,(ix+POFF_PSTART+1) ld l,(ix+POFF_PSTART+2) ld h,(ix+POFF_PSTART+3) pop ix pop iy - ld a,b - or a - jp z,UNEX_PART xor a ret DO_EXTPAR: @@ -217,6 +238,9 @@ EXTP_LOOP: ; Get the base sector number for the primary entry ; and return + bit 7,h ;Partition table entry sector requested: return its sector + jr nz,EXTP_ENTRYADD + ld ix,($SECBUF##) ld bc,MBR_PSTART add ix,bc @@ -224,10 +248,12 @@ EXTP_LOOP: call UPDATE_SEC ld b,(ix+POFF_TYPE) + ld c,(ix+POFF_STATUS) ld e,(ix+POFF_PSIZE) ld d,(ix+POFF_PSIZE+1) ld l,(ix+POFF_PSIZE+2) ld h,(ix+POFF_PSIZE+3) +EXTP_ENTRYADD: push de push hl ld ix,TMP_SEC## @@ -449,11 +475,11 @@ GDRV_OK_ROM: PROC AUTODRV ; This routine automatically assigns devices and partitions to drives for -; device-based DOS 2.50 drivers. There are two versions, one for DOS 1 and +; device-based Nextor drivers. There are two versions, one for DOS 1 and ; another one for DOS 2, since the processing done in both cases is ; quite different. ; -; In both DOS 1 and DOS 2 modes AUTOASSIGN is called with A=1. +; In both DOS 1 and DOS 2 modes AUTO_ASSIGN (or AUTO_ASPART) is called with A=1. ; This causes the root directory of primary partitions to be scanned ; for a file named NEXT_DSK.DAT (only if the current controller is the ; primary controller); if found and its contents are valid, the whole @@ -461,7 +487,7 @@ GDRV_OK_ROM: ld hl,0 add hl,sp - ld (NXT7##),hl + ld (SPSAVE##),hl ld a,(DOS_VER##) or a jp nz,AUTODRV_DOS2 @@ -563,6 +589,7 @@ AUTODRV_DRVLOOP: push ix push iy ld b,1 + ld a,b call ASK_DRIVE_CONFIG pop iy pop ix @@ -570,7 +597,10 @@ AUTODRV_DRVLOOP: jr z,AUTODRV_DRVL3 dec a jr z,AUTODRV_DRVL2 ;Driver does not provide config for that drive + dec a + jp nz,AUTOD_EMU ;We entered disk emulation mode +AUTODRV_DRVL1: pop ix push ix ld a,-1 @@ -586,17 +616,13 @@ AUTODRV_DRVL2: push ix pop hl - ld a,1 ;????? + ld d,1 call AUTO_ASSIGN AUTODRV_DRVL3: cp 2 ;Did we enter disk emulation mode? - jr nz,NOEMU1 ;Yes: discard everything else and return - ld hl,(NXT7##) - ld sp,hl - ret + jp z,AUTOD_EMU ;Yes: discard everything else and return -NOEMU1: ld hl,(DVB_TABLE##) inc (hl) ;Increment size of table pop ix @@ -705,8 +731,9 @@ AUTOD_UDFND2: ld b,0 ld c,(ix+UD_REL##) + ld a,1 call ASK_DRIVE_CONFIG - dec a + cp 1 jr z,AUTOD_UDFND3 ;Driver did not provide config pop hl or a @@ -721,15 +748,12 @@ AUTOD_UDFND3: push ix pop hl - ld a,1 + ld d,1 call AUTO_ASSIGN cp 2 ;Did we enter disk emulation mode? - jr nz,NOEMU2 ;Yes: discard everything else and return - ld hl,(NXT7##) ;(note that we'll enter DOS 1 mode after returning) - ld sp,hl - ret -NOEMU2: + jp z,AUTOD_EMU ;Yes: discard everything else and return + ;(note that we'll enter DOS 1 mode after returning) pop hl ;Pointer in UNIT_TAB or a @@ -757,6 +781,13 @@ AUTOD_OK: djpnz AUTOD_LOOP jp SETNUMDRV + ;--- We entered disk emulation mode, so return immediately + +AUTOD_EMU: + ld hl,(SPSAVE##) ;(note that we'll enter DOS 1 mode after returning) + ld sp,hl + ret + ;----------------------------------------------------------------------------- ; ; This routine sets the NUMDRV variable according to the number @@ -824,108 +855,109 @@ SETNUMD_NOUD: ; Address of entry in device-based drives table, must have UD_SLOT set ; B = Device index (AUTO_ASPART only) ; C = LUN index (AUTO_ASPART only) -; A = 0: Do NOT try to enter disk emulation mode +; D = 0: Do NOT try to enter disk emulation mode ; 1: Enter disk emulation mode if possible ; ; Output: A = Error code ; 0: Ok ; 1: No suitable device/partition found -; 2: Disk emulation mode entered +; 2: Disk emulation mode was entered -;Temporary area BUF9 (9 bytes) is used as follows: -;+0: Candidate device (a device which has a suitable partition, -; but has no NEXTOR.SYS file), device + 8*LUN (0 if no candidates found), -; bit 7 is the removable device flag, bit 6 is the hot-plug device flag -;+1: Sector number of first partition found on disk -;+5: Sector number of partition being examined -; -;Also, NXTEMP is used to store a pre-candidate device -;(a device that exists but has not been checked yet for partitions), -;NXT7+2 is used to store the value of A at input, and -;NXT7+3 is used to store the stack pointer at input so that we can easily -;discard the stack contents when entering disk emulation mode. +;CURR = current deivce/partition being examined +;CAND = candidate device/partition, will be assigned if no one has the active flag set in status byte + +AAD_UNIT_DESCRIPTOR equ 0 +AAD_LOOP_DEV_INDEX equ 2 +AAD_LOOP_LUN_INDEX equ 3 +AAD_DRIVER_SLOT equ 4 +AAD_CURR_PART_DEVLUN equ 5 +AAD_CURR_PART_INDEX equ 6 ;Bit 7 set when examining extended partitions, FFh when examining the MBR +AAD_CURR_PART_SECTOR equ 7 +AAD_CURR_PART_STATUS_BYTE equ 11 +AAD_CAND_PART_DEVLUN equ 12 +AAD_CAND_PART_SECTOR equ 13 +AAD_FLAGS equ 17 + +AAD_SIZE equ 18 + +AAFLAG_ENTER_EMU_MODE equ 0 +AAFLAG_IS_AUTOASPART equ 7 PROC AUTO_ASPART - scf - jr AUTO_COMMON + set AAFLAG_IS_AUTOASPART,d AUTO_ASSIGN: - or a + ld ix,-AAD_SIZE + add ix,sp + ld sp,ix -AUTO_COMMON: - ld (NXT7##+2),a + ld (ix+AAD_FLAGS),d + + ld (ix+AAD_UNIT_DESCRIPTOR),l + ld (ix+AAD_UNIT_DESCRIPTOR+1),h + push hl + pop iy + ld a,(iy+UD_SLOT##) + ld (ix+AAD_DRIVER_SLOT),a - ld de,(NXTEMP##) ;Save lots of page 3 variables. - push de ;This is necessary because AUTO_ASSIGN uses them - ld de,(TMPDEV##) ;as temporary work area, which is OK in DOS 2 mode - push de ;but in in DOS 1 mode these are actually used for anything else. - ld de,(NXT4##) - push de - ld de,(NXT4##+2) - push de call AUTO_COMMON2 - pop de - ld (NXT4##+2),de - pop de - ld (NXT4##),de - pop de - ld (TMPDEV##),de - pop de - ld (NXTEMP##),de + + ld ix,AAD_SIZE + add ix,sp + ld sp,ix + ret AUTO_COMMON2: - jr nc,AUTO_COMMON3 + bit 0,d + jr z,AUTO_NOEMU + push bc + push de + push hl + xor a + call TRY_RAM_EMU + pop hl + pop de + pop bc + or a + ld a,2 + ret nz +AUTO_NOEMU: + + bit 7,d + jr z,AUTO_COMMON3 ;AUTO_ASPART: - push hl - pop ix - ld a,b ;(ix+UD_DI##) - ld (TMPDEV##),a - ld a,c ;(ix+UD_LI##) - ld (TMPLUN##),a + ld (ix+AAD_LOOP_DEV_INDEX),b + ld (ix+AAD_LOOP_LUN_INDEX),c xor a - ld (BUF9##),a - ld (NXTEMP##),a - inc a - ld (NXT3##),a + ld (ix+AAD_CAND_PART_DEVLUN),a + ld (ix+AAD_CURR_PART_DEVLUN),a jp AA_CHKDUP_OK ;AUTO_ASSIGN: AUTO_COMMON3: xor a - ld (BUF9##),a - ld (NXT3##),a - - xor a - ld (NXT7##+5),a + ld (ix+AAD_CAND_PART_DEVLUN),a + ld (ix+AAD_CURR_PART_STATUS_BYTE),a - push hl - pop ix - - ld hl,0 - add hl,sp - ld (NXT7##+3),hl - - ld a,1 ;Device index + inc a ;Device index = 1 AA_DLOOP: - ld (TMPDEV##),a ;push af + ld (ix+AAD_LOOP_DEV_INDEX),a ld a,1 ;LUN index AA_LLOOP: - ld (TMPLUN##),a ;push af + ld (ix+AAD_LOOP_LUN_INDEX),a xor a - ld (NXTEMP##),a + ld (ix+AAD_CURR_PART_DEVLUN),a ;--- Check if the same slot+device+LUN has been assigned ; to other drive already - ld a,(TMPDEV##) - ld d,a - ld a,(TMPLUN##) - ld e,a + ld d,(ix+AAD_LOOP_DEV_INDEX) + ld e,(ix+AAD_LOOP_LUN_INDEX) ld a,(DOS_VER##) ;Skip in DOS 1 or a @@ -943,7 +975,7 @@ AA_CHKDUP_DOS1: AA_CHKDUP_LOOP1: ld a,(iy+UD_SLOT##) - cp (ix+UD_SLOT##) + cp (ix+AAD_DRIVER_SLOT) jr nz,AA_CHKDUP_NEXT1 ld a,(iy+UD1_DI##) @@ -987,7 +1019,7 @@ AA_CHKDUP_LOOP: jr z,AA_CHKDUP_NEXT ;Unit descriptor in use? ld a,(iy+UD_SLOT##) - cp (ix+UD_SLOT##) + cp (ix+AAD_DRIVER_SLOT) jr nz,AA_CHKDUP_NEXT ld a,(iy+UD_DI##) @@ -1010,18 +1042,13 @@ AA_CHKDUP_OK: ;--- Obtain device information - ld a,(ix+UD_SLOT##) + ld a,(ix+AAD_DRIVER_SLOT) ld_iyh_a ld hl,LUN_INFO## ld (BK4_ADD##),hl ld hl,($SECBUF##) - ;pop bc ;Retrieve LUN index - ;pop af ;Retrieve device index - ;push af - ;push bc - ld a,(TMPLUN##) - ld b,a - ld a,(TMPDEV##) + ld b,(ix+AAD_LOOP_LUN_INDEX) + ld a,(ix+AAD_LOOP_DEV_INDEX) push ix ld ix,CALDRV## call CALSLT ;Call LUN_INFO @@ -1056,105 +1083,184 @@ AA_CHKDUP_OK: ;* Mark the device as candidate for autoassign, ; unless this was done before - ld a,(TMPLUN##) - ld b,a - ld a,(TMPDEV##) + ld b,(ix+AAD_LOOP_LUN_INDEX) + ld a,(ix+AAD_LOOP_DEV_INDEX) sla b sla b sla b or b or d ;Include removable flag - ld (NXTEMP##),a ;Device + 8*LUN, bit 7 is removable flag + ld (ix+AAD_CURR_PART_DEVLUN),a ;Device + 8*LUN, bit 7 is removable flag AA_OK_CANDIDATE: - ;--- Device parameters OK. - ; Now read MBR and look for a suitable partition. + ;--- Device parameters OK. Now scan partitions. + + ld a,1 +AA_PXLOOP: + ld (ix+AAD_CURR_PART_INDEX),a + ld h,a + ld l,0 + bit 7,a ;We are examining extended partitions? + jr z,AA_PX_1ST + ld h,2 ;Yes: primary = 2, extended = partition # - 1 + and 7Fh + dec a + ld l,a +AA_PX_1ST: + ld e,(ix+AAD_LOOP_LUN_INDEX) + ld d,(ix+AAD_LOOP_DEV_INDEX) + ld c,(ix+AAD_DRIVER_SLOT) + ld b,0FFh + + push ix + call F_GPART + pop ix + cp .IPART + jp z,AA_PLOOP_END + or a + jp nz,AA_LLOOP_NEXT ;Not ready or partition not available +AA_PX_POK: - ;* Read device MBR + ;--- If we are scanning the first partition and bit 0 of status byte is set, try to enter disk emulation mode - ld hl,0 - ld (TMP_SEC##),hl - ld (TMP_SEC##+2),hl - ld a,(TMPLUN##) - ld b,a - ld a,(TMPDEV##) - call AA_RSEC - or a - jp nz,AA_LLOOP_NEXT ;Not ready + ld (ix+AAD_CURR_PART_STATUS_BYTE),c - ;* Check partition table + bit 0,c + jp z,AA_PX_NOEMU ;Bit 0 of status byte must be set + bit AAFLAG_ENTER_EMU_MODE,(ix+AAD_FLAGS) + jp z,AA_PX_NOEMU ;Enter emulation mode must have been requested + ld a,(0F348h) + cp (ix+AAD_DRIVER_SLOT) ;Must be the primary slot + jp nz,AA_PX_NOEMU + ld a,(ix+AAD_CURR_PART_INDEX) ;Must be the first partition + dec a + jp nz,AA_PX_NOEMU - xor a - ld (NXT4##+2),a + push hl + push de + push bc + push ix - ld hl,($SECBUF##) - ld bc,MBR_PSTART+POFF_TYPE - add hl,bc - ld b,4 -AA_PLOOP:: - ld a,(hl) ;A=Partition type + ld hl,($SECBUF##) ;We still have sector 0 of the device here from F_GPART + ld bc,MBR_PSTART + add hl,bc + push hl + pop iy ;IY = First entry of partition table + + ld a,(BOOTKEYS##) + and 00000001b ;"0" key pressed? + jr z,AA_PX_DOEMU + + ;* Reset emulation mode flag from status byte in partition table, then boot normally + +AA_PX_KILLEMU: + ld a,(ix+AAD_CURR_PART_STATUS_BYTE) + and 0FEh + ld (iy+POFF_STATUS),a + xor a + ld (iy+POFF_CHS_START),a + ld (iy+POFF_CHS_START+1),a + ld (iy+POFF_CHS_START+2),a + ld (iy+POFF_CHS_END),a + ld (iy+POFF_CHS_END+1),a + ld (iy+POFF_CHS_END+2),a + + ld b,(ix+AAD_LOOP_LUN_INDEX) + ld a,(ix+AAD_LOOP_DEV_INDEX) + ld c,(ix+AAD_DRIVER_SLOT) + ld de,0 + ld (TMP_SEC##),de + ld (TMP_SEC##+2),de + call AA_WSEC + + pop ix + pop bc + pop de + pop hl + jr AA_PX_NOEMU + +AA_PX_DOEMU: + ld hl,($SECBUF##) ;We still have sector 0 of the device here from F_GPART + ld bc,MBR_PSTART + add hl,bc + push hl + pop iy + ld c,(ix+AAD_DRIVER_SLOT) + ld a,(iy+POFF_CHS_START) + ld b,(iy+POFF_CHS_START+1) + ld h,(iy+POFF_CHS_START+2) + ld l,(iy+POFF_CHS_END) + ld d,(iy+POFF_CHS_END+1) + ld e,(iy+POFF_CHS_END+2) + call GO_EMU + pop ix + pop bc + pop de + pop hl + inc a + cp 2 + ret z + +AA_PX_NOEMU: + ld a,b ;Partition type + cp PT_EXT + jr nz,AA_PX_NOEX + ld a,(ix+AAD_CURR_PART_INDEX) + or 80h + jp AA_PXLOOP +AA_PX_NOEX: cp PT_FAT12 jr z,AA_PLOOP_OKTYPE - - ld d,a ld a,(DOS_VER##) or a jr z,AA_PLOOP_NEXT ;In DOS1 only FAT12 is valid - ld a,d + ld a,b cp PT_FAT16 jr z,AA_PLOOP_OKTYPE cp PT_FAT16_S - jr z,AA_PLOOP_OKTYPE + jr z,AA_PLOOP_OKTYPE cp PT_FAT16_L jr z,AA_PLOOP_OKTYPE - AA_PLOOP_NEXT: - ld de,MBR_PSIZE - add hl,de - djnz AA_PLOOP - ld hl,0 - ld (BUF9##+5),hl - ld (BUF9##+7),hl - jr AA_CHECK_BOOT_MBR ;No suitable partitions found: try the MBR itself -AA_PLOOP_OKTYPE: - - ld (NXT4##),hl - ld a,b - ld (NXT4##+2),a + ld a,(ix+AAD_CURR_PART_INDEX) + inc a ;FFh if no more partitions left (we were examining the MBR itself) + jp z,AA_LLOOP_NEXT + cp 5 ;We examine the first 4 primary partitions only... + jp c,AA_PXLOOP + bit 7,a + jr z,AA_PLOOP_END + cp 80h+10 ;...or up to 9 extended partitions + jp c,AA_PXLOOP + +AA_PLOOP_END: + ld hl,0 ;No suitable partitions found: try the MBR itself as last resort + ld de,0 + xor a + ld (ix+AAD_CURR_PART_STATUS_BYTE),a ;Clear any stale active partition flag + dec a + ld (ix+AAD_CURR_PART_INDEX),a ;Partition # = 0FFh -> no more partitions - ;* Read first sector of partition + ;* Read first sector of partition - ld a,(TMPLUN##) - ld b,a - ld a,(TMPDEV##) - ld de,POFF_PSTART-POFF_TYPE - add hl,de - ld e,(hl) - inc hl - ld d,(hl) - inc hl +AA_PLOOP_OKTYPE: + ld b,(ix+AAD_LOOP_LUN_INDEX) + ld a,(ix+AAD_LOOP_DEV_INDEX) ld (TMP_SEC##),de - ld (BUF9##+5),de - ld e,(hl) - inc hl - ld d,(hl) - ld (TMP_SEC##+2),de - ld (BUF9##+7),de + ld (ix+AAD_CURR_PART_SECTOR),e + ld (ix+AAD_CURR_PART_SECTOR+1),d + ld (TMP_SEC##+2),hl + ld (ix+AAD_CURR_PART_SECTOR+2),l + ld (ix+AAD_CURR_PART_SECTOR+3),h + ld c,(ix+AAD_DRIVER_SLOT) -DO_RSEC: call AA_RSEC jr nz,AA_PLOOP_NEXT - ;* Check FAT boot sector + ;* Check FAT boot sector AA_CHECK_BOOT: call CHECK_FAT_BOOT - jp nz,AA_NEXTPAR ;AA_LLOOP_NEXT - jr AA_CHECK_BOOT2 - -AA_CHECK_BOOT_MBR: - call CHECK_FAT_BOOT - jp nz,AA_LLOOP_NEXT + jp nz,AA_PLOOP_NEXT ;AA_LLOOP_NEXT AA_CHECK_BOOT2: @@ -1166,263 +1272,86 @@ AA_CHECK_BOOT2: jr nz,AA_SPC_OK ld a,(iy+UPB_SFAT##+1) or a - jp nz,AA_NEXTPAR ;AA_LLOOP_NEXT + jp nz,AA_PLOOP_NEXT ;AA_LLOOP_NEXT ld a,(iy+UPB_SFAT##) cp 4 - jp nc,AA_NEXTPAR ;AA_LLOOP_NEXT + jp nc,AA_PLOOP_NEXT ;AA_LLOOP_NEXT AA_SPC_OK: ;* Check if the partition is already mapped to another drive push ix push iy - ld h,(ix+UD_SLOT##) - ld l,(ix+UD_SEG##) - ld a,(TMPDEV##) - ld d,a - ld a,(TMPLUN##) - ld e,a + ld h,(ix+AAD_DRIVER_SLOT) + ld l,0FFh ;(ix+UD_SEG##) + ld e,(ix+AAD_UNIT_DESCRIPTOR) + ld d,(ix+AAD_UNIT_DESCRIPTOR+1) + push de + ld d,(ix+AAD_LOOP_DEV_INDEX) + ld e,(ix+AAD_LOOP_LUN_INDEX) exx - ld de,(BUF9##+5) - ld hl,(BUF9##+7) + ld e,(ix+AAD_CURR_PART_SECTOR) + ld d,(ix+AAD_CURR_PART_SECTOR+1) + ld l,(ix+AAD_CURR_PART_SECTOR+2) + ld h,(ix+AAD_CURR_PART_SECTOR+3) exx + pop ix call CHECK_MAP_IN_USE pop iy pop ix - jp nz,AA_NEXTPAR - - ;* All checks ok, partition is good - - ld a,(BUF9##) - or a - jr nz,AA_OK_CANDIDATE2 - - ld a,(NXTEMP##) - ld (BUF9##),a ;Valid partition: mark as candidate device - - ld hl,(TMP_SEC##) ;If this is the first partition being examined, - ld (BUF9##+1),hl ;save its number - ld hl,(TMP_SEC##+2) - ld (BUF9##+3),hl -DO_RSEC2: - -AA_OK_CANDIDATE2: - - ;* Check that there is a file named NEXTOR.DAT in the root directory - ; (if A=1 at input and we are the primary controller, check NEXT_DSK.DAT first) - - ;jp AA_NEXTPAR ;!!! - - ld e,(iy+UPB_SFAT##) - ld d,(iy+UPB_SFAT##+1) ;DE=Sectors per fat - ld b,(iy+UPB_NFAT##) ;B=Number of FATs - ld hl,0 -AA_SUM_FATS: - add hl,de - djnz AA_SUM_FATS ;Make HL=Total FAT sectors count - ld c,(iy+UPB_RES##) - ld b,(iy+UPB_RES##+1) - add hl,bc ;Now HL=First root directory sector ;WIP - - ld de,(TMP_SEC##) ;Set the absolute sector number - add hl,de ;for the start of root directory - ld (TMP_SEC##),hl - ld (TMP_FROOT##),hl - ld hl,0 - ld de,(TMP_SEC##+2) - adc hl,de - ld (TMP_SEC##+2),hl - ld (TMP_FROOT##+2),hl - - ld e,(iy+UPB_NDIR##) ;Same some extra data that we'll need - ld d,(iy+UPB_NDIR##+1) ;if we enter in disk emulation mode - ld (TMP_NDIR##),de - ld a,(iy+UPB_CS##) - ld (TMP_CS##),a - - ld b,e ;(iy+UPB_NDIR##) ;Number of root directory entries - ld a,d ;(iy+UPB_NDIR##+1) ;Number of root directory entries - or a - jr z,AA_OK_ROOTNUM - ld b,254 -AA_OK_ROOTNUM: - - ;Outer loop: check all root directory sectors - -AA_MSXDOS2_SLOOP: - ld a,(TMPLUN##) - ld d,a - ld a,(TMPDEV##) - - push bc - ld b,d - call AA_RSEC - jp nz,AA_MSXDOS2_ERR - - ld b,16 ;Directory entries per sector - ld hl,($SECBUF##) - - ;Inner loop: check all entries in one sector - -AA_MSXDOS2_ELOOP: - pop af ;Total number of root dir entries - dec a - jp z,AA_NOMOREENT ;AA_NEXTPAR ;AA_LLOOP_NEXT - push af - - ld a,(NXT7##+2) - or a - jr z,SRCHNX2 ;Don't search NEXT_DSK.DAT if A=0 at input - - push hl - call GET_DISKID_HL - ld a,(hl) - pop hl - or a - jr nz,SRCHNX2 ;I'm not the primary controller - - di - in a,(0AAh) - and 0F0h - ;add 0 - out (0AAh),a - ei - in a,(0A9h) - and 1 - jp z,SRCHNX2 ;Don't search NEXT_DSK.DAT if key 0 is pressed - - push bc - push hl - ld de,EMUDAT - ld b,11 - dec hl -AA_EMU_CHKE: - inc hl - ld a,(de) - cp (hl) - inc de - jr nz,SRCHNXDAT - djnz AA_EMU_CHKE - - pop hl - push hl - push ix - push iy - call GO_EMU - pop iy - pop ix - or a - jr z,SRCHNXDAT - - ;There's a NEXT_DSK.DAT file and it had valid contents: - ;Stop the presses! We cancel everything since we've entered emulation mode. - - ld hl,(NXT7##+3) - ld sp,hl - ld a,2 - ret - -SRCHNXDAT: - pop hl - pop bc - -SRCHNX2: - push bc - ld de,MSXDOS2DAT - ld b,11 - dec hl -AA_MSXDOS2_CHKE: - inc hl - ld a,(de) - cp (hl) - inc de - jr nz,AA_MSXDOS2_NXTE - djnz AA_MSXDOS2_CHKE - - ld a,(NXT7##+2) - or a - jr z,AA_DO_FOUND - ld a,1 - ld (NXT7##+5),a - inc hl - jr AA_NXTE2 - -AA_DO_FOUND: - pop bc - pop bc -AA_DO_FOUND2: - ld hl,(BUF9##+5) - ld (BUF9##+1),hl - ld hl,(BUF9##+7) - ld (BUF9##+3),hl + jp nz,AA_PLOOP_NEXT + + ;* All checks ok, partition is good. + ; If it has the active flag set, go ahead and assign it. + ; Otherwise mark it as candidate. + + ld a,(ix+AAD_CURR_PART_STATUS_BYTE) + and 80h + jr z,AA_NOT_ACTIVE + + ld l,(ix+AAD_CURR_PART_SECTOR) + ld h,(ix+AAD_CURR_PART_SECTOR+1) + ld (ix+AAD_CAND_PART_SECTOR),l + ld (ix+AAD_CAND_PART_SECTOR+1),h + ld l,(ix+AAD_CURR_PART_SECTOR+2) + ld h,(ix+AAD_CURR_PART_SECTOR+3) + ld (ix+AAD_CAND_PART_SECTOR+2),l + ld (ix+AAD_CAND_PART_SECTOR+3),h + ld a,(ix+AAD_CURR_PART_DEVLUN) + ld (ix+AAD_CAND_PART_DEVLUN),a jp AA_DO_ASSIGN -AA_MSXDOS2_NXTE: - inc hl - djnz AA_MSXDOS2_NXTE -AA_NXTE2: - ld bc,32-11 - add hl,bc ;Make HL point to the next dir entry - - pop bc - dec b - jp nz,AA_MSXDOS2_ELOOP - - ld hl,1 - ld de,(TMP_SEC##) ;Increase root dir sector number - add hl,de - ld (TMP_SEC##),hl - ld hl,0 - ld de,(TMP_SEC##+2) - adc hl,de - ld (TMP_SEC##+2),hl - - pop bc - dec b - jp nz,AA_MSXDOS2_SLOOP - -AA_NOMOREENT: - ld a,(NXT7##+5) +AA_NOT_ACTIVE: + ld a,(ix+AAD_CAND_PART_DEVLUN) or a - jr nz,AA_DO_FOUND2 + jp nz,AA_PLOOP_NEXT -AA_NEXTPAR:: - ld a,(NXT4##+2) - or a - jr z,AA_LLOOP_NEXT + ld a,(ix+AAD_CURR_PART_DEVLUN) + ld (ix+AAD_CAND_PART_DEVLUN),a ;Valid partition: mark as candidate device - ld hl,0 - ld (TMP_SEC##),hl - ld (TMP_SEC##+2),hl - ld a,(TMPLUN##) - ld b,a - ld a,(TMPDEV##) - call AA_RSEC - jp nz,AA_LLOOP_NEXT ;Not ready + ld hl,(TMP_SEC##) ;If this is the first partition being examined, save its number + ld (ix+AAD_CAND_PART_SECTOR),l + ld (ix+AAD_CAND_PART_SECTOR+1),h + ld hl,(TMP_SEC##+2) + ld (ix+AAD_CAND_PART_SECTOR+2),l + ld (ix+AAD_CAND_PART_SECTOR+3),h - ld hl,(NXT4##) - ld a,(NXT4##+2) - ld b,a - jp AA_PLOOP_NEXT - -AA_MSXDOS2_ERR: - pop bc + jp AA_PLOOP_NEXT ;--- No suitable partitions in the current LUN, ; so jump to the next device or LUN AA_LLOOP_NEXT: - ld a,(NXT3##) - or a + bit AAFLAG_IS_AUTOASPART,(ix+AAD_FLAGS) jr nz,AA_LLOOP_END - ld a,(TMPLUN##) + ld a,(ix+AAD_LOOP_LUN_INDEX) inc a cp 8 jp nz,AA_LLOOP - ld a,(TMPDEV##) + ld a,(ix+AAD_LOOP_DEV_INDEX) inc a cp 8 jp nz,AA_DLOOP @@ -1432,7 +1361,7 @@ AA_LLOOP_END: ; If a candidate device was identified, use it, ; otherwise return an error - ld a,(BUF9##) + ld a,(ix+AAD_CAND_PART_DEVLUN) or a jr z,AA_END_NOFOUND @@ -1444,30 +1373,34 @@ AA_LLOOP_END: ld b,a ;B=LUN ld a,c and 111b ;A=Device - ld (TMPDEV##),a - ld a,b - ld (TMPLUN##),a + ld (ix+AAD_LOOP_DEV_INDEX),a + ld (ix+AAD_LOOP_LUN_INDEX),b jp AA_DO_ASSIGN AA_END_NOFOUND: ld a,1 ret ;Error, no suitable device/partition found - ;--- A suitable device has been found. + ;--- A suitable device has been found (the candidate device). ; Assign it to the drive. AA_DO_ASSIGN: + ld l,(ix+AAD_UNIT_DESCRIPTOR) + ld h,(ix+AAD_UNIT_DESCRIPTOR+1) + push hl + pop iy + ld a,(DOS_VER##) or a jr z,AA_DO_ASSDOS1 - set UF_FOK,(ix+UD_DFLAGS##) ;Tell that the partition information is valid - ld b,(ix+UD_SLOT##) - ld c,(ix+UD_PHYS##) + set UF_FOK,(iy+UD_DFLAGS##) ;Tell that the partition information is valid + ld b,(iy+UD_SLOT##) + ld c,(iy+UD_PHYS##) push bc - ld a,(ix+UD_DFLAGS##) - push ix ;First clear the current unit descriptor + ld a,(iy+UD_DFLAGS##) + push iy ;First clear the current unit descriptor pop hl push hl pop de @@ -1475,92 +1408,142 @@ AA_DO_ASSIGN: ld (hl),0 ld bc,UD_SZ##-1 ldir - ld (ix+UD_DFLAGS##),a + ld (iy+UD_DFLAGS##),a pop bc - ld (ix+UD_SLOT##),b - ld (ix+UD_PHYS##),c - ld a,(TMPLUN##) - ld b,a - ld a,(TMPDEV##) - ld (ix+UD_LI##),b - ld (ix+UD_DI##),a - ld (ix+UD_SEG##),0FFh - - ld hl,(BUF9##+1) - ld (ix+UD_FSEC##),l - ld (ix+UD_FSEC##+1),h - ld hl,(BUF9##+3) - ld (ix+UD_FSEC##+2),l - ld (ix+UD_FSEC##+3),h - - ld (ix+UD_CDIR##+1),0FFh ;set current dir -ve => root - ld (ix+UD_CDIR##),0FFh - - ld a,(BUF9##) ;Retrieve removable unit flag + ld (iy+UD_SLOT##),b + ld (iy+UD_PHYS##),c + ld b,(ix+AAD_LOOP_LUN_INDEX) + ld a,(ix+AAD_LOOP_DEV_INDEX) + ld (iy+UD_LI##),b + ld (iy+UD_DI##),a + ld (iy+UD_SEG##),0FFh + + ld l,(ix+AAD_CAND_PART_SECTOR) + ld h,(ix+AAD_CAND_PART_SECTOR+1) + ld (iy+UD_FSEC##),l + ld (iy+UD_FSEC##+1),h + ld l,(ix+AAD_CAND_PART_SECTOR+2) + ld h,(ix+AAD_CAND_PART_SECTOR+3) + ld (iy+UD_FSEC##+2),l + ld (iy+UD_FSEC##+3),h + + ld (iy+UD_CDIR##+1),0FFh ;set current dir -ve => root + ld (iy+UD_CDIR##),0FFh + + ld a,(ix+AAD_CAND_PART_DEVLUN) ;Retrieve removable unit flag rlca rlca rlca and 4 or UFM_DB ;Set "device based driver" - or (ix+UD_DFLAGS##) ;Because the "FSEC OK" flag has already its value - ld (ix+UD_DFLAGS##),a + or (iy+UD_DFLAGS##) ;Because the "FSEC OK" flag has already its value + ld (iy+UD_DFLAGS##),a ld hl,$DPBLIST## - ld c,(ix+UD_PHYS##) + ld c,(iy+UD_PHYS##) dec c sla c ld b,0 add hl,bc ld a,(hl) - ld (ix+UD_DPB##),a + ld (iy+UD_DPB##),a inc hl ld a,(hl) - ld (ix+UD_DPB##+1),a + ld (iy+UD_DPB##+1),a xor a ret AA_DO_ASSDOS1: - ld a,(TMPDEV##) - ld (ix+UD1_DI##),a - ld a,(TMPLUN##) - ld (ix+UD1_LI##),a - ld hl,(BUF9##+1) - ld (ix+UD1_FSEC##),l - ld (ix+UD1_FSEC##+1),h - ld hl,(BUF9##+3) - ld (ix+UD1_FSEC##+2),l - ld (ix+UD1_FSEC##+3),h + ld a,(ix+AAD_LOOP_DEV_INDEX) + ld (iy+UD1_DI##),a + ld a,(ix+AAD_LOOP_LUN_INDEX) + ld (iy+UD1_LI##),a + ld l,(ix+AAD_CAND_PART_SECTOR) + ld h,(ix+AAD_CAND_PART_SECTOR+1) + ld (iy+UD1_FSEC##),l + ld (iy+UD1_FSEC##+1),h + ld l,(ix+AAD_CAND_PART_SECTOR+2) + ld h,(ix+AAD_CAND_PART_SECTOR+3) + ld (iy+UD1_FSEC##+2),l + ld (iy+UD1_FSEC##+3),h xor a ret -MSXDOS2DAT: - db "NEXTOR DAT" -EMUDAT: - db "NEXT_DSKDAT" -;This subroutine reads a sector from the device to SECBUF. + ;Try to enter emulation mode from data in RAM + ;Returns A=1 on success, 0 on failure + +TRY_RAM_EMU: + call GET_P2## + ld b,a + ld a,(P2_TPA##) + call PUT_P2## + + ld hl,EMU_RAM_ADDRESS + ld de,EMUDATASIG + call STRCOMP + jr nz,TRY_RAM_EMU_NO_SIG + + xor a ;Disable emulation for next boot + ld (EMU_RAM_ADDRESS),a ;(in case the code of the emulated disk doesn't do it itself) + + push bc ;Save original page 2 segment + + ld bc,(0F348h) + push ix + ld ix,EMU_RAM_ADDRESS+10h + ld a,(ix) + ld b,(ix+1) + ld e,(ix+2) + ld d,(ix+3) + ld l,(ix+4) + ld h,(ix+5) + + pop ix + + ex (sp),hl + push af + ld a,h ;Restore original page 2 segment + call PUT_P2## + pop af + ex (sp),hl + inc sp ;Discard saved segment number without affecting any register + inc sp + + jp GO_EMU + +TRY_RAM_EMU_NO_SIG: + ld a,b ;Previous segment + call PUT_P2## + xor a + ret + + +;This subroutine reads (AA_RSEC) or writes (AA_WSEC) a sector from the device to SECBUF. ;Input: A = Device index ; B = LUN -; IX = Address of unit descriptor +; C = Driver slot ; (TMP_SEC) = sector number ;Output: NZ on error ;Preserves IX +AA_WSEC: + scf + jr AA_DOSEC + AA_RSEC: - push af - ld a,(ix+UD_SLOT##) - ld_iyh_a - pop af + or a +AA_DOSEC: + ld_iyh_c ld hl,DEV_RW## ld (BK4_ADD##),hl ld c,b ld b,1 ld hl,($SECBUF##) ld de,TMP_SEC## - or a push ix ld ix,CALDRV## call CALSLT ;Call DEV_RW @@ -1698,99 +1681,54 @@ upb_not_found: ;If anything was wrong with ret ; Z-flag clear. -; This routine accepts in HL a pointer to the directory entry of the -; NEXT_DSK.DAT file and does all the job of entering in disk emulation mode. +; This routine does all the job of entering in disk emulation mode +; given the pointer to the emulation data file that is passed as follows: +; +; A = Device index +; B = LUN index +; C = Driver slot number +; HLDE = Absolute device sector where the file starts ; ; It first reads the contents of the file (only the first sector) ; and check that it has the expected structure. If this is not true, ; or if there is an error when reading the file, it does nothing ; and returns with A=0. ; -; Otherwise, it builds the work area in the same temporary buffer where -; the device-drivers table is generated when booting normally in DOS 1 mode, -; then returns with A=1. The format of the table is as follows, note that -; it is mostly compatible with a DOS 1 device-drivers table with just one entry: -; -; +0: Device index of current disk image file -; Bit 7 is kept set to 1 to indicate that we are in disk emulation mode -; +1: Controller slot (always the primary controller) -; +2: Device + 16 * logical unit number for NEXT_DSK.DAT -; Bit 7 is set after the current image file is changed -; and reset again when disk change is checked -; +3: Device index of disk image file -; +4: Logical unit number of disk image file -; +5-8: First sector of disk image file -; +9-10: Disk image file size in sectors -; +11: Number of entries in the disk images table in NEXT_DSK.DAT -; +12-15: Device sector number of NEXT_DSK.DAT contents -; -; The definitve address of the work area as read from NEXT_DSK.DAT is temporarily -; appended at the end of this table, so that either it will be moved to this place +; Otherwise, it builds the work area in EMU_TMP (the same temporary buffer where +; the device-drivers table is generated when booting normally in DOS 1 mode), +; then returns with A=1. The format of the table is defined in kvar.mac (DSK_*). +; +; The definitve address of the work area as read from the emulation data file is temporarily +; stored in EMU_WK_AREA, so that either the table it will be moved to this place ; or, if it is zero, the work area will be properly allocated. -GO_EMU:: - - ;--- Calculate data sector of NEXT_DSK.DAT +GO_EMU: - push ix - push hl - pop ix - ld e,(ix+DR_CLU##) - ld d,(ix+DR_CLU##+1) ;DE = First cluster number of file - pop ix - dec de - dec de ;DE = Zero-based cluster index - - ld hl,0 - ld a,(TMP_CS##) ;Sectors per cluster -GOEMU2: - rra - jp c,GOEMU3 - sla e - rl d - rl l - rl h - jr GOEMU2 -GOEMU3: - push hl ;HLDE = File sector, relative to first data sector - - ld hl,(TMP_NDIR##) ;HL = Number of root directory entries - SRL H ;Divide by 16 -> HL = Number of root directory sectors - RR L - SRL H - RR L - SRL H - RR L - SRL H - RR L - - push hl - pop bc ;BC = Number of root directory sectors - - ex de,hl ;HL = Relative file sector, low - ld de,(TMP_FROOT##) ;DE = Absolute first root dir sector, low - add hl,de - ld (TMP_SEC##),hl - pop de ;DE = Relative file sector, high - ld hl,(TMP_FROOT##+2) - adc hl,de - ld (TMP_SEC##+2),hl + ;--- Store device and LUN of the emulation data file - ld hl,(TMP_SEC##) - add hl,bc - ld (TMP_SEC##),hl - ld (0F980h+12),hl - ld hl,(TMP_SEC##+2) - ld de,0 - adc hl,de - ld (TMP_SEC##+2),hl - ld (0F980h+14),hl + push af + push bc + ld c,a ;Dev + ld a,b ;LUN + rlca + rlca + rlca + rlca + and 0F0h + ld b,a + ld a,c ;Dev + and 0Fh + or b + ld (EMU_TMP##+EMU_DEVLUN##),a ;dev+lun of emulation data file + pop bc + pop af ;--- Read file contents - ld a,(TMPLUN##) - ld b,a - ld a,(TMPDEV##) + ld (EMU_TMP##+EMU_FSEC##),de + ld (EMU_TMP##+EMU_FSEC##+2),hl + ld (TMP_SEC##),de + ld (TMP_SEC##+2),hl call AA_RSEC ld a,0 ret nz @@ -1803,18 +1741,10 @@ GOEMU3: push ix pop hl - ld de,NDATSIG -GOEMU_SIG1: - ld a,(de) - cp (hl) - ld a,0 + ld de,EMUDATASIG + call STRCOMP + ld a,0 ret nz - or a - jr z,GOEMU_SIG2 - inc hl - inc de - jr GOEMU_SIG1 -GOEMU_SIG2: ;> Number of entries must be between 1 and 32 @@ -1852,36 +1782,31 @@ GOEMU_WAOK: ;--- Process file contents - ld iy,0F980h + ld iy,EMU_TMP## ;> Basic data - ld a,(0F348h) ;Controller slot - ld (iy+1),a ld a,(ix+18) ;Work area address, low - ld (iy+16),a + ld (EMU_WK_AREA##),a ld a,(ix+19) ;Work area address, high - ld (iy+17),a + ld (EMU_WK_AREA##+1),a ld a,(ix+16) - ld (iy+11),a ;Number of entries in table - - ld a,(TMPLUN##) - rlca - rlca - rlca - rlca - and 0F0h - ld b,a - ld a,(TMPDEV##) - and 0Fh - or b - ld (iy+2),a ;dev+lun of NEXT_DSK.DAT + ld (iy+DSK_COUNT##),a ;Number of entries in table ;> Current file data ld a,(ix+17) ;Boot file index - ld (iy),a + ld (iy+DSK_IDX##),a set 7,(iy) + + ld c,a + ld a,(I_AM_RUSSIAN##) + or a + jr z,GOEMU_NORUS + set 6,(iy) +GOEMU_NORUS: + ld a,c + dec a add a,a ;Each entry is 8 bytes add a,a @@ -1893,17 +1818,33 @@ GOEMU_WAOK: push ix pop bc add hl,bc ;HL = Pointer to boot file data - ld de,0F980h+3 + ld de,EMU_TMP##+DSK_DEV## ld bc,8 ldir -ekix:: + + ld a,(iy+DSK_DEV##) ;set DSK_DEV and DSK_LUN as same of data file if 0 + or a + jr nz,GOEMU_END + ld a,(iy+EMU_DEVLUN##) + ld b,a + and 00000111b + ld (iy+DSK_DEV##),a + ld a,b + rrca + rrca + rrca + rrca + and 00000111b + ld (iy+DSK_LUN##),a + ;--- All done +GOEMU_END: ld a,1 - ld (PROCNM+9),a + ld (IN_EMU##),a ret -NDATSIG: db "Nextor DSK file",0 +EMUDATASIG: db "NEXTOR_EMU_DATA",0 ;----------------------------------------------------------------------------- ; @@ -1923,43 +1864,43 @@ NDATSIG: db "Nextor DSK file",0 ld (iy+0),a ;Media ID ld hl,512 - ld (iy+1),l ;Tamanyo sector + ld (iy+1),l ;Sector size ld (iy+2),h ld a,15 - ld (iy+3),a ;(Tamanyo sector/32)-1 + ld (iy+3),a ;(Sector size/32)-1 ld a,4 - ld (iy+4),a ;Num unos en el anterior + ld (iy+4),a ;Bits set to 1 in previous value ld a,(ix+13) dec a - ld (iy+5),a ;(Sectores por cluster)-1 + ld (iy+5),a ;(Sectors per cluster)-1 ld b,0 MKDPB_CNT1S: inc b rrca jr c,MKDPB_CNT1S - ld (iy+6),b ;Num unos en el anterior+1 + ld (iy+6),b ;Bits set to 1 in previous value+1 - ld a,(ix+14) ;Sector inicio FAT=Sectores reservados + ld a,(ix+14) ;FAT first sector=reserved sectors ld (iy+7),a ld a,(ix+15) ld (iy+8),a - ld a,(ix+16) ;Numero FATs + ld a,(ix+16) ;Number of FATs ld (iy+9),a ld a,(ix+18) or a ld a,254 jr nz,DIRENT - ld a,(ix+17) ;Num entradas directorio + ld a,(ix+17) ;Number of directory entries DIRENT: ld (iy+10),a - ld e,(ix+22) ;Sectores por FAT - ld (iy+15),e ;(2 bytes en sector 0, 1 byte en DPB) + ld e,(ix+22) ;Sectors per FAT + ld (iy+15),e ;(2 bytes in sector 0, 1 byte in DPB) - ;1er sector directorio=(Sectores reservados+Num FATs*Sectores por FAT) + ;1st sector directory=(Reserved sectors+Number of FATs*Sectors per FAT) ld d,0 ld b,(ix+16) @@ -1976,10 +1917,10 @@ CALC_1SECDIR: ld (iy+17),h ex de,hl - ;1er sector datos=(Sectores reservados+Num FATs*Sectores por FAT)+ - ; (32*Entradas dir/512) + ;1er data sector =(Reserved sectors+Num FATs*Sectors per FAT)+ + ; (32*Directory entries/512) - ld l,(ix+17) ;Calcula Entradas dir/16 + ld l,(ix+17) ;Calculate directory entries/16 ld h,(ix+18) ld b,4 CALC_1SECDAT: @@ -1991,7 +1932,7 @@ CALC_1SECDAT: ld (iy+11),l ld (iy+12),h - ;Num clusters+1=((Sectores totales-1er sector datos)/Sectores por cluster)+1 + ;Num clusters+1=((Total sectors-1st data sector)/Sectors per cluster)+1 push hl pop bc ;DE=1st data sector @@ -2013,9 +1954,9 @@ OK_SMALLSEC: sbc hl,bc ex de,hl ;DEHL=total sectors - 1st data sector - ld a,(ix+13) ;Divide teniendo en cuenta que + ld a,(ix+13) ;Divide taking in account that CALC_NUMCLUS: - rrca ;sectores por cluster es potencia de 2 + rrca ;sectors por cluster is a power of 2 jr c,CALC_NUMCLUS1 sra d rr e @@ -2995,10 +2936,11 @@ MAP_DEF_DEVB: ld b,0 ld c,(ix+UD_REL##) + xor a push hl call ASK_DRIVE_CONFIG pop hl - dec a + cp 1 jr z,MAP_DEF_DEVB_NOCFG ;Driver did not provide config or a ld a,0 @@ -3010,7 +2952,7 @@ MAP_DEF_DEVB_NOCFG: push hl push ix pop hl - xor a + ld d,0 call AUTO_ASSIGN pop hl or a @@ -3746,6 +3688,7 @@ MAPDOS1_DEF: ld c,(ix+UD1_REL##) res 7,c ;Ignore "media changed" flag ld b,1 + xor a call ASK_DRIVE_CONFIG pop ix pop hl @@ -3767,6 +3710,7 @@ MAPDOS1_DEF_NOCFG: ;No config provided by driver, use AUTO_ASSIGN push ix pop hl push hl + ld d,0 call AUTO_ASSIGN pop ix pop hl @@ -3788,7 +3732,7 @@ if 0 pop hl push ix push hl - xor a + ld d,0 call AUTO_ASSIGN pop hl ld (hl),0FFh ;Mark FAT buffer as invalid again @@ -5953,7 +5897,8 @@ GET_DISKID_HL: ; Output: A = number of drives. push bc - call SCAN_5_KEY + ld a,(BOOTKEYS##) ;5 key pressed? + and 00100000b pop bc ld c,a @@ -6050,7 +5995,8 @@ DRVS1LOOP: cp 100b ;Provides config? jr nz,DRVS1NX3 ;No: skip but check "5" key - call SCAN_5_KEY + ld a,(BOOTKEYS##) ;5 key pressed? + and 00100000b ld c,a ld hl,DV_CONFIG## ld (BK4_ADD##),hl @@ -6078,7 +6024,7 @@ DRVS1NX2: ret DRVS1NX3: - call SCAN_5_KEY + ld a,(BOOTKEYS##) ;5 key pressed? and 00100000b ld b,1 jr nz,DRVS1CHG @@ -6200,7 +6146,7 @@ CMIU_END: ;--- DOS 1 version CMIU_DOS1: - ld iy,(DVB_TABLE##) + ld iy,(DVB_TABLE) ld b,(iy) ld a,b or a @@ -6264,14 +6210,19 @@ CMIU1_NEXT: ; Must have UD_SLOT set ; C = Relative unit for the drive ; B = 0 for DOS 2 mode, 1 for DOS 1 mode +; A = 1 to enter disk emulation mode ; Output: A = 0 ok ; 1 driver did not provide info for that drive ; 2 driver provided info, but can't assign partition to drive +; 3 if disk emulation mode has been entered ; If A=0 or 2, sets UD_DI, UD_LI and UD_SEG in the unit descriptor ; If A=0, sets UF_FOK in UD_DFLAGS in the unit descriptor +; If A=3, returns B, C, HLDE from AUTO_ASPART ; Modifies: AF, BC, DE, HL, IY ASK_DRIVE_CONFIG: + ld d,a + push de push bc ;BC=DOS mode and relative unit ld a,(ix+UD_SLOT##) ld_iyh_a @@ -6283,6 +6234,7 @@ ASK_DRIVE_CONFIG: call CALSLT pop ix pop hl ;H=DOS mode and relative unit + pop de ;D=A at input or a ret nz @@ -6306,8 +6258,11 @@ ASKDRVCFG_NEXT: push ix pop hl push hl + ;ld a,d call AUTO_ASPART pop ix + cp 2 + jr z,ASKDRVCFG_GOEMU pop bc ;B=DOS mode dec a @@ -6320,6 +6275,12 @@ ASKDRVCFG_NEXT: xor a ret +ASKDRVCFG_GOEMU: + pop af + ld a,3 + ret + + ;---------------------------- ; ; Read the DV_TYPE byte from a driver @@ -6335,12 +6296,20 @@ GET_DV_TYPE: call CALSLT## ret -SCAN_5_KEY: - xor a - call SNSMAT - and 00100000b - xor 00100000b ;A=00100000b if "5" key pressed, 0 if not - ret + +; Compare zero terminated strings pointed by HL and DE +; Return Z if they are equal, NZ if not +; Modifies AF, HL, DE + +STRCOMP: + ld a,(de) + cp (hl) + ret nz + or a + ret z + inc hl + inc de + jr STRCOMP finish end diff --git a/source/kernel/bank5/AsmCall.h b/source/kernel/bank5/AsmCall.h deleted file mode 100644 index 53b3bcc6..00000000 --- a/source/kernel/bank5/AsmCall.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __ASMCALL_H -#define __ASMCALL_H - -#define AsmCall(dir, regs, in, out) AsmCallAlt(dir, regs, in, out, 0) - -void DriverCall(byte slot, uint routineAddress); -void DosCall(byte function, register_usage outRegistersDetail); -void SwitchSystemBankThenCall(int routineAddress, register_usage outRegistersDetail); -void AsmCallAlt(uint address, Z80_registers* regs, register_usage inRegistersDetail, register_usage outRegistersDetail, int alternateAf); - -#endif //__ASMCALL_H \ No newline at end of file diff --git a/source/kernel/bank5/compfdsk.bat b/source/kernel/bank5/compfdsk.bat index ac1917fb..0df28b76 100644 --- a/source/kernel/bank5/compfdsk.bat +++ b/source/kernel/bank5/compfdsk.bat @@ -3,11 +3,11 @@ echo Compiling, please be patient... sdasz80 -o fdisk_crt0.rel fdisk_crt0.s if errorlevel 1 goto :error -sdcc --code-loc 0x4120 --data-loc 0x8020 -mz80 --disable-warning 196 --disable-warning 84 --disable-warning 85 --max-allocs-per-node 10000 --allow-unsafe-read --opt-code-size --no-std-crt0 fdisk_crt0.rel fdisk.c +sdcc --code-loc 0x4120 --data-loc 0x8020 -mz80 --disable-warning 196 --disable-warning 84 --disable-warning 85 --max-allocs-per-node 1000 --allow-unsafe-read --opt-code-size --no-std-crt0 fdisk_crt0.rel fdisk.c if errorlevel 1 goto :error hex2bin -e dat fdisk.ihx -sdcc --code-loc 0x4120 --data-loc 0xA000 -mz80 --disable-warning 196 --disable-warning 84 --disable-warning 85 --max-allocs-per-node 10000 --allow-unsafe-read --opt-code-size --no-std-crt0 fdisk_crt0.rel fdisk2.c +sdcc --code-loc 0x4120 --data-loc 0xA000 -mz80 --disable-warning 196 --disable-warning 84 --disable-warning 85 --max-allocs-per-node 1000 --allow-unsafe-read --opt-code-size --no-std-crt0 fdisk_crt0.rel fdisk2.c if errorlevel 1 goto :error hex2bin -e dat fdisk2.ihx diff --git a/source/kernel/bank5/drivercall.c b/source/kernel/bank5/drivercall.c new file mode 100644 index 00000000..c7a07ac0 --- /dev/null +++ b/source/kernel/bank5/drivercall.c @@ -0,0 +1,40 @@ +#include "drivercall.h" +#include "../../tools/C/AsmCall.h" +#include "../../tools/C/dos.h" + +//The following is required in the main program: +//byte ASMRUT[4]; +//byte OUT_FLAGS; +//Z80_registers regs; + +void DriverCall(byte slot, uint routineAddress) +{ + byte registerData[8]; + int i; + + memcpy(registerData, ®s, 8); + + regs.Bytes.A = slot; + regs.Bytes.B = 0xFF; + regs.UWords.DE = routineAddress; + regs.Words.HL = (int)registerData; + + DosCallFromRom(_CDRVR, REGS_ALL); + + if(regs.Bytes.A == 0) { + regs.Words.AF = regs.Words.IX; + } +} + +void DosCallFromRom(byte function, register_usage outRegistersDetail) +{ + regs.Bytes.C = function; + SwitchSystemBankThenCall((int)0xF37D, outRegistersDetail); +} + + +void SwitchSystemBankThenCall(int routineAddress, register_usage outRegistersDetail) +{ + *((int*)BK4_ADD) = routineAddress; + AsmCall(CALLB0, ®s, REGS_ALL, outRegistersDetail); +} diff --git a/source/kernel/bank5/drivercall.h b/source/kernel/bank5/drivercall.h new file mode 100644 index 00000000..7f0e33a3 --- /dev/null +++ b/source/kernel/bank5/drivercall.h @@ -0,0 +1,11 @@ +#ifndef __DRIVERCALL_H +#define __DRIVERCALL_H + +#include "../../tools/C/types.h" + +void DriverCall(byte slot, uint routineAddress); +void DosCall(byte function, Z80_registers* regs, register_usage inRegistersDetail, register_usage outRegistersDetail); +void DosCallFromRom(byte function, register_usage outRegistersDetail); +void SwitchSystemBankThenCall(int routineAddress, register_usage outRegistersDetail); + +#endif diff --git a/source/kernel/bank5/fdisk.c b/source/kernel/bank5/fdisk.c index 4665e66e..bc91d452 100644 --- a/source/kernel/bank5/fdisk.c +++ b/source/kernel/bank5/fdisk.c @@ -15,13 +15,13 @@ #include #include #include -#include "asm.h" -#include "system.h" -#include "dos.h" -#include "types.h" -#include "partit.h" +#include "../../tools/C/system.h" +#include "../../tools/C/dos.h" +#include "../../tools/C/types.h" +#include "../../tools/C/asmcall.h" +#include "drivercall.h" +#include "../../tools/C/partit.h" #include "fdisk.h" -#include "asmcall.h" //#define FAKE_DEVICE_INFO //#define FAKE_DRIVER_INFO @@ -87,9 +87,9 @@ ulong fakeDeviceSizeInK; #define HideCursor() print("\x1Bx5") #define DisplayCursor() print("\x1By5") -#define CursorDown() putchar('\x1F') -#define CursorUp() putchar('\x1E') -#define ClearScreen() putchar('\x0C') +#define CursorDown() chput('\x1F') +#define CursorUp() chput('\x1E') +#define ClearScreen() chput('\x0C') #define HomeCursor() print("\x0D\x1BK") #define DeleteToEndOfLine() print("\x1BK") #define DeleteToEndOfLineAndCursorDown() print("\x1BK\x1F"); @@ -105,16 +105,17 @@ void ShowDeviceSelectionScreen(); void GetDevicesInformation(); void EnsureMaximumStringLength(char* string, int maxLength); void GoLunSelectionScreen(byte deviceIndex); -void InitializePartitionningVariables(byte lunIndex); +void InitializePartitioningVariables(byte lunIndex); void ShowLunSelectionScreen(); void PrintSize(ulong sizeInK); byte GetRemainingBy1024String(ulong value, char* destination); void GetLunsInformation(); void PrintDeviceInfoWithIndex(); -void GoPartitionningMainMenuScreen(); +void GoPartitioningMainMenuScreen(); bool GetYesOrNo(); byte GetDiskPartitionsInfo(); void ShowPartitions(); +void TogglePartitionActive(byte partitionIndex); void PrintOnePartitionInfo(partitionInfo* info); void DeleteAllPartitions(); void RecalculateAutoPartitionSize(bool setToAllSpaceAvailable); @@ -130,8 +131,9 @@ byte CreateFatFileSystem(ulong firstDeviceSector, ulong fileSystemSizeInK); void CalculateFatFileSystemParameters(ulong fileSystemSizeInK, dosFilesystemParameters* parameters); #endif bool WritePartitionTable(); -void PreparePartitionningProcess(); +void PreparePartitioningProcess(); byte CreatePartition(int index); +byte ToggleStatusBit(byte partitionTableEntryIndex, ulong partitionTablesector); bool ConfirmDataDestroy(char* action); void ClearInformationArea(); void GetDriversInformation(); @@ -147,7 +149,7 @@ void Locate(byte x, byte y); void LocateX(byte x); void PrintCentered(char* string); void PrintStateMessage(char* string); -void putchar(char ch); +void chput(char ch); void print(char* string); int CallFunctionInExtraBank(int functionNumber, void* parametersBuffer); @@ -206,7 +208,7 @@ void DoFdisk() SaveOriginalScreenConfiguration(); ComposeWorkScreenConfiguration(); SetScreenConfiguration(¤tScreenConfig); - InitializeWorkingScreen("Nextor disk partitionning tool"); + InitializeWorkingScreen("Nextor disk partitioning tool"); GoDriverSelectionScreen(); @@ -502,9 +504,9 @@ void GoLunSelectionScreen(byte deviceIndex) return; } else { key -= '0'; - if(key >= 1 && key <= MAX_LUNS_PER_DEVICE && luns[key - 1].suitableForPartitionning) { - InitializePartitionningVariables(key); - GoPartitionningMainMenuScreen(); + if(key >= 1 && key <= MAX_LUNS_PER_DEVICE && luns[key - 1].suitableForPartitioning) { + InitializePartitioningVariables(key); + GoPartitioningMainMenuScreen(); break; } } @@ -513,7 +515,7 @@ void GoLunSelectionScreen(byte deviceIndex) } -void InitializePartitionningVariables(byte lunIndex) +void InitializePartitioningVariables(byte lunIndex) { selectedLunIndex = lunIndex - 1; selectedLun = &luns[selectedLunIndex]; @@ -556,7 +558,7 @@ void ShowLunSelectionScreen() currentLun = &luns[0]; for(i = 0; i < MAX_LUNS_PER_DEVICE; i++) { - if(currentLun->suitableForPartitionning) { + if(currentLun->suitableForPartitioning) { printf("\x1BK%i. Size: ", i + 1); PrintSize(currentLun->sectorCount / 2); NewLine(); @@ -644,13 +646,13 @@ void GetLunsInformation() currentLun->sectorCount = fakeDeviceSizeInK * 2; } #endif - currentLun->suitableForPartitionning = + currentLun->suitableForPartitioning = (regs.Bytes.A == 0) && (currentLun->mediumType == BLOCK_DEVICE) && (currentLun->sectorSize == 512) && (currentLun->sectorCount >= MIN_DEVICE_SIZE_IN_K * 2) && ((currentLun->flags & (READ_ONLY_LUN | FLOPPY_DISK_LUN)) == 0); - if(currentLun->suitableForPartitionning) { + if(currentLun->suitableForPartitioning) { availableLunsCount++; } @@ -683,7 +685,7 @@ void PrintTargetInfo() } -void GoPartitionningMainMenuScreen() +void GoPartitioningMainMenuScreen() { char key; byte error; @@ -836,7 +838,7 @@ byte GetDiskPartitionsInfo() regs.Bytes.E = selectedLunIndex + 1; regs.Bytes.H = primaryIndex; regs.Bytes.L = extendedIndex; - DosCall(_GPART, REGS_ALL); + DosCallFromRom(_GPART, REGS_ALL); error = regs.Bytes.A; if(error == 0) { if(regs.Bytes.B == PARTYPE_EXTENDED) { @@ -845,6 +847,7 @@ byte GetDiskPartitionsInfo() currentPartition->primaryIndex = primaryIndex; currentPartition->extendedIndex = extendedIndex; currentPartition->partitionType = regs.Bytes.B; + currentPartition->status = regs.Bytes.C; ((uint*)&(currentPartition->sizeInK))[0] = regs.UWords.IY; ((uint*)&(currentPartition->sizeInK))[1] = regs.UWords.IX; currentPartition->sizeInK /= 2; @@ -872,30 +875,60 @@ void ShowPartitions() int lastPartitionIndexToShow; bool isLastPage; bool isFirstPage; + bool allPartitionsArePrimary; byte key; partitionInfo* currentPartition; - Locate(0, screenLinesCount-1); - DeleteToEndOfLine(); - PrintCentered("Press ESC to return"); + if(partitionsExistInDisk) { + allPartitionsArePrimary = true; + for(i=0; iextendedIndex != 0) { + allPartitionsArePrimary = false; + break; + } + } + } else { + allPartitionsArePrimary = false; + } while(true) { isFirstPage = (firstShownPartitionIndex == 1); isLastPage = (firstShownPartitionIndex + PARTITIONS_PER_PAGE) > partitionsCount; lastPartitionIndexToShow = isLastPage ? partitionsCount : firstShownPartitionIndex + PARTITIONS_PER_PAGE - 1; - Locate(0, screenLinesCount-1); - print(isFirstPage ? " " : "<--"); + Locate(0, screenLinesCount-1); + DeleteToEndOfLine(); + if(isFirstPage) { + sprintf(buffer, partitionsCount == 1 ? "1" : partitionsCount > 9 ? "1-9" : "1-%i", partitionsCount); + if(isLastPage) { + sprintf(buffer+4, "ESC = return, %s = toggle active (*)", buffer); + } else { + sprintf(buffer+4, "ESC=back, %s=toggle active (*)", buffer); + } + PrintCentered(buffer+4); + } else { + PrintCentered("Press ESC to return"); + } - Locate(currentScreenConfig.screenWidth - 4, screenLinesCount-1); - print(isLastPage ? " " : "-->"); + if(!(isFirstPage && isLastPage)) { + Locate(0, screenLinesCount-1); + print(isFirstPage ? " " : "<--"); + + Locate(currentScreenConfig.screenWidth - 4, screenLinesCount-1); + print(isLastPage ? " " : "-->"); + } ClearInformationArea(); Locate(0, 3); if(partitionsCount == 1) { PrintCentered(partitionsExistInDisk ? "One partition found on device" : "One new partition defined"); } else { - sprintf(buffer, partitionsExistInDisk ? "%i partitions found on device" : "%i new partitions defined", partitionsCount); + if(allPartitionsArePrimary) { + sprintf(buffer, partitionsExistInDisk ? "%i primary partitions found on device" : "%i new primary partitions defined", partitionsCount); + } else { + sprintf(buffer, partitionsExistInDisk ? "%i partitions found on device" : "%i new partitions defined", partitionsCount); + } PrintCentered(buffer); } NewLine(); @@ -925,23 +958,72 @@ void ShowPartitions() } else if(key == CURSOR_RIGHT && !isLastPage) { firstShownPartitionIndex += PARTITIONS_PER_PAGE; break; - } + } else if(isFirstPage && key>=KEY_1 && keystatus ^= 0x80; + return; + } + + status = partition->status; + primaryIndex = partition->primaryIndex; + extendedIndex = partition->extendedIndex; + + sprintf(buffer, "%set active bit of partition %i? (y/n) ", status & 0x80 ? "Res" : "S", partitionIndex + 1); + PrintStateMessage(buffer); + if(!GetYesOrNo()) { + return; + } + + regs.Bytes.A = selectedDriver->slot; + regs.Bytes.B = 0xFF; + regs.Bytes.D = selectedDeviceIndex; + regs.Bytes.E = selectedLunIndex + 1; + regs.Bytes.H = partition->primaryIndex | 0x80; + regs.Bytes.L = partition->extendedIndex; + DosCallFromRom(_GPART, REGS_ALL); + if(regs.Bytes.A != 0) { + return; + } + + ((uint*)&(partitionTableEntrySector))[0] = regs.UWords.DE; + ((uint*)&(partitionTableEntrySector))[1] = regs.UWords.HL; + + PreparePartitioningProcess(); //Needed to set up driver slot, device index, etc + error = ToggleStatusBit(extendedIndex == 0 ? primaryIndex-1 : 0, partitionTableEntrySector); + if(error == 0) { + partition->status ^= 0x80; + } else { + sprintf(buffer, "Error when accessing device: %i", error); + ClearInformationArea(); + Locate(0,7); + PrintCentered(buffer); + PrintStateMessage("Press any key..."); + WaitKey(); + } + + return; +} void PrintOnePartitionInfo(partitionInfo* info) { - if(!partitionsExistInDisk && partitionsCount <= 4) { - putchar(info->primaryIndex == 1 ? '1' : info->extendedIndex + 1 + '0'); - } else { - putchar(info->primaryIndex + '0'); - if(info->extendedIndex != 0) { - printf("-%i", info->extendedIndex); - } - } - print(": "); + printf("%c %i: ", info->status & 0x80 ? '*' : ' ', info->extendedIndex == 0 ? info->primaryIndex : info->extendedIndex + 1); + if(info->partitionType == PARTYPE_FAT12) { print("FAT12"); } else if(info->partitionType == PARTYPE_FAT16 || info->partitionType == PARTYPE_FAT16_SMALL || info->partitionType == PARTYPE_FAT16_LBA) { @@ -1050,7 +1132,7 @@ void AddPartition() buffer[0] = 6; regs.Words.DE = (int)buffer; - DosCall(_BUFIN, REGS_NONE); + DosCallFromRom(_BUFIN, REGS_NONE); lineLength = buffer[1]; if(lineLength == 0) { return; @@ -1106,9 +1188,10 @@ void AddAutoPartition() { partitionInfo* partition = &partitions[partitionsCount]; + partition->status = partitionsCount == 0 ? 0x80 : 0; partition->sizeInK = autoPartitionSizeInK; partition->partitionType = - partition->sizeInK > MAX_FAT12_PARTITION_SIZE_IN_K ? PARTYPE_FAT16 : PARTYPE_FAT12; + partition->sizeInK > MAX_FAT12_PARTITION_SIZE_IN_K ? PARTYPE_FAT16_LBA : PARTYPE_FAT12; if(partitionsCount == 0) { partition->primaryIndex = 1; partition->extendedIndex = 0; @@ -1198,7 +1281,7 @@ void PrintDosErrorMessage(byte code, char* header) regs.Bytes.B = code; regs.Words.DE = (int)buffer; - DosCall(_EXPLAIN, REGS_NONE); + DosCallFromRom(_EXPLAIN, REGS_NONE); if(strlen(buffer) > currentScreenConfig.screenWidth) { print(buffer); } else { @@ -1285,11 +1368,8 @@ bool WritePartitionTable() //masterBootRecord* mbr = (masterBootRecord*)buffer + 80; byte error; - if(partitionsCount <= 4) { - sprintf(buffer, "Create %i primary partitions on device", partitionsCount); - } else { - sprintf(buffer, "Create %i partitions on device", partitionsCount); - } + sprintf(buffer, "Create %i partitions on device", partitionsCount); + if(!ConfirmDataDestroy(buffer)) { return false; } @@ -1299,8 +1379,8 @@ bool WritePartitionTable() PrintStateMessage("Please wait..."); Locate(0, MESSAGE_ROW); - PrintCentered("Preparing partitionning process..."); - PreparePartitionningProcess(); + PrintCentered("Preparing partitioning process..."); + PreparePartitioningProcess(); for(i = 0; i < partitionsCount; i++) { Locate(0, MESSAGE_ROW); @@ -1326,7 +1406,7 @@ bool WritePartitionTable() } -void PreparePartitionningProcess() +void PreparePartitioningProcess() { byte* remoteCallParams = buffer; @@ -1337,7 +1417,7 @@ void PreparePartitionningProcess() *((partitionInfo**)&remoteCallParams[5]) = &partitions[0]; *((uint*)&remoteCallParams[7]) = luns[selectedLunIndex].sectorsPerTrack; - CallFunctionInExtraBank(f_PreparePartitionningProcess, remoteCallParams); + CallFunctionInExtraBank(f_PreparePartitioningProcess, remoteCallParams); } @@ -1350,6 +1430,15 @@ byte CreatePartition(int index) return (byte)CallFunctionInExtraBank(f_CreatePartition, remoteCallParams); } +byte ToggleStatusBit(byte partitionTableEntryIndex, ulong partitionTablesector) +{ + byte* remoteCallParams = buffer; + + remoteCallParams[0] = partitionTableEntryIndex; + *((ulong*)&remoteCallParams[1]) = partitionTablesector; + + return (byte)CallFunctionInExtraBank(f_ToggleStatusBit, remoteCallParams); +} bool ConfirmDataDestroy(char* action) { @@ -1416,7 +1505,7 @@ void GetDriversInformation() while(error == 0 && driverIndex <= MAX_INSTALLED_DRIVERS) { regs.Bytes.A = driverIndex; regs.Words.HL = (int)currentDriver; - DosCall(_GDRVR, REGS_AF); + DosCallFromRom(_GDRVR, REGS_AF); if((error = regs.Bytes.A) == 0 && (currentDriver->flags & (DRIVER_IS_DOS250 | DRIVER_IS_DEVICE_BASED) == (DRIVER_IS_DOS250 | DRIVER_IS_DEVICE_BASED))) { installedDriversCount++; TerminateRightPaddedStringWithZero(currentDriver->driverName, DRIVER_NAME_LENGTH); @@ -1451,7 +1540,7 @@ byte WaitKey() byte GetKey() { regs.Bytes.E = 0xFF; - DosCall(_DIRIO, REGS_AF); + DosCallFromRom(_DIRIO, REGS_AF); return regs.Bytes.A; } @@ -1505,7 +1594,7 @@ void PrintRuler() HomeCursor(); for(i = 0; i < currentScreenConfig.screenWidth; i++) { - putchar('-'); + chput('-'); } } @@ -1543,7 +1632,7 @@ void PrintStateMessage(char* string) } -void putchar(char ch) __naked +void chput(char ch) __naked { __asm push ix @@ -1591,5 +1680,6 @@ int CallFunctionInExtraBank(int functionNumber, void* parametersBuffer) } -#include "asmcall.c" -#include "printf.c" +#include "../../tools/C/printf.c" +#include "../../tools/C/asmcall.c" +#include "drivercall.c" \ No newline at end of file diff --git a/source/kernel/bank5/fdisk.h b/source/kernel/bank5/fdisk.h index 8799305c..ae4fe26e 100644 --- a/source/kernel/bank5/fdisk.h +++ b/source/kernel/bank5/fdisk.h @@ -3,7 +3,8 @@ #define f_CalculateFatFileSystemParameters 1 #define f_CreateFatFileSystem 2 -#define f_PreparePartitionningProcess 3 +#define f_PreparePartitioningProcess 3 #define f_CreatePartition 4 +#define f_ToggleStatusBit 5 #endif //__FDISK_H \ No newline at end of file diff --git a/source/kernel/bank5/fdisk2.c b/source/kernel/bank5/fdisk2.c index 0905f77e..757432eb 100644 --- a/source/kernel/bank5/fdisk2.c +++ b/source/kernel/bank5/fdisk2.c @@ -15,13 +15,13 @@ #include #include #include -#include "asm.h" -#include "system.h" -#include "dos.h" -#include "types.h" -#include "partit.h" +#include "../../tools/C/types.h" +#include "../../tools/C/system.h" +#include "../../tools/C/dos.h" +#include "../../tools/C/asmcall.h" +#include "drivercall.h" +#include "../../tools/C/partit.h" #include "fdisk.h" -#include "asmcall.h" byte sectorBuffer[512]; byte sectorBufferBackup[512]; @@ -39,6 +39,8 @@ ulong mainExtendedPartitionFirstSector; uint sectorsPerTrack; #define Clear(address, len) memset(address, 0, len) +#define ReadSectorFromDevice(driverSlot, deviceIndex, lunIndex, firstDeviceSector) DeviceSectorRW(driverSlot, deviceIndex, lunIndex, firstDeviceSector, 0) +#define WriteSectorToDevice(driverSlot, deviceIndex, lunIndex, firstDeviceSector) DeviceSectorRW(driverSlot, deviceIndex, lunIndex, firstDeviceSector, 1) int remote_CreateFatFileSystem(byte* callerParameters); byte CreateFatFileSystem(byte driverSlot, byte deviceIndex, byte lunIndex, ulong firstDeviceSector, ulong fileSystemSizeInK); @@ -50,11 +52,12 @@ int remote_CalculateFatFileSystemParameters(byte* callerParameters); void CalculateFatFileSystemParameters(ulong fileSystemSizeInK, dosFilesystemParameters* parameters); int CalculateFatFileSystemParametersFat12(ulong fileSystemSizeInK, dosFilesystemParameters* parameters); int CalculateFatFileSystemParametersFat16(ulong fileSystemSizeInK, dosFilesystemParameters* parameters); -byte WriteSectorToDevice(byte driverSlot, byte deviceIndex, byte lunIndex, ulong firstDeviceSector); -int remote_PreparePartitionningProcess(byte* callerParameters); +byte DeviceSectorRW(byte driverSlot, byte deviceIndex, byte lunIndex, ulong firstDeviceSector, byte write); +int remote_PreparePartitioningProcess(byte* callerParameters); int remote_CreatePartition(byte* callerParameters); int CreatePartition(int index); -void putchar(char ch); +int remote_ToggleStatusBit(byte* callerParameters); +int ToggleStatusBit(byte partitionTableEntryIndex, ulong partitonTablesector); void Locate(byte x, byte y); //BC = function number (defined in fdisk.h), HL = address of parameters block @@ -68,12 +71,15 @@ int main(int bc, int hl) case f_CreateFatFileSystem: return remote_CreateFatFileSystem((byte*)hl); break; - case f_PreparePartitionningProcess: - return remote_PreparePartitionningProcess((byte*)hl); + case f_PreparePartitioningProcess: + return remote_PreparePartitioningProcess((byte*)hl); break; case f_CreatePartition: return remote_CreatePartition((byte*)hl); break; + case f_ToggleStatusBit: + return remote_ToggleStatusBit((byte*)hl); + break; default: return 0; } @@ -439,9 +445,9 @@ int CalculateFatFileSystemParametersFat16(ulong fileSystemSizeInK, dosFilesystem } -byte WriteSectorToDevice(byte driverSlot, byte deviceIndex, byte lunIndex, ulong firstDeviceSector) +byte DeviceSectorRW(byte driverSlot, byte deviceIndex, byte lunIndex, ulong firstDeviceSector, byte write) { - regs.Flags.C = 1; + regs.Flags.C = write; regs.Bytes.A = deviceIndex; regs.Bytes.B = 1; regs.Bytes.C = lunIndex; @@ -453,7 +459,7 @@ byte WriteSectorToDevice(byte driverSlot, byte deviceIndex, byte lunIndex, ulong } -int remote_PreparePartitionningProcess(byte* callerParameters) +int remote_PreparePartitioningProcess(byte* callerParameters) { int i; int sectorsRemaining; @@ -495,38 +501,22 @@ int CreatePartition(int index) ulong firstFileSystemSector; ulong extendedPartitionFirstAbsoluteSector; partitionTableEntry* tableEntry; - bool onlyPrimaryPartitions = (partitionsCount <= 4); ulong x; - if(onlyPrimaryPartitions) { - mbrSector = 0; - tableEntry = &(mbr->primaryPartitions[index]); - if(index == 0) { - ClearSectorBuffer(); - nextDeviceSector = 1; - } else { - memcpy(sectorBuffer, sectorBufferBackup, 512); - } - tableEntry->firstAbsoluteSector = nextDeviceSector; - } else { - mbrSector = nextDeviceSector; - tableEntry = &(mbr->primaryPartitions[0]); - ClearSectorBuffer(); - tableEntry->firstAbsoluteSector = 1; - } + mbrSector = nextDeviceSector; + tableEntry = &(mbr->primaryPartitions[0]); + ClearSectorBuffer(); + tableEntry->firstAbsoluteSector = 1; + tableEntry->status = partition->status; tableEntry->partitionType = partition->partitionType; tableEntry->sectorCount = partition->sizeInK * 2; firstFileSystemSector = mbrSector + tableEntry->firstAbsoluteSector; - if(onlyPrimaryPartitions){ - nextDeviceSector = tableEntry->firstAbsoluteSector + tableEntry->sectorCount; - } else { - nextDeviceSector += tableEntry->firstAbsoluteSector + tableEntry->sectorCount; - } + nextDeviceSector += tableEntry->firstAbsoluteSector + tableEntry->sectorCount; - if(!onlyPrimaryPartitions && index != (partitionsCount - 1)) { + if(index != (partitionsCount - 1)) { tableEntry++; tableEntry->partitionType = PARTYPE_EXTENDED; tableEntry->firstAbsoluteSector = nextDeviceSector; @@ -560,20 +550,29 @@ int CreatePartition(int index) return CreateFatFileSystem(driverSlot, deviceIndex, selectedLunIndex, firstFileSystemSector, partition->sizeInK); } - -void putchar(char ch) __naked +int remote_ToggleStatusBit(byte* callerParameters) { - __asm - push ix - ld ix,#4 - add ix,sp - ld a,(ix) - call CHPUT - pop ix - ret - __endasm; + return (int)ToggleStatusBit( + callerParameters[0], + *((ulong*)&callerParameters[1])); } +int ToggleStatusBit(byte partitionTableEntryIndex, ulong partitonTablesector) +{ + int error; + masterBootRecord* mbr = (masterBootRecord*)sectorBuffer; + partitionTableEntry* entry; + + error = ReadSectorFromDevice(driverSlot, deviceIndex, selectedLunIndex, partitonTablesector); + if(error != 0) + return error; + + entry =&mbr->primaryPartitions[partitionTableEntryIndex]; + + entry->status ^= 0x80; + + return WriteSectorToDevice(driverSlot, deviceIndex, selectedLunIndex, partitonTablesector); +} void Locate(byte x, byte y) { @@ -583,4 +582,5 @@ void Locate(byte x, byte y) } -#include "asmcall.c" +#include "../../tools/C/asmcall.c" +#include "drivercall.c" \ No newline at end of file diff --git a/source/kernel/bank6/dos.h b/source/kernel/bank6/dos.h index 9b8c15b8..c3fff8bd 100644 --- a/source/kernel/bank6/dos.h +++ b/source/kernel/bank6/dos.h @@ -47,7 +47,7 @@ typedef struct { uint cylinders; byte heads; byte sectorsPertrack; - bool suitableForPartitionning; + bool suitableForPartitioning; } lunInfo; @@ -75,7 +75,7 @@ typedef struct { #define LUN_INFO 0x4169 -#define BK4_ADD 0xF84C +#define BK4_ADD 0xF1CF #endif //__DOS_H \ No newline at end of file diff --git a/source/kernel/compile.bat b/source/kernel/compile.bat index c9b68218..e68e6fd6 100644 --- a/source/kernel/compile.bat +++ b/source/kernel/compile.bat @@ -1,6 +1,8 @@ @echo off cls +if .%1==.drivers goto :drivers + echo . echo **************** echo *** COMMON *** @@ -34,7 +36,7 @@ copy ..\rel.rel copy ..\chgbnk.rel copy ..\drv.rel for %%A in (DOSHEAD,40FF,B0,INIT,ALLOC,DSKBASIC,DOSBOOT,BDOS,RAMDRV) do cpm32 M80 =%%A -cpm32 l80 /p:4000,CODES,KVAR,DATA,REL,DOSHEAD,40FF,B0,INIT,ALLOC,DSKBASIC,DOSBOOT,BDOS,RAMDRV,/p:781F,drv,/p:7fd0,chgbnk,b0/n/x/y/e +cpm32 l80 /p:4000,CODES,KVAR,DATA,REL,DOSHEAD,40FF,B0,INIT,ALLOC,DSKBASIC,DOSBOOT,BDOS,RAMDRV,/p:7700,drv,/p:7fd0,chgbnk,b0/n/x/y/e hex2bin b0.hex ..\SymToEqus b0.sym b0labels.inc "\?[^ \t]+|DOSV0|GETERR|BDOSE" ..\SymToEqus b0.sym b0lab_b3.inc "INIT|TIMINT|MAPBIO|GWRK|R_[^ \t]+" @@ -96,7 +98,7 @@ copy ..\bank0\doshead.rel copy ..\bank0\40FF.rel copy ..\bank0\b0lab_b3.inc b0labels.inc for %%A in (DOS1KER,B3) do cpm32 M80 =%%A -cpm32 l80 /p:4000,CODES,KVAR,DATA,DOSHEAD,40FF,B3,DOS1KER,/p:781F,drv,/p:7fd0,chgbnk,b3/N/X/Y/E +cpm32 l80 /p:4000,CODES,KVAR,DATA,DOSHEAD,40FF,B3,DOS1KER,/p:7700,drv,/p:7fd0,chgbnk,b3/N/X/Y/E rem cpm32 l80 /p:4000,CODES,KVAR,DATA,DOSHEAD,40FF,B3,DOS1KER,drv,/p:7fd0,chgbnk,b3/N/X/Y/E hex2bin -s 4000 b3.hex @@ -177,8 +179,10 @@ dd if=bank5\fdisk.dat of=dos250ba.dat bs=1 count=16000 seek=82176 dd if=bank5\fdisk2.dat of=dos250ba.dat bs=1 count=8000 seek=98560 copy bank4\b4rd.bin dd if=b4rd.bin of=dos250ba.dat bs=1 count=15 seek=65664 -copy dos250ba.dat Nextor-2.1.0-beta1.base.dat -copy dos250ba.dat ..\..\bin\kernels\Nextor-2.1.0-beta1.base.dat +copy dos250ba.dat Nextor-2.1.0-beta2.base.dat +copy dos250ba.dat ..\..\bin\kernels\Nextor-2.1.0-beta2.base.dat + +:drivers echo . echo ***************** @@ -212,8 +216,8 @@ cpm32 L80 /P:7fd0,CHGBNK,CHGBNK/N/X/Y/E hex2bin -s 4000 driver.hex hex2bin -s 7FD0 CHGBNK.hex -..\..\..\..\wintools\mknexrom ..\..\Nextor-2.1.0-beta1.base.dat Nextor-2.1.0-beta1.%%~nc.ROM /d:driver.bin /m:chgbnk.bin -copy Nextor-2.1.0-beta1.%%~nc.ROM ..\..\..\..\bin\kernels +..\..\..\..\wintools\mknexrom ..\..\Nextor-2.1.0-beta2.base.dat Nextor-2.1.0-beta2.%%~nc.ROM /d:driver.bin /m:chgbnk.bin +copy Nextor-2.1.0-beta2.%%~nc.ROM ..\..\..\..\bin\kernels del b6.mac del *.rom cd .. @@ -227,10 +231,43 @@ echo *** echo . cd MegaFlashRomSD -..\..\..\..\wintools\mknexrom ..\..\Nextor-2.1.0-beta1.base.dat nextor2.rom /d:driver.bin /m:Mapper.ASCII8.bin -copy nextor2.rom ..\..\..\..\bin\kernels\Nextor-2.1.0-beta1.MegaFlashSDSCC.ROM +..\..\..\..\wintools\mknexrom ..\..\Nextor-2.1.0-beta2.base.dat nextor2.rom /d:driver-1slot.dat /m:Mapper.ASCII8.bin +copy nextor2.rom ..\..\..\..\bin\kernels\Nextor-2.1.0-beta2.MegaFlashSDSCC.1-slot.ROM +sjasm makerecoverykernel.asm kernel.dat +copy kernel.dat ..\..\..\..\bin\kernels\Nextor-2.1.0-beta2.MegaFlashSDSCC.1-slot.Recovery.ROM +del nextor2.rom +..\..\..\..\wintools\mknexrom ..\..\Nextor-2.1.0-beta2.base.dat nextor2.rom /d:driver-2slots.dat /m:Mapper.ASCII8.bin +copy nextor2.rom ..\..\..\..\bin\kernels\Nextor-2.1.0-beta2.MegaFlashSDSCC.2-slots.ROM sjasm makerecoverykernel.asm kernel.dat -copy kernel.dat ..\..\..\..\bin\kernels\Nextor-2.1.0-beta1.MegaFlashSDSCC.Recovery.ROM +copy kernel.dat ..\..\..\..\bin\kernels\Nextor-2.1.0-beta2.MegaFlashSDSCC.2-slots.Recovery.ROM +cd .. + +echo . +echo *** +echo *** Driver: Sunrise IDE +echo *** +echo . + +cd SunriseIDE + +del ..\..\..\..\bin\kernels\Nextor-2.1.0-beta2.SunriseIDE.emulators.ROM +ren ..\..\..\..\bin\kernels\Nextor-2.1.0-beta2.SunriseIDE.ROM Nextor-2.1.0-beta2.SunriseIDE.emulators.ROM +sjasm -c sunride.asm driver.bin +..\..\..\..\wintools\mknexrom ..\..\Nextor-2.1.0-beta2.base.dat nextor2.rom /d:driver.bin /m:chgbnk.bin +copy nextor2.rom ..\..\..\..\bin\kernels\Nextor-2.1.0-beta2.SunriseIDE.ROM +:okide +cd .. + +echo . +echo *** +echo *** Driver: Flashjacks +echo *** +echo . + +cd Flashjacks +sjasm flashjacks.asm driver.bin +..\..\..\..\wintools\mknexrom ..\..\Nextor-2.1.0-beta2.base.dat nextor2.rom /d:driver.bin /m:chgbnk.dat +copy nextor2.rom ..\..\..\..\bin\kernels\Nextor-2.1.0-beta2.Flashjacks.ROM cd .. echo . diff --git a/source/kernel/condasm.inc b/source/kernel/condasm.inc index f1ef44ee..e735232a 100644 --- a/source/kernel/condasm.inc +++ b/source/kernel/condasm.inc @@ -10,8 +10,9 @@ BUILTIN equ -1 ;built-in system ALPHA equ 0 ;Level of Alpha release (0: no alpha) ALPHAL equ "" ;Letter after the Alpha release number, or empty -BETA equ 1 ;Level of Beta release (0: no beta) +BETA equ 2 ;Level of Beta release (0: no beta) RC equ 0 ;Level of RC (0: no RC) +RR equ 0 ;Level of release (0: no release level) ; ;----------------------------------------------------------------------------- ; diff --git a/source/kernel/data.mac b/source/kernel/data.mac index 0c7a45c5..41474d9d 100644 --- a/source/kernel/data.mac +++ b/source/kernel/data.mac @@ -50,11 +50,21 @@ ram_ad defl DATABASE ; ------------------------ ; var PRTBUF,6,F1C9 ;MSX-DOS1 compatible string output routine - spare 4 + +; ------------------------ + +; These are available in MSX-DOS 1 mode too thanks to the modification +; of the STROUT routine, see dos1ker.mac + + spare 1 + ;NOTE! BK4_ADD is manually defined in bank5/dos.h, and must be updated if it changes + var0 IS_FIRST_BOOT + var2 BK4_ADD,F1D0 ;Address of routine to be called in bank 4 + var TMP_SEC,4 ;Used for temporary storage of a 32 bit sector number ; ; ------------------------ ; - var0 JUMPBASE,F1D3 ;Start of jump table. + var0 JUMPBASE,F1D6 ;Start of jump table. ; var3 RD_LDIR ;inter-slot LDIR routine for RAMdisk var3 P0_LDIR ;Data transfer routine used by read/write code @@ -63,7 +73,8 @@ ram_ad defl DATABASE var3 GO_DRV ;Call driver routine var3 JP_VECT ;DOS1 compatible error jump ; - var3 $IRQ ;Interrupt entry point + ;var3 $IRQ ;Moved below DTA_ADDR to make room right before JUMPBASE + ;(which was F1D3 originally) ; var3 $RDSLT ;Inter-slot read var3 $WRSLT ;Inter-slot write @@ -99,16 +110,14 @@ ram_ad defl DATABASE ;var3 FR_BK ;spare 6 ; - var TMP_FROOT,4 ;Temporary area used when activating disk emulation mode - var1 TMP_CS - var2 TMP_NDIR - spare 5 ;For future expansion + spare 12 ;For future expansion ; var1 CUR_DRV ;Current logical drive (1=A:) var2 DTA_ADDR,F23D ;DMAADD used by MSXDOS1.SYS - can not move. ; - var0 NXT7 - spare 7 + var3 $IRQ ;Interrupt entry point + var3 RAM_ABORT ;Stores a RET and a pointer to it (see SET_BOOT_VECTORS in dosboot.mac) + spare 1 ; var1 DIRBFD, F246 ;** May be corrupted sometimes. ; @@ -252,16 +261,18 @@ ram_ad defl DATABASE ; var1 DOS_VER ;DOS version number 2.x ; - var0 DVB_TABLE ;Pointer to table of device-based drives for DOS1 var1 P0_64K ;\ These are the basic 64k RAM segment var1 P1_64K ; \ numbers which should never be changed var1 P2_64K ; / by anyone (including the system). var1 P3_64K ;/ + + const DVB_TABLE,P0_64K ;Pointer to table of device-based drives for DOS1 + const KSLOT,P2_64K ;Slot of disk controller being called (used in DOS 1 mode) ; ;===== start mod DOS2.50 (support MegaSCSI) var1 NXT_VER ;Nextor version numbr var1 MAIN_BANK - var KER250,4 ;MSX-DOS 2.50 kernel slots, + var KER250,4 ;Nextor kernel slots, ;bit 6 is set if timer interrupt routine is to be called ;bit 5 is set if the driver provides configuration var _TIME_IRQ,5,F31E @@ -273,24 +284,8 @@ ram_ad defl DATABASE var2 DISKVECT,F323 ;BDOS_GO disk error vector var2 BREAKVECT,F325 ;BDOS_GO ctrl-stop vector ; - var AUXBODY,3,F327 ;Actually 10 - var1 NXTEMP ;For temporary usage by AUTO_ASSIGN - var0 NXT2 ;(values are saved in the stack and later restored) - var1 TMPLUN - var1 TMPDEV - var1 NXT3 - var3 NXT4 + var AUXBODY,10,F327 - ;These variables are declared inside ARG, a 16 byte area used by math-pack. - ;There should be no conflict since DOS kernel and math-pack - ;are not intended to use this area at the same time. - -ARG equ 0F847h - const KSLOT,ARG ;Slot of disk controller being called (used in DOS 1 mode) - const TMP_SEC,ARG+1 ;Used to temporary storage of a 32 bit sector number - const BK4_ADD,ARG+5 ;Address of routine to be called in bank 4 - const BUF9,ARG+7 ;Use by auto-assign routine in bank 4 -; spare 2 var2 $DOS1 ;MSX-DOS1 compatible page-1 BDOS entry spare 1 @@ -596,6 +591,11 @@ ram_ad defl 04115h-6 var3 SET1INT var3 PRV1INT +;----------------------------------------------------------------------------- +; +; Fields in the disk amulation mode table + + ;----------------------------------------------------------------------------- ; diff --git a/source/kernel/drivers/.gitignore b/source/kernel/drivers/.gitignore index 24a9e0df..9b45e266 100644 --- a/source/kernel/drivers/.gitignore +++ b/source/kernel/drivers/.gitignore @@ -3,3 +3,4 @@ bank.inc condasm.inc const.inc macros.inc +**/*.out diff --git a/source/kernel/drivers/Flashjacks/chgbnk.dat b/source/kernel/drivers/Flashjacks/chgbnk.dat new file mode 100644 index 00000000..fe5cb289 --- /dev/null +++ b/source/kernel/drivers/Flashjacks/chgbnk.dat @@ -0,0 +1 @@ +ÅË?ËË?ËË?ËË?ËË?ËxÁæø2AÉÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ \ No newline at end of file diff --git a/source/kernel/drivers/SunriseIDE/DRIVER.02.MAC b/source/kernel/drivers/Flashjacks/flashjacks.asm similarity index 59% rename from source/kernel/drivers/SunriseIDE/DRIVER.02.MAC rename to source/kernel/drivers/Flashjacks/flashjacks.asm index 1b17453e..208fea1e 100644 --- a/source/kernel/drivers/SunriseIDE/DRIVER.02.MAC +++ b/source/kernel/drivers/Flashjacks/flashjacks.asm @@ -1,43 +1,37 @@ - ; Device-based driver for the sunrise IDE interface for MSX-DOS 2.50 + ; Device-based driver for the FLASHJACKS IDE interface for Nextor ; - ; Version 0.1 - ; By Konamiman + ; By Aquijacks v1.4 + ; Based on version 0.1 by Konamiman and 0.15 by Piter Punk + + ;output "sunride_aquijacks.bin" + + org $4000 + + ds 256, $FF ; 256 dummy bytes - ;org 4100h DRV_START: TESTADD equ 0F3F5h -TIMEVAR equ 0FC9Eh ;----------------------------------------------------------------------------- ; ; Driver configuration constants ; -;Driver type: -; 0 for drive-based -; 1 for device-based - -DRV_TYPE equ 1 ;Hot-plug devices support (device-based drivers only): ; 0 for no hot-plug support ; 1 for hot-plug support -DRV_HOTPLUG equ 0 +DRV_HOTPLUG equ 1 -DEBUG equ 0 ;Set to 1 for debugging, 0 to normal operation ;Driver version -VER_MAIN equ 0 -VER_SEC equ 2 -VER_REV equ 0 - - if DEBUG eq 1 - include B0LABELS.INC - endif +VER_MAIN equ 1 +VER_SEC equ 4 +VER_REV equ 1 ;This is a very barebones driver. It has important limitations: ;- CHS mode not supported, disks must support LBA mode. @@ -50,9 +44,8 @@ VER_REV equ 0 ; ; IDE registers and bit definitions -IDE_BANK equ 4104h - ;bit 0: enable (1) or disable (0) IDE registers - ;bits 5-7: select 16K ROM bank +IDE_BANK equ 4104h ;bit 0: enable (1) or disable (0) IDE registers + ;bits 5-7: select 16K ROM bank IDE_DATA equ 7C00h ;Data registers, this is a 512 byte area IDE_ERROR equ 7E01h ;Error register IDE_FEAT equ 7E01h ;Feature register @@ -63,10 +56,10 @@ IDE_CYLOW equ 7E04h ;Cylinder low (CHS mode) IDE_LBAMID equ 7E04h ;Logical sector mid (LBA mode) IDE_CYHIGH equ 7E05h ;Cylinder high (CHS mode) IDE_LBAHIGH equ 7E05h ;Logical sector high (LBA mode) -IDE_HEAD equ 7E06h - ;bits 0-3: Head (CHS mode), logical sector higher (LBA mode) +IDE_HEAD equ 7E06h ;bits 0-3: Head (CHS mode), logical sector higher (LBA mode) IDE_STATUS equ 7E07h ;Status register -IDE_CMD equ 7E07h ;Command register +IDE_CMD equ 7E07h ;Command register +IDE_FLASHJACKS equ 7E09h ;Registro FlashJacks IDE_DEVCTRL equ 7E0Eh ;Device control register ; Bits in the error register @@ -116,6 +109,8 @@ M_SRST equ (1 SHL SRST) CHPUT equ 00A2h ;Character output CHGET equ 009Fh +CLS equ 00C3h +MSXVER equ 002Dh ;----------------------------------------------------------------------------- @@ -156,22 +151,18 @@ CHGET equ 009Fh ; Error codes for DEV_RW and DEV_FORMAT ; -if DRV_TYPE eq 1 - -.NCOMP equ 0FFh -.WRERR equ 0FEh -.DISK equ 0FDh -.NRDY equ 0FCh -.DATA equ 0FAh -.RNF equ 0F9h -.WPROT equ 0F8h -.UFORM equ 0F7h -.SEEK equ 0F3h -.IFORM equ 0F0h -.IDEVL equ 0B5h -.IPARM equ 08Bh - -endif +NCOMP equ 0FFh +WRERR equ 0FEh +DISK equ 0FDh +NRDY equ 0FCh +DATA equ 0FAh +RNF equ 0F9h +WPROT equ 0F8h +UFORM equ 0F7h +SEEK equ 0F3h +IFORM equ 0F0h +IDEVL equ 0B5h +IPARM equ 08Bh ;----------------------------------------------------------------------------- ; @@ -266,13 +257,7 @@ SING_DBL equ 7420h ;"1-Single side / 2-Double side" ; bit 0: 0 for drive-based, 1 for device-based ; bit 1: 1 for hot-plug devices supported (device-based drivers only) -if DRV_TYPE eq 0 - db 0 -endif - -if DRV_TYPE eq 1 db 1+(2*DRV_HOTPLUG) -endif ;Reserved byte db 0 @@ -297,25 +282,16 @@ DRV_NAME: jp DRV_DIRECT3 jp DRV_DIRECT4 - ds 15 -if DRV_TYPE eq 0 - jp DRV_DSKIO - jp DRV_DSKCHG - jp DRV_GETDPB - jp DRV_CHOICE - jp DRV_DSKFMT - jp DRV_MTOFF -endif + ds 15 -if DRV_TYPE eq 1 jp DEV_RW jp DEV_INFO jp DEV_STATUS jp LUN_INFO jp DEV_FORMAT jp DEV_CMD -endif + ;----------------------------------------------------------------------------- @@ -345,7 +321,7 @@ DRV_TIMI: ; Input: ; A = 1 ; B = number of allocated drives for this controller -; (255 if device-based driver, unless 4 i pressed at boot) +; (255 if device-based driver, unless 4 is pressed at boot) ; ; The work area address can be obtained by using GWORK. ; @@ -368,235 +344,369 @@ DRV_INIT: or a ld hl,0 ld a,2 - ret z ;Note that Cy is 0 (no interrupt hooking needed) + ret z ;Note that Cy is 0 (no interrupt hooking needed) ;xor a ;ld (TESTADD),a - ld de,INFO_S - call PRINT - -if DEBUG eq 1 - call DO - - ld hl,8101h - ld (DRVTBL##),hl - ld hl,8301h - ld (DRVTBL##+2),hl - ld hl,8501h - ld (DRVTBL##+4),hl - ld hl,0 - ld (DRVTBL##+6),hl - - ld a,87h - ld (KER250##),a - ld a,85h - ld (KER250##+1),a - ld a,89h - ld (KER250##+2),a + ;--- Borra la pantalla. En los MSX1 hay que decirselo ya que no lo tiene implementado de serie. + + push af ; Guarda las variables de inicio. + push bc + push hl + ;bit 0,a ; Pone a cero el flag Z + ;xor a ; Pone a cero a + ;call CLS + ;--- Este m�todo de borrado es mejor. Aportado por Victor. + ld a,40 ; 40 columnas + ld (0F3AEh),a xor a - ld (KER250##+3),a - - ld a,1 - ld ix,GDRIVER## - ex af,af' - ld a,4 - call CALBNK - jp DRV_INIT_END - - -;Input: Cy=0 to read, 1 to write -; A = Device number, 1 to 7 -; B = Logical unit number, 1 to 7 -; C = Number of sectors to read or write -; HL = Source or destination memory address for the transfer -; DE = Address where the 4 byte sector number is stored. - - ld hl,0C000h - ld ($SECBUF##),hl - - ;ld hl,GPART## - ;ld (BK4_ADD##),hl + call 005Fh ; Screen 0 - ld b,1 - ld c,0FFh - ld d,1 - ld e,1 - ld h,4 - ld l,0 - - ld ix,GPART## - ex af,af' - ld a,4 - call CALBNK - jp DRV_INIT_END - - or a - ld a,1 - ld b,1 - ld c,3 - ld hl,0 - ld (0C000h),hl - ld (0C002h),hl - ld hl,0C000h - ld de,0C000h - call DEV_RW - - ld a,1 - ld (0C000h),a - ld a,2 - ld (0C200h),a - ld a,34h - ld (0C000h+512*3-1),a - - scf - ld a,1 - ld b,1 - ld c,3 - ld hl,0 - ld (0C000h),hl - ld (0C002h),hl - ld hl,0C000h - ld de,0C000h - call DEV_RW - - jp DRV_INIT_END - -luninfo: - - ld a,1 - ld b,1 - ld hl,0C000h - call LUN_INFO - ld a,2 - ld b,1 - ld hl,0C000h - call LUN_INFO - ld a,3 - ld b,1 - ld hl,0C000h - call LUN_INFO - ld a,2 - ld b,2 - ld hl,0C000h - call LUN_INFO + ;--- Comprueba el bit de doble reset y lo ejecuta en caso de estar en on. + call IDE_ON + ld a,(IDE_FLASHJACKS) ; Trae el registro de Flashjacks. + and 11110100b ; Anula los bits de freq y deja solo la marca de comprobaci�n y el bit de reset. + cp 0A4h ; Comprueba marca de comprobaci�n y bit de reset + jr nz,CONTPRG ; No ha detectado una marca correcta del registro flashjacks por lo que no ejecuta nada del reset. + call IDE_OFF + pop hl ; Retorno de las variables de inicio. + pop bc + pop af + rst 0 ; Fuerza un reset. A partir de aqu� hace un soft reset y no continua con el programa. +CONTPRG: + call IDE_OFF + + ;---------------------------------------------- + ;Compruba las teclas F4 y F5 (VDP FREQ y fuerza TURBOCPU) + push af + push hl + push de + push bc - jp DRV_INIT_END + ; Compara tecla pulsada + ld b,7 ;row 7 RET SELECT BS STOP TAB ESC F5 F4 + in a,(0AAh) + and 11110000b + or b + out (0AAh),a + in a,(0A9h) + bit 0,a ;F4 -- Si es tecla pulsada turbo va a la rutina de activaci�n del turbo. + jr nz,Fin_ini ; Salta si no se pulsa tecla de turbo. + push af + call putTURBO_CPU ; Ejecuta el turbo CPU. + pop af +Fin_ini:pop bc + pop de + pop hl + pop af + + ;--- Comienza la escritura en pantalla del driver. + ld de,INFO_S + call PRINT + + ;--- Saca por pantalla el modelo de ordenador. + ld de,MODELO ; Escribre Modelo: + call PRINT + ld a,(MSXVER) ; Trae el registro de version de MSX de la BIOS + cp 00h ; Si es un MSX1 realiza un salto a la escritura de MSX1. + jr z,IMP_MSX1 + cp 01h ; Si es un MSX2 realiza un salto a la escritura de MSX2. + jr z,IMP_MSX2 + cp 02h ; Si es un MSX2+ realiza un salto a la escritura de MSX2+. + jr z,IMP_MSX2M + cp 03h ; Si es un MSX TurboR realiza un salto a la escritura de MSX TurboR. + jr z,IMP_MSXR + cp 04h ; Si es un OCM realiza un salto a la escritura de OCM. + jr z,IMP_OCM + jp NO_DETEC ; Si no es ninguna de las versiones mencionadas, imprime un no detectado. +IMP_MSX1: + ld de,M_MSX1 + call PRINT + jp FIN_IMP; +IMP_MSX2: + ld de,M_MSX2 + call PRINT + jp FIN_IMP; +IMP_MSX2M: + ld de,M_MSX2M + call PRINT + jp FIN_IMP; +IMP_MSXR: + ld de,M_MSXR + call PRINT + jp FIN_IMP; +IMP_OCM: + ld de,M_OCM + call PRINT + jp FIN_IMP; +NO_DETEC: + ld de,M_NDTC + call PRINT +FIN_IMP: + pop hl ; Retorno de las variables de inicio. + pop bc + pop af - ld a,1 - ld b,0 - ld hl,0C000h - call DEV_INFO - ld a,1 - ld b,1 - ld hl,0C000h - call DEV_INFO - ld a,1 - ld b,2 - ld hl,0C000h - call DEV_INFO - ld a,1 - ld b,3 - ld hl,0C000h - call DEV_INFO - jp DRV_INIT_END -DO: -endif + ;-- B�squeda de la unidad por pantalla. + ld de,SEARCH_S + call PRINT ld a,1 call MY_GWORK call IDE_ON - ld (ix),0 - ld (ix+4),0 ;Assume no devices initially + ld (ix),0 ;Assume both devices empty + ld (ix+4),0 - ;--- Perform a software reset on both devices - - ld a,M_SRST - ld (IDE_DEVCTRL),a - nop ;Wait 5 us - xor a - ld (IDE_DEVCTRL),a + ld a,M_SRST ;Do a software reset + ld (IDE_DEVCTRL),a + nop ;Wait 5 us + xor a + ld (IDE_DEVCTRL),a WAIT_RESET: - ld a,(IDE_STATUS) - and M_BSY+M_DRDY - cp M_DRDY - jr nz,WAIT_RESET ;Wait for BSY to clear and DRDY to set - - ;--- Determine whether there is any device connected - ; by looking at the diagnostic code in the error register + ld de,7640 ;Timeout after 30 s +WAIT_RESET1: + ld a,0 + cp e + jr nz,WAIT_DOT ;Print dots while waiting + ld a,46 + call CHPUT +WAIT_DOT: + call CHECK_ESC + jp c,INIT_NO_DEV + ld b,255 +WAIT_RESET2: + ld a,(IDE_STATUS) + and M_BSY+M_DRDY + cp M_DRDY + jr z,WAIT_RESET_END ;Wait for BSY to clear and DRDY to set + djnz WAIT_RESET2 + dec de + ld a,d + or e + jr nz,WAIT_RESET1 + jp INIT_NO_DEV +WAIT_RESET_END: + + ;--- Do a quick pre-check on MASTER device - ld a,(IDE_ERROR) - ld b,a - and 1 - cp 1 - jr nz,INIT_NO_DEV ;Master failed: give up - - ld (ix+4),b ;We'll check later if there is a slave - - ;--- Get info and show the name for the master - - xor a - call WRHEAD ;Select device 1 - ld e,a - ld a,0ECh - call DO_IDE2 - jr c,OK_MASTER - - call INIT_CHECK_DEV - jr c,OK_MASTER + ld a,0 + ld (IDE_HEAD),a ;Select device 0 + nop + + call INIT_PRECHECK_DEV + ld a,(IDE_SECCNT) + cp 85 + jr nz,MASTER_CHECK1_END + ld a,(IDE_SECNUM) + cp 170 + jr nz,MASTER_CHECK1_END + + ld a,1 ;Flag the device + ld (ix),a +MASTER_CHECK1_END: + ld a,46 ;Print dot + call CHPUT + + ld a,M_SRST ; Do ANOTHER software reset + ld (IDE_DEVCTRL),a + nop ;Wait 5 us + xor a + ld (IDE_DEVCTRL),a + nop ;Wait 5 us + ld a,46 ;Print dot + call CHPUT + + ld de,CRLF_S + call PRINT + + ;--- Get info and show the name for the MASTER ld de,MASTER_S call PRINT - call INIT_PRINT_NAME - ld (ix),2 ;ATA device with LBA -OK_MASTER: - - ;--- If the presence of slave musy be checked, - ; issue a test command and check for error - - ld a,(ix+4) ;1 if slave OK or not present, 81h if failed - ld (ix+4),0 +WSKIPMAS: ; If ESC is pressed, ignore this device + ld de,624 ; Wait 1s to read the keyboard +WSKIPMAS1: + call CHECK_ESC + jr c,NODEV_MASTER + ld b,64 +WSKIPMAS2: + ex (sp),hl + ex (sp),hl + djnz WSKIPMAS2 + dec de + ld a,d + or e + jr nz,WSKIPMAS1 + + ld a,(ix) ;If the device isn't flagged it doesn't exists cp 1 - jr nz,OK_SLAVE + jr nz,NODEV_MASTER + ld a,46 ;Print FIRST dot + call CHPUT - ld a,M_DEV - call WRHEAD ;Select device 1 - ld e,a - ld a,0ECh - call DO_IDE2 - jr c,OK_SLAVE ;If error, no device, or ATAPI device + call WAIT_CMD_RDY + jr c,NODEV_MASTER + ld a,0 + ld (IDE_HEAD),a ;Select device 0 + ld a,46 ;Print SECOND dot + call CHPUT + + ld a,0ECh ;Send IDENTIFY commad + call DO_IDE + jr c,NODEV_MASTER + ld a,46 ;Print THIRD dot + call CHPUT + + call INIT_CHECK_DEV ;Check if the device is ATA or ATAPI + jr c,NODEV_MASTER + ld a,46 ;Print FOURTH dot + call CHPUT + + call WAIT_CMD_RDY ;Try to select the device + jr c,NODEV_MASTER ;this is our last chance to *NOT* detect it + ld a,0 + ld (IDE_HEAD),a ;Select device 0 + ld a,46 ;Print FIFTH dot + call CHPUT + + call INIT_PRINT_NAME - ;--- Get info and show the name for the slave + ld (ix),2 ;ATA device with LBA + jr OK_MASTER - call INIT_CHECK_DEV - jr c,OK_SLAVE +NODEV_MASTER: + call CHECK_ESC + jr c,NODEV_MASTER - ld de,SLAVE_S + ld (ix),0 + ld de,NODEVS_S call PRINT - call INIT_PRINT_NAME - - ld (ix+4),2 ;ATA device with LBA -OK_SLAVE: - ;--- End of the initialization procedure +OK_MASTER: + ld a,M_SRST ;Last software reset before we go + ld (IDE_DEVCTRL),a ;some times a faulty slave leaves + ;BSY set forever (30s) + nop ;Wait 5 us + xor a + ld (IDE_DEVCTRL),a jr DRV_INIT_END INIT_NO_DEV: + call CHECK_ESC + jr c,INIT_NO_DEV + + ld de,CRLF_S + call PRINT + ld de,MASTER_S + call PRINT ld de,NODEVS_S call PRINT + + ;--- Fin del procedimiento de inicializaci�n. DRV_INIT_END: + ld (ix+4),0 ; Marca que no hay unidad esclava. call IDE_OFF -if DEBUG eq 1 - ;call CHGET ;For debugging -endif - ret + ;--- Retardo de espera de 2 Segundos para que se vea el texto de carga del driver en pantalla. + ;--- Si es un MSXTurboR no lo hace. Este ya tiene retardo de por si en el arranque. + push de + push bc + ld a,(MSXVER) ; Trae el registro de version de MSX de la BIOS + cp 03h ; Si es un MSX TurboR realiza un salto ya que este equipo es lento de por si al arranque. + jr z,ESPERA_FIN ; Omite la espera de 2s para el TurboR + ld de,1861 ;Contador cargado para 2s +ESPERA_RDY1: + ld b,255 +ESPERA_RDY2: + djnz ESPERA_RDY2 ;Bucle ESPERA_RDY2 + dec de + ld a,d + or e + jr nz,ESPERA_RDY1 ;Bucle ESPERA_RDY1 +ESPERA_FIN: + pop bc + pop de + + ;--- Codigo asistencia a la unidad FLASHJACKS. Se ejecuta despues del inicio de NEXTOR. + call IDE_ON + ld a,(MSXVER) ; Trae el registro de version de MSX de la BIOS + cp 00h ; Si es un MSX1 salta la operaci�n de forzado del VDP por incompatibilidad del mismo. + jr z,DEV_FLASH_FIN + + ; Compara tecla pulsada + ld b,7 ;row 7 RET SELECT BS STOP TAB ESC F5 F4 + in a,(0AAh) + and 11110000b + or b + out (0AAh),a + in a,(0A9h) + bit 1,a ;F5 -- Si es tecla pulsada VDP va a la rutina de permutaci�n de frecuencia. + jp z,DEV_VDP_FIN ; Salta la gesti�n del VDP para la permutaci�n del VDP por tecla pulsada. + ld a,(IDE_FLASHJACKS) ; Trae el registro de Flashjacks. + and 11111011b ; Anula el bit de doble reset para comparar el resto. + cp 0A3h ; Forzado a 60Hz. 101000 + Bit de Forzado a 1 + Bit de 60 Hz a 1 + jr z,DEV_FLASH60 ; Salta al forzado a 60 Hz. + cp 0A2h ; Forzado a 50Hz. 101000 + Bit de Forzado a 1 + Bit de 50 Hz a 0 + jr z,DEV_FLASH50 ; Salta al forzado a 50 Hz. + jp DEV_FLASH_FIN ; Otras opciones son ignoradas y no hace cambio alguno. + +DEV_FLASH50: + ld a,02h ; 02h a 50hz y 00h a 60hz + jp DEV_FLASHVDP; + +DEV_FLASH60: + ld a,00h ; 02h a 50hz y 00h a 60hz + +DEV_FLASHVDP: + out (099h),a ;Salida directa del VPD + ld (0ffe8h), a ;Salida por BIOS del VDP registro 9 + ld a,89h + out (099h),a + +DEV_FLASH_FIN: + call IDE_OFF + ret ; Devuelve el control. + +DEV_VDP_FIN: + ; Ejecuta la permutaci�n del VDP existente + ld hl,0ffe8h;VDP register value + ld a,(hl) + xor 2 + ld (hl),a + di + out (99h),a ;Set VDP Frequency + ld a,9+128 + ei + out (099h),a + call IDE_OFF + ret ; Devuelve el control. + +;--- Subroutines for the INIT procedure + +;Check if there is any device listening in the bus +;Input: device already selected +;Output: If something is there, IDE_SECCNT=85, IDE_SECNUM=170 +; Both variables have random values if nothing is there -;--- Subruotines for the INIT procedure +INIT_PRECHECK_DEV: + ld a,85 + ld (IDE_SECCNT),a + ld a,170 + ld (IDE_SECNUM),a + ld a,170 + ld (IDE_SECCNT),a + ld a,85 + ld (IDE_SECNUM),a + ld a,85 + ld (IDE_SECCNT),a + ld a,170 + ld (IDE_SECNUM),a + ret ;Check that a device is present and usable. ;Input: IDENTIFY DEVICE issued successfully. @@ -606,20 +716,72 @@ endif INIT_CHECK_DEV: ld hl,IDE_DATA ld de,TEMP_WORK - ld bc,50*2 ;Get the first 50 data words + ld bc,50*2 ;Get the first 50 data words ldir - ;ld a,(TEMP_WORK+1) - ;and 80h ;ATAPI device? - ;scf - ;ret nz + ld a,(IDE_STATUS) ;Check status + cp 01111111b ;Usually this means "no device" + jr z,INIT_CHECK_NODEV - ld a,(TEMP_WORK+49*2+1) - and 2 ;LBA supported? - scf - ret z + ; "At power-up or after reset, the Command Block Registers are initialized + ; to the following values: + ; + ; REGISTER VALUE + ; 1F1 Error : 01 + ; 1F2 Sector Count : 01 + ; 1F3 Sector Number : 01 + ; 1F4 Cylinder Low : 00 + ; 1F5 Cylinder High : 00 + ; 1F6 Drive / Head : 00" + ; + ; Not all devices respect this. One of my CompactFlash cards never have + ; Sector Count = 01 and Sector Number = 01 after reset. + ; + ; ld a,(IDE_SECNUM) ;Test if the device is REALLY here + ; cp 1 + ; jr nz,INIT_CHECK_NODEV + ; ld a,(IDE_SECCNT) + ; cp 1 + ; jr nz,INIT_CHECK_NODEV + + ld a,(IDE_CYLOW) ;Test for PATAPI devices + cp 20 + jr nz,TEST2_FOR_ATAPI + ld a,(IDE_CYHIGH) + cp 235 + jr z,INIT_CHECK_NODEV +TEST2_FOR_ATAPI: + ld a,(IDE_CYLOW) ;Test for SATAPI devices + cp 105 + jr nz,TEST_FOR_ATA + ld a,(IDE_CYHIGH) + cp 150 + jr z,INIT_CHECK_NODEV + +TEST_FOR_ATA: + ld a,(IDE_CYLOW) ;Test for PATA devices + cp 0 + jr nz,TEST2_FOR_ATA + ld a,(IDE_CYHIGH) + cp 0 + jr z,TEST_FOR_LBA +TEST2_FOR_ATA: + ld a,(IDE_CYLOW) ;Test for SATA devices + cp 60 + jr nz,INIT_CHECK_NODEV + ld a,(IDE_CYHIGH) + cp 195 + jr nz,INIT_CHECK_NODEV + +TEST_FOR_LBA: + ld a,(TEMP_WORK+49*2+1) + and 2 ;LBA supported? + jr z,INIT_CHECK_NODEV + xor a + ret - or a +INIT_CHECK_NODEV: + scf ret @@ -709,135 +871,10 @@ DRV_DIRECT4: ret -;===== -;===== BEGIN of DRIVE-BASED specific routines -;===== - -if DRV_TYPE eq 0 - -;----------------------------------------------------------------------------- -; -; Read/write disk sectors -; -;Input: A = Drive number, starting at 0 -; Cy = 0 for reading sectors, 1 for writing sectors -; B = Number of sectors to read/write -; DE = First sector number to read/write -; HL = source/destination address for the transfer -;Output: Cy = 0 on success, 1 on error -; A = Error code (on error only): -; 0 Write protected -; 2 Not ready -; 4 Data (CRC) error -; 6 Seek error -; 8 Record not found -; 10 Write fault -; 12 Other errors - -DRV_DSKIO: - ld a,12 - scf - ret - - -;----------------------------------------------------------------------------- -; -; Get disk change status -; -;Input: A = Drive number, starting at 0 -; B = C = Media descriptor -; HL = Base address for DPB -1 -;Output: Cy = 0 on success, 1 on error -; A = Error code (on error only) -; Same codes as DRV_DSKIO -; B = Disk status (on success only) -; 1 Disk not changed -; 0 Unknown -; -1 Disk changed - -DRV_DSKCHG: - ld a,12 - scf - ret - - -;----------------------------------------------------------------------------- -; -; Get DPB for disk -; -;Input: A = Drive number, starting at 0 -; B = C = Media descriptor -; HL = Base address for DPB -1 -;Output: - - -DRV_GETDPB: - ld a,12 - scf - ret - - -;----------------------------------------------------------------------------- -; -; Return format choice string -; -;Input: - -;Output: HL = Address of the choice string in the kernel slot - -DRV_CHOICE: - ld hl,NULL_MSG - ret - - -;----------------------------------------------------------------------------- -; -; Format a disk -; -;Input: A = Formatting choice, from 1 to 9 (see DRV_CHOICE). -; D = Drive number, starting at 0 -; HL = Address of work area in memory -; DE = Size of work area -;Output: Cy = 0 on success, 1 on error -; A = Error code (on error only): -; 0 Write protected -; 2 Not ready -; 4 Data (CRC) error -; 6 Seek error -; 8 Record not found -; 10 Write fault -; 12 Bad parameter -; 14 Insufficient memory -; 16 Other errors - -DRV_DSKFMT: - ld a,16 - scf - ret - - -;----------------------------------------------------------------------------- -; -; Turn off the floppy disk drive motor -; -;Input: - -;Output: - - -DRV_MTOFF: - ret - -endif - - -;===== -;===== END of DRIVE-BASED specific routines -;===== - - ;===== ;===== BEGIN of DEVICE-BASED specific routines ;===== -if DRV_TYPE eq 1 - ;----------------------------------------------------------------------------- ; ; Read or write logical sectors from/to a logical unit @@ -863,6 +900,7 @@ if DRV_TYPE eq 1 ; B = Number of sectors actually read/written DEV_RW: + push af ld a,b ;Swap B and C @@ -901,14 +939,20 @@ DEV_RW_NO0SEC: ld a,(ix+3) or M_LBA or b - call WRHEAD ;IDE_HEAD must be written first, + di ; Se desactivan peticiones de interrupciones para evitar intromisiones. + ld (IDE_HEAD),a ;IDE_HEAD must be written first, + ld (IDE_HEAD),a ; Se duplica env�o de comando para refrescar sin error la FLASHJACKS. ld a,(ix) ;or the other IDE_LBAxxx and IDE_SECCNT ld (IDE_LBALOW),a ;registers will not get a correct value + ld (IDE_LBALOW),a ; Se duplica env�o de comando para refrescar sin error la FLASHJACKS. ld a,(ix+1) ;(blueMSX issue?) + ld (IDE_LBAMID),a ; Se duplica env�o de comando para refrescar sin error la FLASHJACKS. ld (IDE_LBAMID),a ld a,(ix+2) + ld (IDE_LBAHIGH),a ; Se duplica env�o de comando para refrescar sin error la FLASHJACKS. ld (IDE_LBAHIGH),a ld a,c + ld (IDE_SECCNT),a ; Se duplica env�o de comando para refrescar sin error la FLASHJACKS. ld (IDE_SECCNT),a pop af @@ -917,7 +961,9 @@ DEV_RW_NO0SEC: ;--- ;--- READ ;--- - + + call WAIT_CMD_RDY + jr c,DEV_RW_ERR ld a,20h push bc ;Save sector count call DO_IDE @@ -933,10 +979,53 @@ DEV_R_GDATA: push bc ld hl,IDE_DATA ld bc,512 - ldir - pop bc - djnz DEV_R_GDATA +BUCLE_R_GDATA: + di ; Se desactivan peticiones de interrupciones para evitar intromisiones. + ld a,(IDE_STATUS) + bit BSY,a + jr nz,BUCLE_R_GDATA ; Hace una comprobaci�n al inicio y deja paso cuando la FLASHJACKS informa que puede continuar. + ;ld a,(hl) ; Esto est� anulado ya que se trata del mismo proceso que hace ldir pero en muchos mas ciclos de reloj. Proceso muy lento. + ;ld (de),a + ;inc hl + ;inc de + ;dec bc + ;ld a,b + ;or c + ;jr nz,BUCLE_R_GDATA ; Esto est� anulado ya que se trata del mismo proceso que hace ldir pero en muchos mas ciclos de reloj. + + ;ldir ; Volcado ultrar�pido. Usar el del LDI(mas abajo) si se reportan anomal�as (Psycho world en DSK es bueno para probarlo). + ;CALL VOLCADO ; Es un ldir un 21% m�s r�pido. + + +BUCLE_R2_GDATA: + ldi ; 8x LDI + 8x nop Hacemos una espera en cada byte de volcado para dejar a la Flashjacks que se refresque a tiempo.(En un manual de asm es un modo r�pido de copia) + nop ; Esto solo es para sistemas ultra r�pidos como el TurboR. Esto hace lectura y ciclo refresco, bucle hasta fin. + ldi ; Es el m�todo m�s estable. (pero no el m�s r�pido. Mas r�pido ldir y a�n m�s call VOLCADO) + nop ; Los otros funcionan pero cuando hay algo en el otro slot, provoca fallos. (Ejemplo Music module slot 1 y FlashJacks slot 2) + ldi + nop + ldi + nop + ldi + nop + ldi + nop + ldi + nop + ldi + nop + jp pe,BUCLE_R2_GDATA + +BUCLE_R_FIN: + ld a,(IDE_STATUS) + bit BSY,a + jr nz,BUCLE_R_FIN ; Hace una comprobaci�n al final y deja paso cuando la FLASHJACKS informa que puede continuar. + pop bc + call WAIT_IDE + + dec b + jp nz,DEV_R_GDATA call IDE_OFF xor a ret @@ -946,6 +1035,8 @@ DEV_R_GDATA: ;--- DEV_DO_WR: + call WAIT_CMD_RDY + jr c,DEV_RW_ERR ld a,30h push bc ;Save sector count call DO_IDE @@ -957,7 +1048,8 @@ DEV_W_LOOP: push bc ld de,IDE_DATA ld bc,512 - ldir + ldir ; Se deja ldir por mayor estabilidad. + ;CALL VOLCADO ; Es un ldir un 21% m�s r�pido.(Por estabilidad se quita) pop bc call WAIT_IDE @@ -965,8 +1057,9 @@ DEV_W_LOOP: call DEV_RW_FAULT ret nz - - djnz DEV_W_LOOP + + dec b + jp nz,DEV_W_LOOP call IDE_OFF xor a @@ -984,26 +1077,26 @@ DEV_RW_ERR: bit NM,a ;Not ready jr nz,DEV_R_ERR1 - ld a,.NRDY + ld a,NRDY ld b,0 ret DEV_R_ERR1: bit IDNF,a ;Sector not found jr nz,DEV_R_ERR2 - ld a,.RNF + ld a,RNF ld b,0 ret DEV_R_ERR2: bit WP,a ;Write protected jr nz,DEV_R_ERR3 - ld a,.WPROT + ld a,WPROT ld b,0 ret DEV_R_ERR3: - ld a,.DISK ;Other error + ld a,DISK ;Other error ld b,0 ret @@ -1016,7 +1109,7 @@ DEV_RW_FAULT: ret z call IDE_OFF - ld a,.DISK + ld a,DISK ld b,0 or a ret @@ -1026,18 +1119,17 @@ DEV_RW_FAULT: DEV_RW_NOSEC: call IDE_OFF pop af - ld a,.RNF + ld a,RNF ld b,0 ret DEV_RW_NODEV: call IDE_OFF pop af - ld a,.IDEVL + ld a,IDEVL ld b,0 ret - ;----------------------------------------------------------------------------- ; ; Device information gathering @@ -1142,6 +1234,8 @@ DEV_STRING_LOOP: ld a,d cp 33 jr nc,DEVSTRLOOP_1 + cp 126 + jr c,DEVSTRLOOP_1 ld a," " DEVSTRLOOP_1: ld (hl),a @@ -1149,6 +1243,8 @@ DEVSTRLOOP_1: ld a,e cp 33 jr nc,DEVSTRLOOP_2 + cp 126 + jr c,DEVSTRLOOP_2 ld a," " DEVSTRLOOP_2: ld (hl),a @@ -1196,8 +1292,9 @@ DEV_INFO_ERR2: ;Corrupts AF, DE DEV_STING_PREPARE: + call WAIT_CMD_RDY ld a,c ;Issue IDENTIFY DEVICE command - call WRHEAD + ld (IDE_HEAD),a ld a,0ECh call DO_IDE ret c @@ -1265,15 +1362,6 @@ DEV_STATUS: ld a,1 ret nz - ;ld a,(TESTADD) - ;or a - ;ld a,2 - ;ld (TESTADD),a - ;ret z - - ;ld a,1 ;Device is non-removable - ;ret - ld a,e dec a ;FOR TESTING: ld a,2 ;Return "Unchanged" for device 1, "Unknown" for device 2 @@ -1328,7 +1416,12 @@ LUN_INFO: jr z,LUN_INFO2 ld a,M_DEV LUN_INFO2: - call WRHEAD + ld e,a + call WAIT_CMD_RDY + jr c,LUN_INFO_ERROR + ld a,e + + ld (IDE_HEAD),a ld a,0ECh call DO_IDE @@ -1342,7 +1435,7 @@ LUN_INFO2: ld (ix+9),h ld hl,(IDE_DATA) ;Skip word 2 ld hl,(IDE_DATA) - ld (ix+10),l ;Word 3: Heades + ld (ix+10),l ;Word 3: Heads ld hl,(IDE_DATA) ld hl,(IDE_DATA) ;Skip words 4,5 ld hl,(IDE_DATA) @@ -1438,7 +1531,7 @@ LUN_INFO_ERROR: ; FFh: 5.25" Double sided, 40 tracks per side, 8 sectors per track (320K) DEV_FORMAT: - ld a,.IFORM + ld a,IFORM ret @@ -1469,9 +1562,6 @@ DEV_CMD: ld a,2 ret -endif - - ;===== ;===== END of DEVICE-BASED specific routines ;===== @@ -1497,128 +1587,81 @@ IDE_OFF: ld (IDE_BANK),a ret +;----------------------------------------------------------------------------- +; +; Wait the BSY flag to clear and RDY flag to be set +; if we wait for more than 30s, send a soft reset to IDE BUS +; if the soft reset didn't work after 30s return with error +; +; Input: Nothing +; Output: Cy=1 if timeout after soft reset +; Preserves: DE and BC +WAIT_CMD_RDY: + push de + push bc + ld de,8142 ;Limit the wait to 30s +WAIT_RDY1: + ld b,255 +WAIT_RDY2: + ld a,(IDE_STATUS) + and M_BSY+M_DRDY + cp M_DRDY + jr z,WAIT_RDY_END ;Wait for BSY to clear and DRDY to set + djnz WAIT_RDY2 ;End of WAIT_RDY2 loop + dec de + ld a,d + or e + jr nz,WAIT_RDY1 ;End of WAIT_RDY1 loop + scf +WAIT_RDY_END: + pop bc + pop de + ret + ;----------------------------------------------------------------------------- ; ; Execute a command ; ; Input: A = Command code ; Other command registers appropriately set -; Output: Cy=1 if timeout on BSY clear or if ERR bit in status register set +; Output: Cy=1 if ERR bit in status register set -DO_IDE: - ld (IDE_CMD),a - ;ex (sp),hl ;Not necessary - WAIT_BUSY introduces delay already - ;ex (sp),hl +DO_IDE: di + ld (IDE_CMD),a ; Se duplica env�o de comando para refrescar sin error la FLASHJACKS. + ld (IDE_CMD),a WAIT_IDE: - call WAIT_BUSY - jr c,DO_IDE_TOUT - bit DRQ,a - jr z,WAIT_IDE - - rrca - ret - -DO_IDE_TOUT: - pop af - scf - ret - - -;Wait for the BUSY flag to clear. -;If we spend 30 seconds waiting, return Cy set. -;Returns A=last value of IDE_STATUS read (except if timeout occurs). - -WAIT_BUSY: - push bc - push de - ld bc,1500 - ld a,(TIMEVAR) - ld d,a - -WBUSY_LOOP: + nop ; Wait 50us + nop ; Wait 50us ld a,(IDE_STATUS) - bit BSY,a - jr z,WBUSY_END - - ld a,(TIMEVAR) - cp d - jr z,WBUSY_LOOP - ld d,a - - dec bc - ld a,b - or c - jr nz,WBUSY_LOOP - scf - -WBUSY_END: - pop de - pop bc - ret - - ;--- This is the same as DO_IDE - ; but writes E to IDE_HEAD while waiting - -DO_IDE2: - ld (IDE_CMD),a - ;ex (sp),hl ;Not necessary - WAIT_BUSY introduces delay already - ;ex (sp),hl - -WAIT_IDE2: - call WAIT_BUSY2 - jr c,DO_IDE_TOUT2 bit DRQ,a - jr z,WAIT_IDE2 + jr nz,IDE_END + bit BSY,a + jr nz,WAIT_IDE +IDE_END: rrca ret -DO_IDE_TOUT2: - pop af - scf - ret - -WAIT_BUSY2: - push bc - push de - ld bc,1500 - ld a,(TIMEVAR) - ld d,a - -WBUSY_LOOP2: - ld a,e - ld (IDE_HEAD),a - ld a,(IDE_STATUS) - bit BSY,a - jr z,WBUSY_END2 - - ld a,(TIMEVAR) - cp d - jr z,WBUSY_LOOP2 - ld d,a +;----------------------------------------------------------------------------- +; +; Read the keyboard matrix to see if ESC is pressed +; Output: Cy = 1 if pressed, 0 otherwise - dec bc - ld a,b - or c - jr nz,WBUSY_LOOP2 +CHECK_ESC: + ld b,7 + in a,(0AAh) + and 11110000b + or b + out (0AAh),a + in a,(0A9h) + bit 2,a + jr nz,CHECK_ESC_END scf - -WBUSY_END2: - pop de - pop bc - ret - - -;Write A to the HEAD register - -WRHEAD: - ;call WAIT_BUSY - ld (IDE_HEAD),a +CHECK_ESC_END: ret - ;----------------------------------------------------------------------------- ; ; Print a zero-terminated string on screen @@ -1694,23 +1737,112 @@ CHECK_DEV_LUN: or a ret +;----------------------------------------------------------------------------- +; +; Hace un volcado de 512 bytes. +VOLCADO: + REPT 512 ; esto es un 21% m�s r�pido que el ldi + ldi + ENDM + ret + +;---------------------------------------------------------------------------------- +;Turn On Turbo CPU: MSX CIEL, Panasonic 2+,Panasonic Turbo R, special TurboCPU kits +; +;Input: Nothing +;Output: Nothing + +putTURBO_CPU: + +CHGTURCIEL equ 01387h ; CIEL Expert3 bizarre turbo routine + +_TURBO3: +; ; Expert 3 CIEL +; ; Test if the CIEL change-turbo routine signature is in ROM + ld hl,CHGTURCIEL + ld de,CIELSIGN + ld c,2 + +_CIEL1: ld b,3 +_CIEL2: ld a,(hl) + ld ixh,a + ld a,(de) + cp ixh + jr nz,NOTCIEL + inc hl + inc de + djnz _CIEL2 + ld hl,CHGTURCIEL+0Ch + dec c + ld a,c + or a + jr nz,_CIEL2 + call CHGTURCIEL + db 1 ; Padding to make the CIELSIGN inert +CIELSIGN: DEFB 0A7h,0FAh,093h,013h,0DBh,0B6h + +NOTCIEL: + +;------------------------------------------------------------------------------ + ;Check for Panasonic 2+ + LD A,8 + OUT (040H),A ;out the manufacturer code 8 (Panasonic) to I/O port 40h + IN A,(040H) ;read the value you have just written + CPL ;complement all bits of the value + CP 8 ;if it does not match the value you originally wrote, + JR NZ,Not_WX ;it is not a WX/WSX/FX. + XOR A ;write 0 to I/O port 41h + OUT (041H),A ;and the mode changes to high-speed clock + + + jr end_turbo + +Not_WX: ld a,(0180h) ;Turbo R or Turbo CPU kits with JUMP in 0180h + cp 0c3h + ;no_turbo + jr nz,end_turbo + ld a,081h ;ROM Mode... for DRAM Mode-> 82h + call 0180h + +end_turbo: + + ret +;--------------------------------------------------------------- + ;======================= ; Strings ;======================= INFO_S: - db "Sunrise IDE device-based driver",13,10 - db "(c) Konamiman 2009",13,10,13,10,0 + db "FLASHJACKS IDE driver v" + db VER_MAIN+"0",".",VER_SEC+"0",".",VER_REV+"0",13,10 + db "(c) Konamiman 2009",13,10 + db "(c) Aquijacks 2018",13,10,13,10,0 + +SEARCH_S: + db "Buscando: ",0 NODEVS_S: - db "No IDE devices found.",13,10,0 + db "No encontrada",13,10,0 MASTER_S: - db "Master device: ",0 -SLAVE_S: - db "Slave device: ",0 + db "Unidad: ",0 CRLF_S: db 13,10,0 +MODELO: + db "Modelo: ",0 +M_MSX1: + db "MSX1",13,10,13,10,0 +M_MSX2: + db "MSX2",13,10,13,10,0 +M_MSX2M: + db "MSX2+",13,10,13,10,0 +M_MSXR: + db "MSX TurboR",13,10,13,10,0 +M_OCM: + db "OCM",13,10,13,10,0 +M_NDTC: + db "No detectado",13,10,13,10,0 ;----------------------------------------------------------------------------- @@ -1719,6 +1851,8 @@ CRLF_S: DRV_END: - ;ds 3FD0h-(DRV_END-DRV_START) + ds 3ED0h-(DRV_END - DRV_START) end + + diff --git a/source/kernel/drivers/MegaFlashRomSD/driver-1slot.dat b/source/kernel/drivers/MegaFlashRomSD/driver-1slot.dat new file mode 100644 index 0000000000000000000000000000000000000000..cf812a68264ac09ba0e9f83a5080a03f2695379e GIT binary patch literal 11370 zcmeHNe@q+K9e-!w2sD6yB%AA`&bj9$mrg{GO4!Qe!w83jWyTCMLRF3Vu&>0%IS1S% zCQVP>x|UX}wrUfa*k4g6tyTVUQ?2!?X%@zV@i<*ok~M-#8MO!;~*7=(gGs zhH+r(IOFAHYlz44yppWeVQO@|T=^)X; zJVlq)BJ9E#dpO#|?c*t|L}`jg6A+s=a8yMax0D0TQRTH%8n1a~{~Yp^sGD~}HIsKj zMVJE#ZwaruYt^?SFp2esG8*ADRv&DQ)@a0+@G7+LVq&uD{(Jt@m}j zYEZO3VLU)r5sRPzH(fz^Uy-E&H6375rWWzt2Pe zytVugT>rX%Wcu0%Ub6)U9KR7{_I++|hO3%VuM1Ud&iZLBTIQX5*(|fZ1goVw1xZLI zq-fY_=uRZhMf(M3Sx}IC(d3}BoD2Hf>x0cl=`K+clS0yI@(Geye=;tHo%@5r`Q*j( z15RtZ^h{I|6Oz-yory{Vej(L-)M?{7zugY~0WO%3Mu0fTbq@c|CDKl>EV7C;E;wC?zgS zPS32M?Zcb>fmF$G^UeO^2yDpquI8cyAGZ-6whpcm+8^@w=fc&NqbAIC-F&gWlpJDLz|1KVU^hu8~jk{xEX zebIPCk|t63`xwHlO?|YiJ{dk$S65dE1!&}`+N@e$Tw0pTt!8ExS^V)^ASfe(+(wmL zc;QBXg-b5%y@A(w?{O4bg}zqn)l1>|30TF;eA#ccH)t9LAEYr|eFAkF*VUgyyyPVw zv%flDD3&PuD-*yvjSzKx)IK_2qL_{q`^z$dU!krOY$Y<{sq~vyiq^ zM72fZLmci8c9g*m@}eeaAKqi|LKu-;`mFgw<9}TEqlG0{VjH&y-g~x#ZNqk? z^~&RlNih;15<-{J1vG?)Q4%$Q`LQkQdgg%(-!&nx4WWD2KL6dd*=S_j@n36DJ0pCT znusj84`g)f~u?9DQp>V%lh)=&OE!hZ{dE3luWckvsTY-e8>wvYLn`+m*jI}v`< zg_pt2!cxjJ8xj}zr!;rI3~yjOCy*EBz;BqRz~f!pU0cp(D;z3SOg4+^xM+mg@SA3Y zY&IAHpyT3hh6_VFfmk`7Vv6q7d?~WP_Y&uKUK2BuKNrdB_>y_svkhsU88fVofz+^V z%P9?z9;Ybu0?Z}D?0F=0gIUYDaBhcJ`i!Fq^PjF9{v0Qr(h<-R__85D@^mLc1~m2| zB%XQhzKd|asby|=4WwJXM5FACaRc~7{ufQ&zLnW`#9X;?-GxcsW?Whk1IJB3E|i_^ zL$Y#2u_)%P7FcZxqkQ%Iw=304F`wU}z8KT=GnlS~T1PH42YOH+O#^KaVnI8Cw7*~3 zx7Ds>@ET+^0nB~fmU#j4$s=Nt=%)ZB2Oy%fNIDZc8+s{;L zCo!A`s@G+v=hP$t3&v8B(^6`DyJS3sSz z!#w=3Dxt1bkiukpT((0zEKU4^bWw~mox+twl6;Pe{B2$EWh(hfm6UwIXlSV4z8i@G zX#B5FStG+yD9mcAp>|6~6B5&S?8%yHE_{^vLV)89jliy{Mi3$_3`dw`Jn<}pNVEuv l_DtfU6gdWRzrR(}3bul$)DC%kn>u{{nH_kg5Ox literal 0 HcmV?d00001 diff --git a/source/kernel/drivers/MegaFlashRomSD/driver-2slots.dat b/source/kernel/drivers/MegaFlashRomSD/driver-2slots.dat new file mode 100644 index 0000000000000000000000000000000000000000..68e00b59365e8dfc771ca06b6cb96f6182e3ffa1 GIT binary patch literal 11370 zcmeHNe@q+K9e-!T5oiGaNH*6=opaAiE}e)Vm9Uk`hY=15%ZwRjgsK|zVPA=ja}IWs zm^8JzbuFz{ZPg|;vA?2DTC4oyrdsP&(=3b!<8ivGBx?kz(8eOHYAkD*$Ce3j_k9PX zRN9~WuXjGb_kG{*_kF+beZF_!_xYH&BAg*SqQzk>2W;dcXt+EBp| za^l@`jn)v*5YQ0N5YQ0N5YQ0N5YQ0N5YQ0N5YQ0N5YQ0N5YQ0N5YQ0N5YQ0N5YQ0N z5YQ0N5YQ0N5YQ0#e;|OfOobgGZ2Wjg`9-u2DZh*|dyEY+GN5SPREgKUu9!o$OvR#% zZY!N382hJ=qduiSr1XaJ>n;cLc$@JMnJ_Zlq`ZOn6VRlp>;tiv;;)Sj_Orbp${XG_ z9wa)Lr)Yg0!cL5_o1@*_KAysIgr;~j0lsNHM^$EUYX#68RZ&M}@S1z}&p~%tck@oL zcJfZJ1ZyDf&7oCSo$_`V7O~!_rxDIz<-yiyjYfPKuR{ASCR0{je=mF*b}$!z(Cp+22X zQ)RdBAK(IUX#|LaTu(xfk|9wF!{{-t zwZYrk(+cE~UNJEsJR3RhaB^olI#2mp`+(c(Khxnz1|qRbV&Zg<<9hspDER_?4)h&q zNQz&U9PU{`jl-J*{uG4c&4JPg1Y|p^`3S+sWq^mRldFRE$Gi?683=Ca);K?UYaB1y zC(z~-6C27wgx#|V)l^LgOi`0Hp=A=(k*&u=DMkJ`E)sKI-;>j35kbvyL5RFR)2A z!K!glc|?*SUikYM+^tQ0w5&WCI#pj^Ukv(bWUt<=US3>Un#-?dXBJuf@mnC!6G48X zI$eC>hM$EiUEF&EukoJaD7XrJo!TpxLh}=_i8W2(d9{ z`{8_%DpTB_fOADvu)R2M`@u>&m&?hQZ90xR2oK-G$?{p|F);8`)xehe&*p)-M?S?Y zWNZ{sZB_Z;hx>yKWw9N3(g-zsP&2d-?=g5G3@BaxtmQ+)f1LQEg(cWxJGTekd$yBp z$2O$)^5e2mHV_*ULYL76G>j4`iJD>hv8~w+%mXLBYeXI^LietH{<~|n(#X1FzfPxg zh52qJ9$s)A&NA!@Up{x(lVdiO2{D&znEZX1{}u>WAfBXm@*9|hvp)pkWB%s4Upx6u znBR2bWiYd_lyc7o#RdK;)tooW>lpV5T6+c-MN@nzveuhsu?cEuu0m8eld2 zrU@ad6-EH)xVW3)#E?$FSDvSsl54e44lnS1#Q2@p#O&nHMY21-Y}&SLMXF`S1iND( zHEhr2tmU0Jzr!nk#?gfNPiG!~j*~`d2xtg=*$^Okx(gv4 z8v76u&pdbENjTqBGqd*G0w0uN1%ciXsSnV<+fA#yftCUMoug|Q!7*+MNn683aCtYmu_o9B92HGq{12zO{ zf4{tMt6jR-yo_r;Wt=SnUB+Zt8 zm-yG=Fom@mA3=}yvT63V?w!d`qVLUq620gBRgMK3j$e1V>Lw6r_C3yQtU!;#`Ey|3 zex^!2iQzOL2lB6R$?7*-&pt(tguO#c4#%81Z}^8QgZ#UEMm`}Q*!_QQnz$Y*){jnm z29Ke+!h}eQM;Y}pdZ-r+mBzP*Ec>B*f5=h?-RzL1O06q0c!e@TnFuGumOe*Us#7w! z66%y4=HZ7`33aWK6eina{SNW4H1P@2MKQ*730LAt@;NH0 at input: -; A = 0: Ok, device formatted -; Other: error code, same as DEV_RW plus: -; .IPARM: Invalid format choice -; .IFORM: Invalid device or logical unit number, -; or device not formattable -; B = Media ID if the device is a floppy disk, zero otherwise -; (only if A=0 is returned) -; -; Media IDs are: -; F0h: 3.5" Double Sided, 80 tracks per side, 18 sectors per track (1.44MB) -; F8h: 3.5" Single sided, 80 tracks per side, 9 sectors per track (360K) -; F9h: 3.5" Double sided, 80 tracks per side, 9 sectors per track (720K) -; FAh: 5.25" Single sided, 80 tracks per side, 8 sectors per track (320K) -; FBh: 3.5" Double sided, 80 tracks per side, 8 sectors per track (640K) -; FCh: 5.25" Single sided, 40 tracks per side, 9 sectors per track (180K) -; FDh: 5.25" Double sided, 40 tracks per side, 9 sectors per track (360K) -; FEh: 5.25" Single sided, 40 tracks per side, 8 sectors per track (160K) -; FFh: 5.25" Double sided, 40 tracks per side, 8 sectors per track (320K) - -DEV_FORMAT: - ld a,.IFORM - ret - - -;----------------------------------------------------------------------------- -; -; Execute direct command on a device -; -;Input: A = Device number, 1 to 7 -; B = Logical unit number, 1 to 7 (if applicable) -; HL = Address of input buffer -; DE = Address of output buffer, 0 if not necessary -;Output: Output buffer appropriately filled (if applicable) -; A = Error code: -; 0: Ok -; 1: Invalid device number or logical unit number, -; or device not ready -; 2: Invalid or unknown command -; 3: Insufficient output buffer space -; 4-15: Reserved -; 16-255: Device specific error codes -; -; The first two bytes of the input and output buffers must contain the size -; of the buffer, not incuding the size bytes themselves. -; For example, if 16 bytes are needed for a buffer, then 18 bytes must -; be allocated, and the first two bytes of the buffer must be 16, 0. - -DEV_CMD: - ld a,2 - ret - -endif - - -;===== -;===== END of DEVICE-BASED specific routines -;===== - - -;======================= -; Subroutines -;======================= - -;----------------------------------------------------------------------------- -; -; Enable or disable the IDE registers - -;Note that bank 7 (the driver code bank) must be kept switched - -IDE_ON: - ld a,1+7*32 - ld (IDE_BANK),a - ret - -IDE_OFF: - ld a,7*32 - ld (IDE_BANK),a - ret - - -;----------------------------------------------------------------------------- -; -; Execute a command -; -; Input: A = Command code -; Other command registers appropriately set -; Output: Cy=1 if ERR bit in status register set - -DO_IDE: - ld (IDE_CMD),a - -WAIT_IDE: - ld a,(IDE_STATUS) - bit DRQ,a - jr nz,IDE_END - bit BSY,a - jr nz,WAIT_IDE - -IDE_END: - rrca - ret - - -;----------------------------------------------------------------------------- -; -; Print a zero-terminated string on screen -; Input: DE = String address - -PRINT: - ld a,(de) - or a - ret z - call CHPUT - inc de - jr PRINT - - -;----------------------------------------------------------------------------- -; -; Obtain the work area address for the driver -; Input: A=1 to obtain the work area for the master, 2 for the slave -; Preserves A - -MY_GWORK: - push af - xor a - EX AF,AF' - XOR A - LD IX,GWORK - call CALBNK - pop af - cp 1 - ret z - inc ix - inc ix - inc ix - inc ix - ret - - -;----------------------------------------------------------------------------- -; -; Check the device index and LUN -; Input: A = device index, B = lun -; Output: Cy=0 if OK, 1 if device or LUN invalid -; IX = Work area for the device -; Modifies F, C - -CHECK_DEV_LUN: - or a ;Check device index - scf - ret z - cp 3 - ccf - ret c - - ld c,a - ld a,b ;Check LUN number - cp 1 - ld a,c - scf - ret nz - - push hl - push de - call MY_GWORK - pop de - pop hl - ld c,a - ld a,(ix) - or a - ld a,c - scf - ret z - - or a - ret - - -;======================= -; Strings -;======================= - -INFO_S: - db "Sunrise IDE device-based driver",13,10 - db "(c) Konamiman 2009",13,10,13,10,0 - -NODEVS_S: - db "No IDE devices found.",13,10,0 -MASTER_S: - db "Master device: ",0 -SLAVE_S: - db "Slave device: ",0 -CRLF_S: - db 13,10,0 - - -;----------------------------------------------------------------------------- -; -; Padding up to the required driver size - -DRV_END: - - ;ds 3FD0h-(DRV_END-DRV_START) - - end diff --git a/source/kernel/drivers/SunriseIDE/DRIVER.MAC b/source/kernel/drivers/SunriseIDE/driver.mac similarity index 95% rename from source/kernel/drivers/SunriseIDE/DRIVER.MAC rename to source/kernel/drivers/SunriseIDE/driver.mac index 80139bd8..4bb0845a 100644 --- a/source/kernel/drivers/SunriseIDE/DRIVER.MAC +++ b/source/kernel/drivers/SunriseIDE/driver.mac @@ -818,6 +818,9 @@ DRV_DIRECT4: ; C = LUN index DRV_CONFIG: + ld a,1 + ret + dec a jr z,DRV_CONFIG_1 dec a @@ -835,7 +838,10 @@ DRV_CONFIG_1: ret DRV_CONFIG_2: - ld a,1 + ld b,c + inc b + ld c,1 + xor a ret @@ -868,6 +874,11 @@ DRV_CONFIG_2: ; B = Number of sectors actually read/written DEV_RW: + ;jr nc,kk + ;ld a,0F8h ;.WPROT + ;ld b,0 + ;ret +kk: push af ld a,b ;Swap B and C diff --git a/source/kernel/drivers/SunriseIDE/sunride.asm b/source/kernel/drivers/SunriseIDE/sunride.asm new file mode 100644 index 00000000..bb683d02 --- /dev/null +++ b/source/kernel/drivers/SunriseIDE/sunride.asm @@ -0,0 +1,3315 @@ + ; Device-based driver for the sunrise IDE interface for Nextor + ; + ; Version 0.1.7 + ; By Konamiman + ; By Piter Punk + ; By FRS + + org 4000h + ds 4100h-$,0 ; DRV_START must be at 4100h +DRV_START: + +TESTADD equ 0F3F5h + +;----------------------------------------------------------------------------- +; +; Driver configuration constants +; + +;Driver type: +; 0 for drive-based +; 1 for device-based + +DRV_TYPE equ 1 + +;Hot-plug devices support (device-based drivers only): +; 0 for no hot-plug support +; 1 for hot-plug support + +DRV_HOTPLUG equ 0 + +DEBUG equ 0 ;Set to 1 for debugging, 0 to normal operation + +;Driver version + +VER_MAIN equ 0 +VER_SEC equ 1 +VER_REV equ 7 + + +;Miscellaneous configuration + DEFINE PIOMODE3 ; Configure devices to work on PIO MODE 3 + + +;This is a very barebones driver. It has important limitations: +;- CHS mode not supported, disks must support LBA mode. +;- 48 bit addresses are not supported +; (do the Sunrise IDE hardware support them anyway?) +;- ATAPI devices not supported, only ATA disks. + + +;----------------------------------------------------------------------------- +; +; IDE registers and bit definitions + +IDE_BANK equ 4104h ;bit 0: enable (1) or disable (0) IDE registers + ;bits 5-7: select 16K ROM bank +IDE_DATA equ 7C00h ;Data registers, this is a 512 byte area +IDE_ERROR equ 7E01h ;Error register +IDE_FEAT equ 7E01h ;Feature register +IDE_SECCNT equ 7E02h ;Sector count +IDE_SECNUM equ 7E03h ;Sector number (CHS mode) +IDE_LBALOW equ 7E03h ;Logical sector low (LBA mode) +IDE_CYLOW equ 7E04h ;Cylinder low (CHS mode) +IDE_LBAMID equ 7E04h ;Logical sector mid (LBA mode) +IDE_CYHIGH equ 7E05h ;Cylinder high (CHS mode) +IDE_LBAHIGH equ 7E05h ;Logical sector high (LBA mode) +IDE_HEAD equ 7E06h ;bits 0-3: Head (CHS mode), logical sector higher (LBA mode) +IDE_STATUS equ 7E07h ;Status register +IDE_CMD equ 7E07h ;Command register +IDE_DEVCTRL equ 7E0Eh ;Device control register + +; Bits in the error register + +UNC equ 6 ;Uncorrectable Data Error +WP equ 6 ;Write protected +MC equ 5 ;Media Changed +IDNF equ 4 ;ID Not Found +MCR equ 3 ;Media Change Requested +ABRT equ 2 ;Aborted Command +NM equ 1 ;No media + +M_ABRT equ 100b ;(1 SHL ABRT) + +; Bits in the head register + +DEV equ 4 ;Device select: 0=master, 1=slave +LBA equ 6 ;0=use CHS mode, 1=use LBA mode + +M_DEV equ 10000b ;(1 SHL DEV) +M_LBA equ 1000000b ;(1 SHL LBA) + +; Bits in the status register + +BSY equ 7 ;Busy +DRDY equ 6 ;Device ready +DF equ 5 ;Device fault +DRQ equ 3 ;Data request +ERR equ 0 ;Error + +M_BSY equ 10000000b ;(1 SHL BSY) +M_DRDY equ 1000000b ;(1 SHL DRDY) +M_DF equ 100000b ;(1 SHL DF) +M_DRQ equ 1000b ;(1 SHL DRQ) +M_ERR equ 1b ;(1 SHL ERR) + +; Bits in the device control register register + +nIEN equ 1 ;Disable interrupts +SRST equ 2 ;Software reset + +M_nIEN equ 10b ;(1 SHL nIEN) +M_SRST equ 100b ;(1 SHL SRST) + +; IDE commands + +ATACMD: +.PRDSECTRT equ #20 +.PWRSECTRT equ #30 +.DEVDIAG equ #90 +.IDENTIFY equ #EC +.SETFEATURES equ #EF + +ATAPICMD: +.RESET equ #08 +.PACKET equ #A0 +.IDENTPACKET equ #A1 + +PACKETCMD: +.RQSENSE equ #03 ; +.RDCAPACITY equ #25 ; Read the media capacity +.READ10 equ #28 ; Read sectors (16bit) +.READ12 equ #A8 ; Read sectors (32bit) +.WRITE10 equ #2A ; Write sectors (16bit) +.WRITE12 equ #AA ; Write sectors (32bit) +.GTMEDIASTAT equ #DA ; Get media status + + +;----------------------------------------------------------------------------- +; +; Standard BIOS entries +CALSLT equ #001C +DCOMPR equ #0020 ; Compare register pairs HL and DE +INITXT equ #006C +CHSNS equ #009C ; Sense keyboard buffer for character +CHGET equ #009F ; Get character from keyboard buffer +CHPUT equ #00A2 ; A=char +BREAKX equ #00B7 ; Check CTRL-STOP key directly +CLS equ #00C3 ; Chamar com A=0 +ERAFNK equ #00CC ; Erase function key display +SNSMAT equ #0141 ; Read row of keyboard matrix +KILBUF equ #0156 ; Clear keyboard buffer +EXTROM equ #015F +CHGCPU equ #0180 +GETCPU equ #0183 + +; subROM functions +SDFSCR equ #0185 +REDCLK equ #01F5 + +; System variables +MSXVER equ #002D +LINL40 equ #F3AE ; Width +LINLEN equ #F3B0 +BDRCLR equ #F3EB +BASROM equ #FBB1 +INTFLG equ #FC9B +JIFFY equ #FC9E +SCRMOD equ #FCAF +EXPTBL equ #FCC1 + + +;----------------------------------------------------------------------------- +; +; Work area definition +; +;+0: Device and logical units types for master device +; bits 0,1: Device type +; 00: No device connected +; 01: ATA hard disk, CHS only +; 10: ATA hard disk, LBA supported +; 11: ATAPI device +; bits 2,3: Device type for LUN 1 on master device +; 00: Block device, non-removable +; 01: Block device, removable +; 10: Other, non removable +; 11: CD-ROM +; bits 4,5: Device type for LUN 2 on master device +; bits 6,7: Device type for LUN 3 on master device +; Inside DRV_INIT only: b7=1 error detected on diagnostics +; b6~b0: reported error code +; +;+1: Logical unit types for master device +; bits 0,1: Device type for LUN 4 on master device +; bits 2,3: Device type for LUN 5 on master device +; bits 4,5: Device type for LUN 6 on master device +; bits 6,7: Device type for LUN 7 on master device +; +;+2,3: Reserved for CHS data for the master device (to be implemented) +; +;+4..+7: Same as +0..+3, for the slave device +; +; Note: Actually, due to driver limitations, currently only the +; "device type" bits are used, and with possible values 00 and 10 only. +; LUN type bits are always 00. + + + STRUCT DEVINFO ; Contains information about a specific device +BASE ; Offset to the base of the data structure +t321D db +t7654 db +;CHSRESERVED ds 2 ; Disabled to save space. 2 bytes won't be enough anyway +SECTSIZE dw ; Sector size for this device +pBASEWRK dw ; Cache pointer to go back to the base of the work area + ENDS + + STRUCT WRKAREA +BASE ; Offset to the base of the data structure +BLKLEN dw ; Size of the block to be copied. ***Must be + ; \the first element of the WRKAREA +PCTBUFF ds 16 ; Buffer to send ATAPI PACKET commands +LDIRHLPR ds 8 ; LDIR data transter helper routine. This is + ; in RAM to speed up the R800 copy a lot. +MASTER DEVINFO ; Offset to the MASTER data structure +SLAVE DEVINFO ; Offset to the SLAVE data structure + ; \*** It must follow the MASTER DEVINFO + ENDS + + STRUCT WRKTEMP +pDEVMSG dw ; Pointer to the text "Master:" or "Slave:" +BUFFER ds 512 ; Buffer for the IDENTIFY info + ENDS + +; ATAPI/SCSI packet structures + STRUCT PCTRW10 ; PACKET READ10/WRITE10 structure +OPCODE db +OPTIONS db +LBA dd +GROUP db +LENGHT dw +CONTROL db + ENDS + + STRUCT PCTRW12 ; PACKET READ12/WRITE12 structure +OPCODE db +OPTIONS db +LBA dd +LENGHT dd +GROUP db +CONTROL db + ENDS + + + + +;----------------------------------------------------------------------------- +; +; Error codes for DEV_RW and DEV_FORMAT +; + +_NCOMP equ 0FFh +_WRERR equ 0FEh +_DISK equ 0FDh +_NRDY equ 0FCh +_DATA equ 0FAh +_RNF equ 0F9h +_WPROT equ 0F8h +_UFORM equ 0F7h +_SEEK equ 0F3h +_IFORM equ 0F0h +_IDEVL equ 0B5h +_IPARM equ 08Bh + +;----------------------------------------------------------------------------- +; +; Routines available on kernel page 0 +; + +;* Get in A the current slot for page 1. Corrupts F. +; Must be called by using CALBNK to bank 0: +; xor a +; ld ix,GSLOT1 +; call CALBNK + +GSLOT1 equ 402Dh + + +;* This routine reads a byte from another bank. +; Must be called by using CALBNK to the desired bank, +; passing the address to be read in HL: +; ld a,bank +; ld hl,address +; ld ix,RDBANK +; call CALBNK + +RDBANK equ 403Ch + + +;* This routine temporarily switches kernel bank 0/3, +; then jumps to CALBAS in MSX BIOS. +; This is necessary so that kernel bank is correct in case of BASIC error. + +CALBAS equ 403Fh + + +;* Call a routine in another bank. +; Must be used if the driver spawns across more than one bank. +; Input: A = bank +; IX = routine address +; AF' = AF for the routine +; BC, DE, HL, IY = input for the routine + +CALBNK equ 4042h + + +;* Get in IX the address of the SLTWRK entry for the slot passed in A, +; which will in turn contain a pointer to the allocated page 3 +; work area for that slot (0 if no work area was allocated). +; If A=0, then it uses the slot currently switched in page 1. +; Returns A=current slot for page 1, if A=0 was passed. +; Corrupts F. +; Must be called by using CALBNK to bank 0: +; ld a,slot +; ex af,af' +; xor a +; ld ix,GWORK +; call CALBNK + +GWORK equ 4045h + + +;* Call a routine in the driver bank. +; Input: (BK4_ADD) = routine address +; AF, BC, DE, HL, IY = input for the routine +; +; Calls a routine in the driver bank. This routine is the same as CALBNK, +; except that the routine address is passed in address BK4_ADD (#F2ED) +; instead of IX, and the bank number is always 5. This is useful when used +; in combination with CALSLT to call a driver routine from outside +; the driver itself. +; +; Note that register IX can't be used as input parameter, it is +; corrupted before reaching the invoked code. + +CALDRV equ 4048h + + +;* Set the current bank +; Must be used exclusively by the MSXBOOT routine +SETBNK equ 7FD0h + + +;----------------------------------------------------------------------------- +; +; Built-in format choice strings +; + +NULL_MSG equ 741Fh ;Null string (disk can't be formatted) +SING_DBL equ 7420h ;"1-Single side / 2-Double side" + + +;----------------------------------------------------------------------------- +; +; Driver signature +; + db "NEXTOR_DRIVER",0 + +; Driver flags: +; bit 0: 0 for drive-based, 1 for device-based +; bit 1: 1 for hot-plug devices supported (device-based drivers only) + + db 1+(2*DRV_HOTPLUG) + +;Reserved byte + db 0 + +;Driver name + +DRV_NAME: + db "Sunrise IDE" + ds 32-($-DRV_NAME)," " + +;Jump table + + jp DRV_TIMI + jp DRV_VERSION + jp DRV_INIT + jp DRV_BASSTAT + jp DRV_BASDEV + jp DRV_EXTBIO + jp DRV_DIRECT0 + jp DRV_DIRECT1 + jp DRV_DIRECT2 + jp DRV_DIRECT3 + jp DRV_DIRECT4 + + ds 15 + + jp DEV_RW + jp DEV_INFO + jp DEV_STATUS + jp LUN_INFO + jp DEV_FORMAT + jp DEV_CMD + + +;----------------------------------------------------------------------------- +; +; Timer interrupt routine, it will be called on each timer interrupt +; (at 50 or 60Hz), but only if DRV_INIT returns Cy=1 on its first execution. + +DRV_TIMI: + ret + + +;----------------------------------------------------------------------------- +; +; Driver initialization, it is called twice: +; +; 1) First execution, for information gathering. +; Input: +; A = 0 +; B = number of available drives (drive-based drivers only) +; HL = maximum size of allocatable work area in page 3 +; Output: +; A = number of required drives (for drive-based driver only) +; HL = size of required work area in page 3 +; Cy = 1 if DRV_TIMI must be hooked to the timer interrupt, 0 otherwise +; +; 2) Second execution, for work area and hardware initialization. +; Input: +; A = 1 +; B = number of allocated drives for this controller +; (255 if device-based driver, unless 4 is pressed at boot) +; +; The work area address can be obtained by using GWORK. +; +; If first execution requests more work area than available, +; second execution will not be done and DRV_TIMI will not be hooked +; to the timer interrupt. +; +; If first execution requests more drives than available, +; as many drives as possible will be allocated, and the initialization +; procedure will continue the normal way +; (for drive-based drivers only. Device-based drivers always +; get two allocated drives.) + +DRV_INIT: + ld hl,WRKAREA ; size of work area + or a ; Clear Cy + ret z + +; 2nd call: + ld a,(CHGCPU) + cp #C3 ; IS CHGCPU present? + jr nz,.call2ini + call GETCPU + push af ; Save the current CPU + ld a,#82 + call CHGCPU ; Enable the turbo +.call2ini: + call MYSETSCR + + ld de,INFO_S + call PRINT + + xor a ; Request the WorkArea base pointer + call MY_GWORK + call INIWORK ; Initialize the work-area + call IDE_ON + +.init: ld (ix+WRKAREA.MASTER.t321D),#FE ; error: No master detected yet + ld de,INIT_S ; Print "Initializing: " + call PRINT + ld a,M_DEV ; Select SLAVE + call WAIT_BSY ; Is the it alive? + jr c,.reset ; No, reset everyone + xor a ; select MASTER + call SELDEV + call WAIT_BSY ; Is the it alive? + jr nc,.diag ; Yes, skip +.reset: + call RESET_ALL +.diag: + ld a,(INTFLG) + cp 3 ; CTRL+STOP pressed? + jp z,INIT_ABORTED + ld a,ATACMD.DEVDIAG ; Both drives will execute diagnostics + ld (IDE_CMD),a + call WAIT_RST ; Wait for the diagnostics to end + ld a,(INTFLG) + cp 3 ; CTRL+STOP pressed? + jp z,INIT_ABORTED + ld a,(IDE_STATUS) + and M_ERR ; Error bit set? + jr nz,.diagchk ; on error, skip to diagnostics + ld (ix+WRKAREA.MASTER.t321D),0 ; Clear undetected master error + +.diagchk: + ; Check the diagnostics and print the results + call CHKDIAG + push af + ld de,INIT_S ; Print "Initializing: " + call PRINT + pop af + ld de,OK_S + call nc,PRINT + ld de,ERROR_S + call c,PRINT + +.chkmaster: + ld de,MASTER_S + ld (TEMP_WORK.pDEVMSG),de + call PRINT + + ; Check for DIAGNOSTICS errors + ld a,(ix+WRKAREA.MASTER.t321D) + ld c,a + bit 7,a ; Any error detected by DIAGNOSE? + jr z,.detinit ; No, skip + call DIAGERRPRT ; Print the diagnostic error + ld (ix+WRKAREA.MASTER.t321D),0 ; This device isn't available + ; Errors 0 and 5 are critical and cannot proceed + ld a,c + and #7F ; Crop erro code + jr z,.critical + cp 5 ; Microcontroller error on master? + jp nz,.chkslave ; No: slave can still be used safely +.critical: + ld (ix+WRKAREA.SLAVE.t321D),0 ; No master = no slave + jp DRV_INIT_END ; Finish DEV_INIT + +.detinit: + ld a,M_DEV ; Select SLAVE + call SELDEV + call WAIT_RST ; wait until ready + jr nc,.detmaster + ld (ix+WRKAREA.SLAVE.t321D),#80 ; Slave has an error + +.detmaster: + call RESET_ALL.ataonly + push ix + ld de,WRKAREA.MASTER + add ix,de ; Point ix to the MASTER work area + xor a ; Select MASTER + call DETDEV + pop ix + ld a,(ix+WRKAREA.MASTER.t321D) + and 3 ; There can't be a slave without a master + jr z,INIT_MASTERFAIL ; Finish DEV_INIT + +.chkslave: + ld de,SLAVE_S + ld (TEMP_WORK.pDEVMSG),de + call PRINT + + ; Check for DIAGNOSTICS errors + ld a,(ix+WRKAREA.SLAVE.t321D) + bit 7,a ; Any error detected by DIAGNOSE? + jr z,.detslave ; No, skip to detection + + call DIAGERRPRT ; Print the diagnostic error + ld (ix+WRKAREA.SLAVE.t321D),0 ; This device isn't available + jp DRV_INIT_END + +.detslave: + push ix + ld de,WRKAREA.SLAVE.BASE + add ix,de ; Point ix to the SLAVE work area + ld a,M_DEV ; Select SLAVE + call DETDEV + pop ix + + ; Reset all devices to finish +END_DETECT: + call RESET_ALL + + ;--- End of the initialization procedure +DRV_INIT_END: + call IDE_OFF + call INICHKSTOP + ld de,CRLF_S ; Skip a line for the next driver + call PRINT + + ; ***Workaround for a bug in Nextor that causes it to freeze if + ; CTRL+STOP was pressed on boot + ld a,(INTFLG) + cp 3 ; Is CTRL+STOP still signaled? + jr nz,.restCPU ; no, skip + xor a + ld (INTFLG),a ; Clear CTRL+STOP otherwise Nextor will freeze + +.restCPU: ; Restore the CPU if necessary + ld a,(CHGCPU) + cp #C3 ; IS CHGCPU present? + ret nz + pop af + or #80 + jp CHGCPU + + +INIT_ABORTED: + ld de,ABORTED_S ; Print "" + jr INIT_MASTERFAIL.end + +INIT_MASTERFAIL: + ld de,DIAGS_S.nomaster ; Print "failed"> + call PRINT +.end: ld (ix+WRKAREA.MASTER.t321D),0 + ld (ix+WRKAREA.SLAVE.t321D),0 + jr DRV_INIT_END + + + + +;--- Subroutines for the INIT procedure + +; Input: A=target device +; (TEMP_WORK.pDEVMSG): Pointer to the "Master" or "Slave" text +DETDEV: + ld c,a ; c=target device + ld de,DETECT_S ; Print "detecting" + call PRINT + + ld a,(INTFLG) + cp 3 ; Was CTRL+STOP signaled? + jp z,.aborted ; Yes, skip + + ld a,c ; Select device + call SELDEV + call WAIT_BSY ; wait until ready + jp c,.nodev + call DISDEVINT ; Disable interrupts + jp c,.nodev + + ld a,'.' ; Print the FIRST dot + call CHPUT + ;--- Get the device type + call GETDEVTYPE ; Get the device type + ei + ld (ix+DEVINFO.t321D),a + jp c,.nodev + cp #FF + jp z,.unknown + + ;---Configure the PIO transfer mode + IFDEF PIOMODE3 + ld a,3 ; Set transfer mode + ld (IDE_FEAT),a + + ld a,#8+#3 ; PIO flow control, mode 3, so + ; IORDY becomes functional + ld (IDE_SECCNT),a + + ld a,ATACMD.SETFEATURES + ld (IDE_CMD),a + call WAIT_BSY + jr c,.unsupported ; No PIO3? This device is too old + ENDIF + + ;--- Get the name of the device + ;(IDENTIFY device data on TEMP_WORK.BUFFER) +.getinfo: + ld de,(TEMP_WORK.pDEVMSG) + call PRINT + + ;Print the device name. + ld hl,TEMP_WORK.BUFFER+27*2 + ld b,20 + call .prtword + + ; Print the firmware version + ld hl,TEMP_WORK.BUFFER+23*2 + ld b,4 + call .prtword + + ; Print the device characteristics + ld de,DETECT_S.oparenthesis + call PRINT + ld a,(ix+DEVINFO.t321D) + and 3 ; Crop devtype + ld de,DETECT_S.chs + dec a + jr z,.printdevtype + ld de,DETECT_S.lba + dec a + jr z,.printdevtype + ld de,DETECT_S.atapi +.printdevtype: + call PRINT + + ld a,')' + call CHPUT + ld de,CRLF_S + jp PRINT + + + + + + ; --- Print an word string + ; input: HL=string ponter + ; B=Number of words to print +.prtword: + ld c,(hl) + inc hl + ld a,(hl) + inc hl + call CHPUT + ld a,c + call CHPUT + djnz .prtword + ret + + ;--- Unknown device +.unknown: + ld (ix+DEVINFO.t321D),a + ld de,DETECT_S.unknown + call PRINT + ld a,h + call PRINTHEXBYTE + ld a,l + call PRINTHEXBYTE + ld a,'h' + call CHPUT + ld de,CRLF_S + jp PRINT + + ;--- Unsupported device (either too old or too new) +.unsupported: + ld de,DETECT_S.unsupported + jr .nodevreason + + ;--- No device was found +.nodev: + ld de,NODEVS_S + + ;--- Prints the reason why there will be no device reported here +.nodevreason: + ld (ix+DEVINFO.t321D),0 + push de + ld de,(TEMP_WORK.pDEVMSG) + call PRINT ; Clear previous label message + pop de + jp PRINT + + ;--- Dectection aborted by the user +.aborted: + ld de,ABORTED_S + jr .nodevreason + +;----------------------------------------------------------- +WAIT_RST: +; Wait for the BSY flat to be reset for the selected device +; Output: Cy set= timeout +; (INTFLG)=3 if the user pressed CTRL+STOP +; Note: This routine is intended to wait BSY for long periods, as required +; by soft-reset and DIAGNOSTICS. + +; Step-1: Fast reset +; Will catch devices that reset quicly, like CFs and HDDs that are already spinning + + ld de,5*60 ; Wait for up to 5s +.wait1: + ld a,e + and 127 ; Is it the time to print a dot? + ld a,'.' + call z,CHPUT ;Yes, print dots while waiting + call BREAKX + ret c + ld bc,#0505 ;5 fast retries for 5 short pauses +.wait2: + ld a,(INTFLG) + cp 3 ; was CTRL+STOP still signaled? + ret z + ld a,(IDE_STATUS) + and M_BSY + ret z ; This ATA device has finished its reset + djnz .wait2 + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + dec c + jr nz,.wait2 + dec de + ld a,e + or d + halt ;Give the device some time to breath + jr nz,.wait1 + scf + ret + +;Check that a device is present and usable. +;Input: DIAGNOSTICS issued successfully. +;Output: A=devtype. 0=nodev, 1=CHS, 2=LBA, 3=ATAPI +; Cy=0 for device ok, 1 for no device or not usable. +; If device ok, 50 first bytes of IDENTIFY device copied to TEMP_WORK. + +GETDEVTYPE: +; Input: none +; Output: A=devtype. 0=none, 1=CHS, 2=LBA, 3=ATAPI +; Cy on if the device is undetected or unknown +; When Cy=on, HL will contain the signature of the unknown device + +; Notes: + ; Device Signatures are checked according to the ATA/ATAPI Command Set-3 + ; (ACS-3) revision-5 document, page-347. + + ; PATA PATAPI SATA SATAPI + ; COUNT : 01h 01h 01h 01h + ; LBA 23-16: 00h EBh C3h 96h + ; LBA 8-15: 00h 14h 3Ch 69h + ; LBA 0-7: 01h 01h 01h 01h + + ; This signatures are output by the following commands: + ; - DEVICE RESET (08h) + ; - DEVICE DIAGNOSTIC (90h) + ; - IDENTIFY DEVICE (ECh) + ; - READ SECTOR(S) (20h) + + ; Note by Piter: Not all devices respect this. One of my CompactFlash + ; cards never have Sector Count = 01 after reset. + ;ld a,(IDE_SECCNT) + ;cp 1 + ;jr nz,INIT_CHECK_NODEV + + ld hl,(IDE_LBAMID) + ld de,#EB14 ; PATAPI signature? + rst DCOMPR + ld a,3 ; devtype=ATAPI + jr z,.identify + + ld de,#9669 ; SATAPI signature? + rst DCOMPR + ld a,3 ; devtype=ATAPI + jr z,.identify + + ld de,#0000 ; PATA signature? + rst DCOMPR + ld a,1 ; devtype=CHS + jr z,.identify + + ld de,#C33C ; SATA signature? + rst DCOMPR + ld a,2 ; devtype=LBA + jr z,.identify + + ld de,#7F7F ; Unconnected signature? + rst DCOMPR + scf + ret z ; Yes, quit with Cy + + ld de,#FFFF ; Unconnected signature? + rst DCOMPR + scf + ret z ; Yes, quit with Cy + +.unkdev: ; Unknown device + ld a,#FF + or a + ret + +.identify: + ld b,a ; b=devtype + cp 3 ; ATAPI? + ld a,ATACMD.IDENTIFY ;Send IDENTIFY commad + jr c,.identify2 + ld a,ATAPICMD.IDENTPACKET ;Send IDENTIFY PACKET commad +.identify2: + di + call PIO_CMD + ld a,0 ; Return 0 on error + ret c + ld a,b ; a=devtype + ld hl,IDE_DATA + ld de,TEMP_WORK.BUFFER + ld bc,512 ;Read the IDENTIFY packet + ldir + ei + cp 2 ; SATA or ATAPI? + ret nc ; Yes, return + +.chkLBA: + ld a,(TEMP_WORK.BUFFER+49*2+1) + and 2 ; LBA supported? + ld a,1 ; devtype=CHS + ret z ; No, return + inc a ; devtype=LBA + ret + + + + +;----------------------------------------------------------------------------- +; +; Obtain driver version +; +; Input: - +; Output: A = Main version number +; B = Secondary version number +; C = Revision number + +DRV_VERSION: + ld a,VER_MAIN + ld b,VER_SEC + ld c,VER_REV + ret + + +;----------------------------------------------------------------------------- +; +; BASIC expanded statement ("CALL") handler. +; Works the expected way, except that CALBAS in kernel page 0 +; must be called instead of CALBAS in MSX BIOS. + +DRV_BASSTAT: + scf + ret + + +;----------------------------------------------------------------------------- +; +; BASIC expanded device handler. +; Works the expected way, except that CALBAS in kernel page 0 +; must be called instead of CALBAS in MSX BIOS. + +DRV_BASDEV: + scf + ret + + +;----------------------------------------------------------------------------- +; +; Extended BIOS hook. +; Works the expected way, except that it must return +; D'=1 if the old hook must be called, D'=0 otherwise. +; It is entered with D'=1. + +DRV_EXTBIO: + ret + + +;----------------------------------------------------------------------------- +; +; Direct calls entry points. +; Calls to addresses 7450h, 7453h, 7456h, 7459h and 745Ch +; in kernel banks 0 and 3 will be redirected +; to DIRECT0/1/2/3/4 respectively. +; Receives all register data from the caller except IX and AF'. + +DRV_DIRECT0: +DRV_DIRECT1: +DRV_DIRECT2: +DRV_DIRECT3: +DRV_DIRECT4: + ret + + +;===== +;===== BEGIN of DEVICE-BASED specific routines +;===== + +;----------------------------------------------------------------------------- +; +; Read or write logical sectors from/to a logical unit +; +;Input: Cy=0 to read, 1 to write +; A = Device number, 1 to 7 +; B = Number of sectors to read or write +; C = Logical unit number, 1 to 7 +; HL = Source or destination memory address for the transfer +; DE = Address where the 4 byte sector number is stored +;Output: A = Error code (the same codes of MSX-DOS are used): +; 0: Ok +; _IDEVL: Invalid device or LUN +; _NRDY: Not ready +; _DISK: General unknown disk error +; _DATA: CRC error when reading +; _RNF: Sector not found +; _UFORM: Unformatted disk +; _WPROT: Write protected media, or read-only logical unit +; _WRERR: Write error +; _NCOMP: Incompatible disk +; _SEEK: Seek error +; B = Number of sectors actually read/written + +DEV_RW: + push af + call MY_GWORK ; ix=Work area pointer for this device + + push bc + ld b,c ;b=LUN + call CHECK_DEV_LUN + pop bc + jp c,DEV_RW_NODEV + + dec a + jr z,DEV_RW2 + ld a,M_DEV +DEV_RW2: + ld c,a ;c=dev# in IDE format + + ld a,b + or a + jr nz,DEV_RW_NO0SEC + pop af ;Discard the device number that was on stack + xor a + ld b,0 + ret +DEV_RW_NO0SEC: + ld iy,de + ld a,(iy+3) + and 11110000b + jp nz,DEV_RW_NOSEC ;Only 28 bit sector numbers supported + + call IDE_ON + + ld a,(ix+DEVINFO.t321D) + and 3 ; Crop devtype + cp 3 ; ATAPI? + jp z,DEV_ATAPI_RW + +DEV_ATA_RW: + ld a,(iy+3) + or M_LBA + or c ; Mix with dev# in IDE format + call SELDEV ; IDE_HEAD must be written first, + ld a,(iy) ; or the other IDE_LBAxxx and IDE_SECCNT + ld (IDE_LBALOW),a ; registers will not get a correct value + ld e,(iy+1) ; (blueMSX issue?) + ld d,(iy+2) + ld (IDE_LBAMID),de + ld a,b + ld (IDE_SECCNT),a + + pop af ; a=device number in Nextor format + jp c,DEV_ATA_WR + + ;--- + ;--- ATA READ + ;--- +DEV_ATA_RD: + ld a,ATACMD.PRDSECTRT ; PIO read sector with retry + call PIO_CMD + jp c,DEV_RW_ERR + + call CHK_RW_FAULT + ret c + ld iyl,b ; iyl=number of blocks + ex de,hl ; de=destination address + + ld bc,512 ; block size ***Hardcoded. Ignores (BLKLEN) + call READ_DATA + jp c,DEV_RW_ERR + call IDE_OFF + xor a ; A=0: No error. + ret + + ;--- + ;--- ATA WRITE + ;--- +DEV_ATA_WR: + ld a,ATACMD.PWRSECTRT ; PIO write sector with retry + call PIO_CMD + jp c,DEV_RW_ERR + ld iyl,b ; iyl=number of blocks + + ld bc,512 ; block size ***Hardcoded. Ignores (BLKLEN) + call WRITE_DATA + jp c,DEV_RW_ERR + call IDE_OFF + xor a ; A=0: No error. + ret + + +DEV_ATAPI_RW: + ld a,c ;Get devnum in IDE format + call SELDEV + + ; Fill the READ10/WRITE10 packet structure + push de + ld e,(ix+DEVINFO.pBASEWRK) ; hl=pointer to WorkArea + ld d,(ix+DEVINFO.pBASEWRK+1) + ld iy,de ; iy=WRKAREA pointer + pop de + + ; Set the block size + ld a,(ix+DEVINFO.SECTSIZE) + ld (iy+WRKAREA.BLKLEN),a + ld a,(ix+DEVINFO.SECTSIZE+1) + ld (iy+WRKAREA.BLKLEN+1),a + + ld (iy+WRKAREA.PCTBUFF+PCTRW10.LENGHT),0 + ld (iy+WRKAREA.PCTBUFF+PCTRW10.LENGHT+1),b + ld a,(de) + ld (iy+WRKAREA.PCTBUFF+PCTRW10.LBA+3),a + inc de + ld a,(de) + ld (iy+WRKAREA.PCTBUFF+PCTRW10.LBA+2),a + inc de + ld a,(de) + ld (iy+WRKAREA.PCTBUFF+PCTRW10.LBA+1),a + inc de + ld a,(de) + ld (iy+WRKAREA.PCTBUFF+PCTRW10.LBA+0),a + ; Set the fields that we don't need to 0 + xor a + ld (iy+WRKAREA.PCTBUFF+PCTRW10.OPTIONS),a + ld (iy+WRKAREA.PCTBUFF+PCTRW10.GROUP),a + ld (iy+WRKAREA.PCTBUFF+PCTRW10.CONTROL),a + ld (iy+WRKAREA.PCTBUFF+PCTRW12.GROUP),a + ld (iy+WRKAREA.PCTBUFF+PCTRW12.CONTROL),a + + ld de,512 ;Set the buffer size to the 512 bytes + ld (IDE_LBAMID),de + + ; + pop af ; a=device number in Nextor format, f=r/w flag + jp c,DEV_ATAPI_WR + ; + +DEV_ATAPI_RD: + ld a,PACKETCMD.READ12 + ld (iy+WRKAREA.PCTBUFF+PCTRW10.OPCODE),a + ld a,ATAPICMD.PACKET ; PIO send PACKET command + call PIO_CMD + jp c,DEV_RW_ERR + push bc,hl,iy + ld iyl,1 ; 1 block + ld hl,WRKAREA.PCTBUFF + ld bc,PCTRW10 ; block size=10 bytes + call WRITE_DATA ; Send the packet to the device + pop iy,hl,bc + jp c,DEV_RW_ERR + +.init1: ; Set the sector size and number of blocks + ; sizes bigger than 512 must be a multiple of 512 + ld a,(ix+DEVINFO.SECTSIZE+1) + srl a ; SECTSIZE=SECTSIZE/512 (the IDE buffer can + ; transfer only 512 bytes per time) + ld de,512 ; block size=512 + jr nz,.init2 ; Skip if the boundary check is ok + inc a ; Keep the block count to at least 1 + ld e,(ix+DEVINFO.SECTSIZE) + ld d,(ix+DEVINFO.SECTSIZE+1) + +.init2: + ld c,a ; c=number of 512-byte blocks per sector + + push bc + ld bc,de ; bc=block size + call SETLDIRHLPR ; hl'=Pointer to LDIR helper in RAM + pop bc + ex de,hl ; de=destination address +.loopsector: + push bc + ld iyl,c ; get the number of blocks per sector +.loopblock: + call WAIT_DRQ + jr c,.rderr + ld hl,IDE_DATA + call RUN_HLPR + dec iyl + jr nz,.loopblock + pop bc + djnz .loopsector + + call IDE_OFF + xor a + ret + +.rderr: ; Allows the read loop to run faster with a jr + jp DEV_RW_ERR + + +DEV_ATAPI_WR: + ld a,PACKETCMD.WRITE10 + ld (iy+WRKAREA.PCTBUFF+PCTRW10.OPCODE),a + ld a,ATAPICMD.PACKET ; PIO send PACKET command + call PIO_CMD + jp c,DEV_RW_ERR + push bc,hl,iy + ld iyl,1 ; 1 block + ld hl,WRKAREA.PCTBUFF + ld bc,PCTRW10 ; block size=10 bytes + call WRITE_DATA ; Send the packet to the device + pop iy,hl,bc + jp c,DEV_RW_ERR + +.init1: ; Set the sector size and number of blocks + ; sizes bigger than 512 must be a multiple of 512 + ld a,(ix+DEVINFO.SECTSIZE+1) + srl a ; SECTSIZE=SECTSIZE/512 (the IDE buffer can + ; transfer only 512 bytes per time) + ld de,512 ; block size=512 + jr nz,.init2 ; Skip if the boundary check is ok + inc a ; Keep the block count to at least 1 + ld e,(ix+DEVINFO.SECTSIZE) + ld d,(ix+DEVINFO.SECTSIZE+1) + +.init2: + ld c,a ; c=number of 512-byte blocks per sector + + push bc + ld bc,de ; bc=block size + call SETLDIRHLPR ; hl'=Pointer to LDIR helper in RAM + pop bc +.loopsector: + push bc + ld iyl,c ; get the number of blocks per sector +.loopblock: + call WAIT_DRQ + jr c,.rderr + ld de,IDE_DATA + call RUN_HLPR + call CHK_RW_FAULT + jr c,.rderr + dec iyl + jp nz,.loopblock + pop bc + djnz .loopsector + + call IDE_OFF + xor a + ret + +.rderr: ; Allows the read loop to run faster with a jr +; jp DEV_RW_ERR + + + ;--- + ;--- ERROR ON READ/WRITE + ;--- + +DEV_RW_ERR: + ld a,(IDE_ERROR) + ld b,a ; b=IDE_ERROR + call IDE_OFF + bit NM,b ;Not ready + jr nz,DEV_R_ERR1 + ld a,_NRDY + ld b,0 + ret +DEV_R_ERR1: + bit IDNF,b ;Sector not found + jr nz,DEV_R_ERR2 + ld a,_RNF + ld b,0 + ret +DEV_R_ERR2: + bit WP,b ;Write protected + jr nz,DEV_R_ERR3 + ld a,_WPROT + ld b,0 + ret +DEV_R_ERR3: + ld a,_DISK ;Other error + ld b,0 + ret + + ;--- Termination points + +DEV_RW_NOSEC: + call IDE_OFF + pop af + ld a,_RNF + ld b,0 + ret + +DEV_RW_NODEV: + call IDE_OFF + pop af + ld a,_IDEVL + ld b,0 + ret + + +;----------------------------------------------------------------------------- +; +; Device information gathering +; +;Input: A = Device index, 1 to 7 +; B = Information to return: +; 0: Basic information +; 1: Manufacturer name string +; 2: Device name string +; 3: Serial number string +; HL = Pointer to a buffer in RAM +;Output: A = Error code: +; 0: Ok +; 1: Device not available or invalid device index +; 2: Information not available, or invalid information index +; When basic information is requested, +; buffer filled with the following information: +; +;+0 (1): Numer of logical units, from 1 to 8. 1 if the device has no logical +; drives (which is functionally equivalent to having only one). +;+1 (1): Flags, always zero +; +; The strings must be printable ASCII string (ASCII codes 32 to 126), +; left justified and padded with spaces. All the strings are optional, +; if not available, an error must be returned. +; If a string is provided by the device in binary format, it must be reported +; as an hexadecimal, upper-cased string, preceded by the prefix "0x". +; The maximum length for a string is 64 characters; +; if the string is actually longer, the leftmost 64 characters +; should be provided. +; +; In the case of the serial number string, the same rules for the strings +; apply, except that it must be provided right-justified, +; and if it is too long, the rightmost characters must be +; provided, not the leftmost. + +DEV_INFO: + ;Check device index boundaries + or a + jp z,.error1 + cp 3 + jp nc,.error1 + + call MY_GWORK + + ld c,a + ld a,b + or a + jr nz,.strings + + ;--- Obtain basic information + + ld a,(ix+DEVINFO.t321D) ; Get current device type + and 3 ;Device available? + jr z,.error1 + + ld (hl),1 ;One single LUN + inc hl + ld (hl),0 ;Always zero + xor a + ret + + ;--- Obtain string information +.strings: + call IDE_ON + + ld a,c + dec a + jr z,.swcase + ld a,M_DEV + +.swcase: + call SELDEV + + ld a,b + dec a ; A=1? (Manufacturer name) + jr z,.error2 ; Yes, quit. IDE doesn't have it. + + dec a ; A=2? (Device name) + jr z,.devname + + dec a ; A=3? (Serial number) + jr nz,.error2 ; No, quit with error + jr .devserial ; Skip to serial number routine + + ;--- Device name +.devname: +; push hl + call DEV_STRING_CLR + ld bc,#1B14 ; Device name word on IDENTIFY + call DEV_STRING_DIGEST +; pop hl + jr c,.error1 +; ld bc,#1708 +; ld de,21 +; add hl,de +; call DEV_STRING_DIGEST ; Get the device version +; jr c,.error1 + + call IDE_OFF + xor a + ret + + + ;--- Serial number +.devserial: + call DEV_STRING_CLR + ld bc,#0A0A + ld de,44 + add hl,de ;Since the string is 20 chars long + call DEV_STRING_DIGEST + jr c,.error1 + call IDE_OFF + xor a + ret + + + ;--- Termination with error +.error1: + call IDE_OFF + ld a,1 + scf + ret + +.error2: + call IDE_OFF + ld a,2 + ret + + +;--- Clear the destination buffer +; Input : HL = 64 bytes string buffer +; Modifies: AF, BC +DEV_STRING_CLR: + push hl + ld a,' ' + ld b,64 +.loopclr: + ld (hl),a + inc hl + djnz .loopclr + pop hl + ret + + + + + +;Common processing for obtaining a device information string +;Input : B = Offset of the string in the device information (words) +; C = Size of the string to be copied to the buffer (bytes) +; HL = Destination address for the string +;Modifies: AF, BC, DE, HL +DEV_STRING_GET: + push hl + ; Calculate the number of bytes that will remain + ld a,c + srl a ; a=number of words in the string + add b ; a=number of words to be consumed + ld e,a + ld d,0 + ld hl,256 + or a + sbc hl,de + ld h,l ; h=number of remaining words + ex (sp),hl ; (sp)=number of remaining words + + ld a,(ix+DEVINFO.t321D) + and 3 + cp 3 ; ATAPI? + ld a,ATACMD.IDENTIFY ; Send IDENTIFY commad + jr c,.identify + ld a,ATAPICMD.IDENTPACKET ;Send IDENTIFY PACKET commad +.identify: + call PIO_CMD + jr c,.errorpop + + ex de,hl ; de=string buffer +.skip: + ld hl,(IDE_DATA) ;Skip device data until the desired string + djnz .skip + + ; Transfer all bytes to the buffer. String processing must be done + ; later because some devices don't like when the transfer is too slow +; ld b,0 + ld hl,IDE_DATA + ldir + + pop bc ; b=number of remaining words +.flushloop: ; Flush the rest of the data + ld hl,(IDE_DATA) + djnz .flushloop + + or a ; Clear Cy + ret + +.errorpop: + pop de ; Discard stack data + ret + + +; Digest a string from the device and place it on the buffer +; Input : IY=Pointer to the text buffer +; B=Size of the string +; Modifies: AF, BC +DEV_STRING_DIGEST: + push bc,hl + call DEV_STRING_GET + pop iy,bc + ret c + ld b,c + + ; --- Digest an ATA string into a text string +.stringloop: + ld a,(iy+1) + ld c,(iy) + call .validatechar + ld (iy),a + ld a,c + call .validatechar + ld (iy+1),a + inc iy + inc iy + djnz .stringloop + or a ; Clear Cy + ret + +.validatechar: + cp 32 + jr c,.invalidchar + cp 127 + ret c +.invalidchar: + ld a,'_' + ret + + + + +;----------------------------------------------------------------------------- +; +; Obtain device status +; +;Input: A = Device index, 1 to 7 +; B = Logical unit number, 1 to 7. +; 0 to return the status of the device itself. +;Output: A = Status for the specified logical unit, +; or for the whole device if 0 was specified: +; 0: The device or logical unit is not available, or the +; device or logical unit number supplied is invalid. +; 1: The device or logical unit is available and has not +; changed since the last status request. +; 2: The device or logical unit is available and has changed +; since the last status request +; (for devices, the device has been unplugged and a +; different device has been plugged which has been +; assigned the same device index; for logical units, +; the media has been changed). +; 3: The device or logical unit is available, but it is not +; possible to determine whether it has been changed +; or not since the last status request. +; +; Devices not supporting hot-plugging must always return status value 1. +; Non removable logical units may return values 0 and 1. + +DEV_STATUS: + set 0,b ;So that CHECK_DEV_LUN admits B=0 + + call CHECK_DEV_LUN + ld e,a + ld a,0 + ret c + + ld a,1 ;Never changed + ret + + ;ld a,1 + ;ret + + ld a,e + cp 2 + ld a,1 + ret nz + + ld a,e + dec a ;FOR TESTING: + ld a,2 ;Return "Unchanged" for device 1, "Unknown" for device 2 + ret z + ld a,3 + ret + + +;----------------------------------------------------------------------------- +; +; Obtain logical unit information +; +;Input: A = Device index, 1 to 7. +; B = Logical unit number, 1 to 7. +; HL = Pointer to buffer in RAM. +;Output: A = 0: Ok, buffer filled with information. +; 1: Error, device or logical unit not available, +; or device index or logical unit number invalid. +; On success, buffer filled with the following information: +; +;+0 (1): Medium type: +; 0: Block device +; 1: CD or DVD reader or recorder +; 2-254: Unused. Additional codes may be defined in the future. +; 255: Other +;+1 (2): Sector size, 0 if this information does not apply or is +; not available. +;+3 (4): Total number of available sectors. +; 0 if this information does not apply or is not available. +;+7 (1): Flags: +; bit 0: 1 if the medium is removable. +; bit 1: 1 if the medium is read only. A medium that can dinamically +; be write protected or write enabled is not considered +; to be read-only. +; bit 2: 1 if the LUN is a floppy disk drive. +;+8 (2): Number of cylinders (0, if not a hard disk) +;+10 (1): Number of heads (0, if not a hard disk) +;+11 (1): Number of sectors per track (0, if not a hard disk) + +LUN_INFO: + call CHECK_DEV_LUN + jp c,LUN_INFO_ERROR + + call MY_GWORK ; ix=workarea for this device + + ld b,a + call IDE_ON + ld a,b + + push hl + pop iy + dec a + jr z,LUN_INFO2 + ld a,M_DEV +LUN_INFO2: + + ld e,a + call WAIT_DRDY + jp c,LUN_INFO_ERROR + ld a,e + + call SELDEV + + ld a,(ix+DEVINFO.t321D) + and 3 + cp 3 ; ATAPI? + jp z,LUN_NFO_ATAPI ; Yes, skip + + ld a,ATACMD.IDENTIFY ; Send IDENTIFY commad + call PIO_CMD + jp c,LUN_INFO_ERROR + + ;========== Device properties ========== + + ;---Set the device type + ld (iy),0 ;set device type + ld (iy+7),0 ;Not removable, nor floppy + + ld hl,(IDE_DATA) ;Skip word 0 + ;Set cylinders, heads, and sectors/track + ld hl,(IDE_DATA) + ld (iy+8),l ;Word 1: Cylinders + ld (iy+9),h + ld hl,(IDE_DATA) ;Skip word 2 + ld hl,(IDE_DATA) + ld (iy+10),l ;Word 3: Heads + ld hl,(IDE_DATA) + ld hl,(IDE_DATA) ;Skip words 4,5 + ld hl,(IDE_DATA) + ld (iy+11),l ;Word 6: Sectors/track + + ;Set maximum sector number + ld b,60-7 ;Skip until word 60 +.skip1: + ld de,(IDE_DATA) + djnz .skip1 + + ld de,(IDE_DATA) ;DE = Low word + ld hl,(IDE_DATA) ;HL = High word + + ld (iy+3),e + ld (iy+4),d + ld (iy+5),l + ld (iy+6),h + + ;Set sector size + ld b,117-62 ;Skip until word 117 +.skip2: + ld de,(IDE_DATA) + djnz .skip2 + + ld de,(IDE_DATA) ;DE = Low word + ld hl,(IDE_DATA) ;HL = High word + + ld a,h ;If high word not zero, set zero (info not available) + or l + ld hl,0 + ex de,hl + jr nz,.info_ssize + + ex de,hl + ld a,d + or e + jr nz,.info_ssize + ld de,512 ;If low word is zero, assume 512 bytes +.info_ssize: + ld (iy+1),e + ld (iy+2),d + ld (ix+DEVINFO.SECTSIZE),e + ld (ix+DEVINFO.SECTSIZE+1),d + + ;Flush the rest of the data + ld b,256-118 +.skip3: + ld de,(IDE_DATA) + djnz .skip3 + + ; Finish + call IDE_OFF + xor a + ret + +LUN_NFO_ATAPI: + ld a,ATAPICMD.IDENTPACKET ;Send IDENTIFY PACKET commad + call PIO_CMD + jp c,LUN_INFO_ERROR + + ld hl,(IDE_DATA) ;Read word 0 + ; Get the ATAPI device type + xor a + sla l ;Get the removable-device flag + adc a,a ;Inject it in A + ld (iy+7),a + ld a,h + and #1F ;Crop command packet set + ld d,a ;d=0: block device + jr z,.setdevtype ;Direct-access device + dec d ;d=255: other + cp 5 ;CD-ROM? + jr nz,.setdevtype ;Yes, skip + ld d,1 ;d=1: CD-ROM + ld a,2 ;read-only media + or (iy+7) +.setdevtype: + ld (iy+7),a + ld (iy),d ;set device type + + ld b,255 ;Flush the rest of the data +.skip1: + ld hl,(IDE_DATA) + djnz .skip1 + + + ld hl,512 ;Set the buffer size to 512 bytes + ld (IDE_LBAMID),hl + ld l,(ix+DEVINFO.pBASEWRK) ; hl=WorkArea + ld h,(ix+DEVINFO.pBASEWRK+1) + ld de,WRKAREA.PCTBUFF + add hl,de + push hl + ld (hl),PACKETCMD.RDCAPACITY + inc hl + ld b,11 +.zloop: ld (hl),0 ; Clear the rest of the package + inc hl + djnz .zloop + + ld a,ATAPICMD.PACKET ; PIO send PACKET command + call PIO_CMD + jr c,.errorpop + + pop hl + push hl ; Source=PCTBUF + ld bc,12 ; 12 byte packet + push iy + ld iyl,1 + call WRITE_DATA ; Send the packet to the device + pop iy + jr nc,.rdmediapropr ; No error? Then read media proprieties + + ; Guess the sector size based on the device type + pop de ; Discard the destination buffer address + ld a,(iy) ; Get device type + ld de,2048 ; CD-ROM sector size + cp 1 ; CD-ROM? + jr z,.info_ssizeatapi + ld de,512 ; Otherwise assume a 512 byte sector + jr .info_ssizeatapi + +.rdmediapropr: + pop de ; Destination=PCTBUFF + ld bc,8 ; 8 byte response + push iy + ld iyl,1 + call READ_DATA + pop iy + jr c,LUN_INFO_ERROR + + ld h,(ix+WRKAREA.PCTBUFF+0) ; Get the number of sectors + ld l,(ix+WRKAREA.PCTBUFF+1) + ld d,(ix+WRKAREA.PCTBUFF+2) + ld e,(ix+WRKAREA.PCTBUFF+3) + ld (iy+3),e ; Set the number of sectors + ld (iy+4),d + ld (iy+5),l + ld (iy+6),h + + ld h,(ix+WRKAREA.PCTBUFF+4) ; Get the sector size + ld l,(ix+WRKAREA.PCTBUFF+5) + ld d,(ix+WRKAREA.PCTBUFF+6) + ld e,(ix+WRKAREA.PCTBUFF+7) + + ld a,h ;If high word not zero, set zero (info not available) + or l + ld hl,0 + ex de,hl + jr nz,.info_ssizeatapi + + ex de,hl + ld a,d + or e + jr nz,.info_ssizeatapi + ld de,512 ;If low word is zero, assume 512 bytes +.info_ssizeatapi: + ld (iy+1),e ; Set the sector size + ld (iy+2),d + ld (ix+DEVINFO.SECTSIZE),e + ld (ix+DEVINFO.SECTSIZE+1),d + + call IDE_OFF + xor a + ret + +.errorpop: + pop hl + +LUN_INFO_ERROR: + call IDE_OFF + ld a,1 + ret + + +;----------------------------------------------------------------------------- +; +; Physical format a device +; +;Input: A = Device index, 1 to 7 +; B = Logical unit number, 1 to 7 +; C = Format choice, 0 to return choice string +;Output: +; When C=0 at input: +; A = 0: Ok, address of choice string returned +; _IFORM: Invalid device or logical unit number, +; or device not formattable +; HL = Address of format choice string (in bank 0 or 3), +; only if A=0 returned. +; Zero, if only one choice is available. +; +; When C<>0 at input: +; A = 0: Ok, device formatted +; Other: error code, same as DEV_RW plus: +; _IPARM: Invalid format choice +; _IFORM: Invalid device or logical unit number, +; or device not formattable +; B = Media ID if the device is a floppy disk, zero otherwise +; (only if A=0 is returned) +; +; Media IDs are: +; F0h: 3.5" Double Sided, 80 tracks per side, 18 sectors per track (1.44MB) +; F8h: 3.5" Single sided, 80 tracks per side, 9 sectors per track (360K) +; F9h: 3.5" Double sided, 80 tracks per side, 9 sectors per track (720K) +; FAh: 5.25" Single sided, 80 tracks per side, 8 sectors per track (320K) +; FBh: 3.5" Double sided, 80 tracks per side, 8 sectors per track (640K) +; FCh: 5.25" Single sided, 40 tracks per side, 9 sectors per track (180K) +; FDh: 5.25" Double sided, 40 tracks per side, 9 sectors per track (360K) +; FEh: 5.25" Single sided, 40 tracks per side, 8 sectors per track (160K) +; FFh: 5.25" Double sided, 40 tracks per side, 8 sectors per track (320K) + +DEV_FORMAT: + ld a,_IFORM + ret + + +;----------------------------------------------------------------------------- +; +; Execute direct command on a device +; +;Input: A = Device number, 1 to 7 +; B = Logical unit number, 1 to 7 (if applicable) +; HL = Address of input buffer +; DE = Address of output buffer, 0 if not necessary +;Output: Output buffer appropriately filled (if applicable) +; A = Error code: +; 0: Ok +; 1: Invalid device number or logical unit number, +; or device not ready +; 2: Invalid or unknown command +; 3: Insufficient output buffer space +; 4-15: Reserved +; 16-255: Device specific error codes +; +; The first two bytes of the input and output buffers must contain the size +; of the buffer, not incuding the size bytes themselves. +; For example, if 16 bytes are needed for a buffer, then 18 bytes must +; be allocated, and the first two bytes of the buffer must be 16, 0. + +DEV_CMD: + ld a,2 + ret + +;===== +;===== END of DEVICE-BASED specific routines +;===== + + +;======================= +; Subroutines +;======================= + +;----------------------------------------------------------------------------- +; +; Enable or disable the IDE registers + +;Note that bank 7 (the driver code bank) must be kept switched + +IDE_ON: + ld a,1+7*32 + ld (IDE_BANK),a + ret + +IDE_OFF: + ld a,7*32 + ld (IDE_BANK),a + ret + +;----------------------------------------------------------------------------- +; Wait the BSY flag to clear +; Note: This version has a short timeout and is intended for the normal r/w +; operations. It's not adequate to be used for slower commands like soft-reset +; or DIAGNOSTICS. +; +; Input: Nothing +; Output: Cy=1 if timeout +; A = Contents of the status register + +WAIT_BSY: + out (#E6),a ; Reset System-timer + in a,(#E7) + or a ; Is the timer present? + jr z,.hasTimer + + push bc + ld bc,#0090 ; 256 fast retries, 48 slow retries +.wait1: + ld a,(IDE_STATUS) + and M_BSY ; Still busy? + jr z,.end ; No, skip + ex (sp),hl + ex (sp),hl + djnz .wait1 ; fast retry + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + dec c + jr nz,.wait1 ; slow retry + scf ; Timeout: quit with Cy=on +.end: pop bc + ret + +.hasTimer: + push bc + ld b,1*4 ; 1s +.twait1: + ld a,(IDE_STATUS) + and M_BSY + jr z,.tend ; Yes, quit + in a,(#E7) + cp 250 ; 250ms + jr c,.twait1 + out (#E6),a ; Reset the timer again + djnz .twait1 + scf ; Timeout: quit with Cy=on +.tend: + ld a,(IDE_STATUS) ; Clear the INTRQ + pop bc + ret + + + + + +;----------------------------------------------------------------------------- +; Wait the BSY flag to clear and RDY flag to be set +; if we wait for more than 30s, send a soft reset to IDE BUS +; if the soft reset didn't work after 30s return with error +; +; Input: Nothing +; Output: Cy=1 if timeout after soft reset +; A = Contents of the status register + +WAIT_DRDY: + out (#E6),a ; Reset System-timer + in a,(#E7) + or a ; Is the timer present? + jr z,.hasTimer + + push bc + ld bc,#0000 ; 256 fast retries, 256 slow retries +.wait1: ld a,(IDE_STATUS) + and M_BSY+M_DRDY + cp M_DRDY ; BSY=0 and DRDY=1? + jr z,.end ; Yes, quit + ex (sp),hl + ex (sp),hl + djnz .wait1 ; fast retry + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + dec c + jr nz,.wait1 ; slow retry + scf +.end: pop bc + ld a,(IDE_STATUS) ; Clear the INTRQ + ret + +.hasTimer: + push bc + ld b,10*4 ; 10s +.twait1: + ld a,(IDE_STATUS) + and M_BSY+M_DRDY + cp M_DRDY ; BSY=0 and DRDY=1? + jr z,.tend ; Yes, quit + in a,(#E7) + cp 250 ; 250ms + jr c,.twait1 + out (#E6),a ; Reset the timer again + djnz .twait1 + scf ; Timeout: quit with Cy=on +.tend: ld a,(IDE_STATUS) + pop bc + ret + +;----------------------------------------------------------------------------- +;--- Check for device fault or error +; Output: Cy=on and A=_DISK on fault + +CHK_RW_FAULT: + call WAIT_BSY ; wait until the flags are valid +; jr c,.error ; quit on timeout + ret c ; quit on timeout + + ld a,(IDE_STATUS) + and M_DF+M_ERR ; Device fault or error? + ret z ; No, quit wit Cy off +;.error: +; call IDE_OFF +; ld a,_DISK +; ld b,0 + scf + ret + +;----------------------------------------------------------------------------- +; Check for ERROR +; +CHK_ERR: + call WAIT_BSY ; wait until the flags are valid + ret c + bit ERR,a ; error? + ret z ; No, quit + scf + ret + + +;----------------------------------------------------------------------------- +; Execute a PIO command +; +; Input: A = Command code +; Other command registers appropriately set +; Output: Cy=1 if ERR bit in status register set +; A = Contents of the status register + +PIO_CMD: + push bc + ld c,a + call WAIT_BSY ; wait until the flags are valid + ld a,c + pop bc + ret c + ld (IDE_CMD),a + ; Must wait 400ns + nop ; 1400ns@3.57MHz + +;----------------------------------------------------------------------------- +; +WAIT_DRQ: + call WAIT_BSY ; wait until the flags are valid + ret c ; quit on timeout + + out (#E6),a ; Reset System-timer + in a,(#E7) + or a ; Is the timer present? + jr z,.hasTimer + + push bc + ld bc,#0090 ; 256 fast retries, 144 slow retries +.wait1: ld a,(IDE_STATUS) + rrca ; ERR=1? + jr c,.end2 ; Yes, abort with error + and (M_DRQ>>1) ; DRQ=1? + jr nz,.end ; Yes, quit + ex (sp),hl + ex (sp),hl + djnz .wait1 ; fast retry + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + ex (sp),hl + dec c + jr nz,.wait1 ; slow retry + scf ; Cy = timeout +.end: +; ex (sp),hl ; Blind wait for the INTRQ, since +; ex (sp),hl ; this IDE interface doesn't allow +; ex (sp),hl ; us to know when the interrupt would +; ex (sp),hl ; be triggered. +.end2: pop bc + ld a,(IDE_STATUS) + ret + +.hasTimer: + push bc + ld b,5*4 ; 5s +.twait1: + ld a,(IDE_STATUS) + rrca ; error? + jr c,.tend2 ; Yes, abort with Cy=on + and (M_DRQ>>1) ; DRQ=1? + jr nz,.tend ; Yes, quit + in a,(#E7) + cp 250 ; 250ms + jr c,.twait1 + out (#E6),a ; Reset the timer again + djnz .twait1 + scf ; Timeout: quit with Cy=on + jr .tend2 +.tend: + out (#E6),a ; Reset the timer +.tblindwait: ; Blind wait for the INTRQ, since + in a,(#E6) ; this IDE interface doesn't allow + ; us to know when the interrupt would + ; be triggered. Duh! + cp 3 ; 3*4us + jr c,.tblindwait +.tend2: pop bc + ld a,(IDE_STATUS) ; Clear the INTRQ + ret + + + + + +;----------------------------------------------------------------------------- +; Select a device +; +; This operation seems to require a delay, otherwise the devices may behave +; erratically +SELDEV: + ex af,af' + call WAIT_BSY + ret c + ex af,af' + ld (IDE_HEAD),a + ; Detect the system timer + out (#E6),a + in a,(#E7) + or a + jr z,.twait1 + ex (sp),hl + ex (sp),hl + ret +.twait1: + in a,(#E6) + cp 3 ; 3*4us + jr c,.twait1 + ret + +;----------------------------------------------------------------------------- +; Disable the interrupts for the current device +; +; This operation seems to require a delay, otherwise the devices may behave +; erratically +DISDEVINT: + ld a,M_nIEN ; Disable interrupts + ld (IDE_DEVCTRL),a + ; Detect the system timer + out (#E6),a + in a,(#E7) + or a + jr z,.twait1 + ex (sp),hl + ex (sp),hl + ret +.twait1: + in a,(#E6) + cp 3 ; 3*4us + jr c,.twait1 + ret + + ld a,(IDE_STATUS) + rrca ; ERR=1? + ccf + ret nc ; Yes, quit + jp WAIT_BSY + + +;----------------------------------------------------------------------------- +; +; Do a soft reset on the IDE devices +; +; Input : none +; Output : Cy if timed out +; (INTFLG)=3 if the user pressed CTRL+STOP + +RESET_ALL: + ld a,M_DEV ; Select SLAVE + call SELDEV + call WAIT_BSY + xor a ; Select MASTER + call SELDEV + call WAIT_BSY + + call .atapirst + +.ataonly: + xor a ; Select MASTER + call SELDEV + call WAIT_BSY + + out (#E6),a + in a,(#E7) + or a ; Is the system-timer present? + jr z,.hasSystimer ; Yes, use it + +.noSystimer: + ld a,M_SRST+M_nIEN ; Do a software reset + ld (IDE_DEVCTRL),a + halt + halt ; 16.6ms (spec: 5us) + ld a,M_nIEN ; stop reset + ld (IDE_DEVCTRL),a + halt ; 16.6ms (spec: 2ms) + call WAIT_RST ; Wait for the resets to finish + ret c + halt + halt + ret + +.hasSystimer: +.twait1: + in a,(#E6) + cp 2 ; 2*4us (spec: > 5us) + jr c,.twait1 + + ld a,M_nIEN ; stop reset + ld (IDE_DEVCTRL),a + out (#E6),a +.twait2: + in a,(#E7) + cp 3 ; 3ms (spec: > 2ms) + jr c,.twait2 + call WAIT_RST ; Wait for the resets to finish + ret c + halt + halt + ret + +.atapirst: + ; Reset a slave ATAPI + ld a,M_DEV ; Select SLAVE + call SELDEV + ld a,ATAPICMD.RESET + ld (IDE_CMD),a + ; Reset a master ATAPI + xor a ; Select MASTER + call SELDEV + ld a,ATAPICMD.RESET + ld (IDE_CMD),a + ret + + +;----------------------------------------------------------------------------- +; Checks for a diagnostic error and set a warning flag accordingly +; Input : none +; Output: WRKAREA.MASTER.t321D and WRKAREA.SLAVE.t321D: +; 0=no error +; bit7=1: error. b6~b0: reported error code +; Modifies: B + + +CHKDIAG: + ld a,(ix+WRKAREA.MASTER.t321D) + inc a ; Undetected master? + scf + ret z ; Yes, quit with error + ld a,(IDE_ERROR) + ld b,a ; b=DIAG status + and #7F ; Crop the master error code + cp 1 ; Any error? + jr z,.chkslave ; No, skip +.saveerrms: ; Save the error code from the master + or #80 + ld (ix+WRKAREA.MASTER.t321D),a + bit 7,b ; Error on slave? + scf + ret z ; No, quit +.chkslave: + bit 7,b ; Error on slave? + ret z ; No, quit + ld a,M_DEV ; Select the slave + call SELDEV + ld a,(IDE_ERROR) + and #7F ; Crop the slave error code + cp 1 ; Any error? + ret z ; No, quit +.saveerrsl: ; Save the error code from the slave + or #80 + ld (ix+WRKAREA.SLAVE.t321D),a + ld a,b + cp 1 ; Any error reported? + ret z ; No, quit with Cy=off + scf ; Cy=on if there was any error + ret + +;----------------------------------------------------------------------------- +; Prints an explanation message for a diagnostic error +; Input: A=Diagnostic error + +DIAGERRPRT: + cp #FE ; Undetected master? + ld de,DIAGS_S.nomaster + jr z,.print ; Yes, print + and #7F ; Crop the error code + jr z,.print ; 0=Undetected master: print + ld b,a + dec b ; adjust for the switch case + djnz .buff + ld de,DIAGS_S.formatter ; ERR=2 + jr .print +.buff: djnz .ecc + ld de,DIAGS_S.buffer ; ERR=3 + jr .print +.ecc: djnz .mcu + ld de,DIAGS_S.ECC ; ERR=4 + jr .print +.mcu: djnz .unkn + ld de,DIAGS_S.microcontroller ; ERR=5 +.print: jp PRINT +.unkn: ld de,DIAGS_S.unknown + push af + call PRINT + pop af + call PRINTHEXBYTE + ld a,'>' + call CHPUT + ld de,CRLF_S + jr .print + +;----------------------------------------------------------------------------- +; Subroutine to read blocks of arbitrary size on the IDE +; Input: DE =Data destination +; BC =block size +; IYL=Number of blocks +READ_DATA: + call SETLDIRHLPR ; hl'=Pointer to data transfer helper +.loop: + call WAIT_DRQ + ret c + ld hl,IDE_DATA + call RUN_HLPR + dec iyl + jp nz,.loop + ret + + +;----------------------------------------------------------------------------- +; Subroutine to write blocks of arbitrary size on the IDE +; Input: HL =Data source +; BC =block size +; IYL=Number of blocks +WRITE_DATA: + call SETLDIRHLPR ; hl'=Pointer to LDIR helper in RAM +.loop: + call WAIT_DRQ + ret c + ld de,IDE_DATA + call RUN_HLPR + call CHK_RW_FAULT + ret c + dec iyl + jp nz,.loop + ret + +LDI512: ; Z80 optimized 512 byte transfer + exx + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ldi + ret + + + +;----------------------------------------------------------------------------- +; +; Print a zero-terminated string on screen +; Input: DE = String address + +PRINT: + ld a,(de) + or a + ret z + call CHPUT + inc de + jr PRINT + + +;----------------------------------------------------------------------------- +; +; Obtain the work area address for the driver or the device +; Input: A=Selects where to point inside the work area +; 0: base work area +; 1: work area for the master +; 2: work area for the slave +; Output: IX=Pointer to the selected work area +; Modifies: disables the IDE registers + +MY_GWORK: + push af + xor a + EX AF,AF' + XOR A + LD IX,GWORK + call CALBNK + pop af + push de + ld e,(ix) ; de=Pointer to the WorkAREA in RAM + ld d,(ix+1) + ld ix,0 + or a + jr z,.end + cp 1 + ld ix,WRKAREA.MASTER.BASE + jr z,.end + ld ix,WRKAREA.SLAVE.BASE +.end: add ix,de ; Point ix to the device work area + pop de + ret + +;----------------------------------------------------------------------------- +; +; Check the device index and LUN +; Input: A = device index, B = lun +; Output: Cy=0 if OK, 1 if device or LUN invalid +; IX = Work area for the device +; Modifies F, C + +CHECK_DEV_LUN: + or a ;Check device index + scf + ret z ;Return with error if devindex=0 + cp 3 + ccf + ret c ;Return with error if devindex>2 + + ld c,a ; c=device index + + + + ld a,b ; Check LUN number + cp 1 + ld a,c + scf + ret nz + + push hl + push de + call MY_GWORK + pop de + pop hl + ld c,a + ld a,(ix+DEVINFO.t321D) + and 3 + jr z,.nodev + cp 1 ; TODO: Implement CHS support + jr z,.nodev ; For now, CHS devices are unsupported + ld a,c + or a + ret + +.nodev: + ld a,c + scf + ret + + + +; ------------------------------------------------ +; Jumps to a helper routine, usually in RAM +; Input: HL': Address of the target routine +; ------------------------------------------------ +RUN_HLPR: + exx + jp (hl) + +; ------------------------------------------------ +; Setup the arbitrary block size LDIR helper to be used +; Input : BC : block size (must be >2 bytes) +; Output : HL': Address of the LDIR helper in RAM +; Modifies: AF, DE', HL' +; ------------------------------------------------ +SETLDIRHLPR: + ld a,b + or c ; Shortcut comparison. Takes advantage that + ; only 512 and 2 will have this OR bitmask + ; to save time + cp HIGH 512 ; bc=512? + exx + jr nz,.useLDIR ; No, must use LDIR then + + ; Check for a Z80 or R800 + xor a ; Clear Cy + dec a ; A=#FF + db #ED,#F9 ; mulub a,a + jr c,.useLDIR ; Always use LDIR in RAM for the R800 + + ld hl,LDI512 + exx + ret + +.useLDIR: + exx + push bc + exx + pop de ; de=block size + ld l,(ix+DEVINFO.pBASEWRK) + ld h,(ix+DEVINFO.pBASEWRK+1) + ; Set the the block size + ; *** BLKLEN must be the first data in the workArea + ld (hl),e + inc hl + ld (hl),d + ; Point to the data transfer routine + ld de,WRKAREA.LDIRHLPR-1 + add hl,de + exx ; hl'=Pointer to LDIR helper routine + ret + + + +; ------------------------------------------------ +; Initialize the Work-area +; ------------------------------------------------ +INIWORK: + ; Clear the WorkArea + push ix + pop hl + push hl + ld b,WRKAREA + xor a +.clrwork2: + ld (hl),a + inc hl + djnz .clrwork2 + + pop hl + ; Set the pointers to go back to the base of the WorkArea + ld (ix+WRKAREA.MASTER.pBASEWRK),l + ld (ix+WRKAREA.MASTER.pBASEWRK+1),h + ld (ix+WRKAREA.SLAVE.pBASEWRK),l + ld (ix+WRKAREA.SLAVE.pBASEWRK+1),h + + ; Install the data transfer helper routine in the WorkArea + ; This speeds up the LDIR speed a lot for the R800 + ld de,WRKAREA.LDIRHLPR + add hl,de + ex de,hl + ld hl,R800DATHLP + ld bc,R800DATHLP.end-R800DATHLP + ldir + + ; Point the LD BC (addr) from LDIRHLPR to BLKLEN + push ix + pop hl + ld de,WRKAREA.BLKLEN + add hl,de ; hl=pointer to BLKLEN + ld (ix+WRKAREA.LDIRHLPR+3),l + ld (ix+WRKAREA.LDIRHLPR+4),h + ret + +; ------------------------------------------------ +; R800 data transfer routine, copied to the WorkArea +; ------------------------------------------------ +R800DATHLP: + exx + ld bc,(0) ; The address will be set by INIWORK + ldir + ret +.end: + +;----------------------------------------------------------------------------- +; +; Restore screen parameters on MSX>=2 if they're not set yet +; Input : none +; Output : none +; Modifies: all +MYSETSCR: + ld a,(MSXVER) + or a ; MSX1? + jr nz,.notMSX1 ; No, skip +.MSX1: + ld a,(SCRMOD) + or a ; SCREEN0 already? + ret z ; Yes, quit + jp INITXT ; set screen0 + +.notMSX1: + ld c,$23 ; Block-2, R#3 + ld ix,REDCLK + call EXTROM + and 1 + ld b,a + ld a,(SCRMOD) + cp b + jr nz,.restore + inc c + ld ix,REDCLK + call EXTROM + ld b,a + inc c + ld ix,REDCLK + call EXTROM + add a,a + add a,a + add a,a + add a,a + or b + ld b,a + ld a,(LINLEN) + cp b + ret z +.restore: + xor a ; Don't displat the function keys + ld ix,SDFSCR + jp EXTROM + +;----------------------------------------------------------------------------- +; Prints a byte in hex +; Input : A=byte to be printed +; Modifies: C +PRINTHEXBYTE: + ld c,a + rrca + rrca + rrca + rrca + and #F + call printnibble + ld a,c + and #F + call printnibble + ret + +printnibble: + cp 10 ; <=9? + jr c,.print09 ; Yes, skip +; ld a,9 ; Limit to 1 digit + cp 15 + jr c,.printAF + ld a,#F ; Limit to 15 +.printAF: + add "A"-10 + jp CHPUT +.print09: + add "0" + jp CHPUT + +;----------------------------------------------------------------------------- +; +; Check if the STOP key was signaled on DRV_INIT +; Input : none +; Output : none +; Modifies: all + +INICHKSTOP: + ld a,(INTFLG) + cp 4 ; Was STOP pressed? + ret nz ; No, quit as fast as possible + + ; Handle STOP to pause and read messages, and ask for the copyright info + ld de,BOOTPAUSE_S + call PRINT +.wait1: ld a,7 + call SNSMAT + and $10 ; Is STOP still pressed? + jr z,.wait1 ; Wait for STOP to be released + xor a + ld (INTFLG),a ; Clear STOP flag + ld b,0 ; b=inhibit 'i' key flag +.wait2: call CHSNS + call nz,.chkikey ; Wait until a key is pressed + ld a,(INTFLG) + cp 4 ; Was STOP pressed? + jr nz,.wait2 ; No, return + xor a + ld (INTFLG),a ; Clear STOP flag + call KILBUF + ld b,30 ; Since the user is trying pause the +.wait3: halt ; boot messages, this gives him enough + ; time to react and pause the next + ; driver + ld a,(INTFLG) + cp 4 ; Was STOP pressed? + ret z ; quit so the next driver can process it + djnz .wait3 ; The user will have the impression + ; that he has a perfect timing. ;) + ret + +.chkikey: + bit 0,b ; Was the copyright message shown? + ret nz ; Yes, return + call CHGET + cp 'i' + jr z,.showcopyright + cp 'I' + ret nz +.showcopyright: + inc b ; Inhibit further presses of the i key + ld de,COPYRIGHT_S + jp PRINT + + + + + +;======================= +; Strings +;======================= + +INFO_S: + db 13,"Sunrise compatible IDE driver v",27,'J' + db VER_MAIN+$30,'.',VER_SEC+$30,'.',VER_REV+$30 +CRLF_S: db 13,10,0 +COPYRIGHT_S: + db "(c) 2009 Konamiman",13,10 + db "(c) 2014 Piter Punk",13,10 + db "(c) 2017 FRS",13,10,13,10,0 + +BOOTPAUSE_S: + db "Paused. Press to show the copyright info.",13,10,0 + +SEARCH_S: + db "Searching: ",0 + +NODEVS_S: + db "not found",13,10,0 +ABORTED_S: + db "",13,10,0 +INIT_S: + db 13,"Initializing : ",27,'J',0 +MASTER_S: + db 13,"Master device: ",27,'J',0 +SLAVE_S: + db 13,"Slave device : ",27,'J',0 + +OK_S: db "Ok",13,10,0 +ERROR_S: + db "Error!",13,10,0 + +DETECT_S: + db "detecting",0 +.unknown: db "Unknown device ",0 +.unsupported: db "Unsuppored device",0 +.oparenthesis: db " (",0 +.chs: db "CHS",0 +.lba: db "LBA",0 +.atapi: db "ATP",0 + + +DIAGS_S: +.nomaster: db "",7,13,10,0 +.formatter: db "",7,13,10,0 +.buffer: db "",7,13,10,0 +.ECC: db "",7,13,10,0 +.microcontroller: db "",7,13,10,0 +.unknown: db " + PRINTL ,%($-START)-(ADDR-ORIGIN) + org ADDR-ORIGIN + else + PRINTL ,%(ADDR-ORIGIN)-($-START) + defs (ADDR-ORIGIN)-($-START),0 + endif +endm + +ORIGIN equ 7700h + + ALIGN 7700h ; ; External Routines. ; @@ -27,10 +48,219 @@ $$DRIVE:: public DEFDPB ; - ;*** This should be compiled at 781Fh -SNSMAT equ 0141h +;----------------------------------------------------------------------------- + +;This routine is invoked in disk emulation mode prior to any disk access. +;If checks if a valid file change key is being pressed, and if so, +;reloads the emulation data file and updates the information in DVB_TABLE. +;If no suitable key is being pressed, or if change is performed ok, returns Z. +;If there is an error reading the emulation data file, returns NZ and A=Error code. + +CHGFILE: + push hl + push de + push bc + push ix + push iy + call CHGF2 + pop iy + pop ix + pop bc + pop de + pop hl + ret + +CHGF2: + ld ix,(DVB_TABLE##) + + call GETCURKEY + or a + ret z + cp 0FFh + jr nz,CHGF3 + + call CAPSON + call WAIT_KEY_RELEASE ;GRAPH pressed: wait for other keys to release... + +CHGWA2: + call GETCURKEY ;...then to be pressed again. + or a + jr z,CHGWA2 + + cp 0FFh ;User changed his mind and pressed GRAPH + jr nz,CHGF3 + + call WAIT_KEY_RELEASE + ret + +CHGF3: + ld c,a + call CAPSON + + ;--- The key with index C is pressed + + ;> Do nothing if chosen file is the same currently in use + + ld a,(ix+DSK_IDX##) + and 3Fh + cp c + call z,CAPSOFF + ret z + + ;> Read emulation data file + push bc + + ld a,(ix+EMU_DEVLUN##) ;data file dev index + 16 * LUN index + ld d,a + rrca + rrca + rrca + rrca + and 111b + ld b,a ;LUN + ld a,d + and 111b ;Device + + ld l,(ix+EMU_FSEC##) + ld h,(ix+EMU_FSEC##+1) + ld (TMP_SEC##),hl + ld l,(ix+EMU_FSEC##+2) + ld h,(ix+EMU_FSEC##+3) + ld (TMP_SEC##+2),hl + + ld iy,(0F348h-1) ;Master controller slot + ld hl,DEV_RW## + ld (BK4_ADD##),hl + ld c,b + ld b,1 + ld hl,($SECBUF##) + ld de,TMP_SEC## + or a + + push ix + ld ix,CALDRV## + call CALSLT## ;Call DEV_RW + pop ix + pop bc + call CAPSOFF + or a + ret nz + + ;> Set the new file data in work area + + ld a,(ix+DSK_IDX##) + and 11000000b ;In emulation mode flag + Russian keyboard flag + ld b,a + ld a,c + or b + ld (ix+DSK_IDX##),a + set 7,(ix+EMU_DEVLUN##) ;File changed flag + + dec a + add a,a ;Each entry is 8 bytes + add a,a + add a,a + ld l,a + ld h,0 + ld bc,24 + add hl,bc + ld de,($SECBUF##) + add hl,de ;HL = Pointer to boot file data + push ix + pop de + inc de + inc de ;DE must point to DSK_DEV in work area + ld bc,8 + ldir + + ld a,(ix+DSK_DEV##) ;set DSK_DEV and DSK_LUN as same of data file if 0 + or a + jr nz,CHGF4 + ld a,(ix+EMU_DEVLUN##) + ld b,a + and 00000111b + ld (ix+DSK_DEV##),a + ld a,b + rrca + rrca + rrca + rrca + and 00000111b + ld (ix+DSK_LUN##),a + +CHGF4: + xor a + ret + + +WAIT_KEY_RELEASE: + call GETCURKEY + or a + jr nz,WAIT_KEY_RELEASE + ret + + + ;Return in A the index of currently pressed key, 0 if none, FFh is GRAPH + ;Input: IX = Pointer to emulation data area +GETCURKEY: + ex af,af' + ld a,(ix+DSK_IDX##) + rlca + rlca + rlca + and 1 ;Russian keyboard? + ex af,af' + push ix + ld ix,SCANKEYS + xor a + call CALBNK## + pop ix + bit 6,h + ld a,0FFh + ret nz + ld c,b + ld b,(ix+DSK_COUNT##) + ld a,1 + + ;HLDEC = key statuses + ;B = Keys left to check + ;A = Current key index + ;We do an initial rotation because we want to start at key 1. +CHGLOOP: + sra c + rr e + rr d + rr l + rr h + bit 0,c + ret nz + + inc a + djnz CHGLOOP + + xor a + ret + +CAPSON: + in a,(0AAh) + and 10111111b + out (0AAh),a + ret + +CAPSOFF: + push af + in a,(0AAh) + or 01000000b + out (0AAh),a + pop af + ret + + + + + ALIGN 781Fh ;----------------------------------------------------------------------------- ; ; Null message. The address of this message can be returned by @@ -52,9 +282,9 @@ null_message: ; Calls to these addresses will be translated to calls to the DV_DIRECTx ; entry points in the driver bank. - ds 7850h-7843h ;Can't do "ds 7850h-$", the compiler complaints + ALIGN 7850h -DIRCALL:: +DIRCALL: call DO_DIRCALL call DO_DIRCALL call DO_DIRCALL @@ -82,22 +312,31 @@ DIO_ENTRY:: call IS_DVB jp nc,DIO_ENTRY_DO - ld a,(iy+2) + ld a,(iy+UD1_DI##) or a jp z,DISKERR call IS_EMU - jr nc,DIOEN_NOEMU + jp c,DIOEN_ISEMU + + ;>>> NOT in disk emulation mode + +DIOEN_NOEMU: + call HAS_PARTITION + call nz,ASSIGN_PARTITION + jp nz,POP_CONV_ERR + jr DIOEN3 ;>>> In disk emulation mode +DIOEN_ISEMU: pop af push af or a jp nz,DISKERR ;Drive number must be 0 - call CHGFILE + call CHGFILE jr z,DIOCHGFOK pop bc ld b,0 @@ -109,8 +348,8 @@ DIOCHGFOK: push hl push de ld ix,(DVB_TABLE##) - ld e,(ix+9) - ld d,(ix+10) ;DE = dsk size in sectors + ld e,(ix+DSK_SIZE##) + ld d,(ix+DSK_SIZE##+1) ;DE = dsk size in sectors pop hl push hl @@ -150,29 +389,36 @@ WVDP: call CAPSOFF ret - ;>>> NOT in disk emulation mode - -DIOEN_NOEMU: - call HAS_PARTITION - call nz,ASSIGN_PARTITION - jp nz,POP_CONV_ERR - jr DIOEN3 - DIOEN2: push af + ld iy,(DVB_TABLE) DIOEN3: + + ; In this point one of these is true: + ; + ; - We are in disk emulation mode, and IY points to the beginning + ; of the work area for emulation mode. + ; + ; - We are in normal DOS 1 mode, and IY points to the entry + ; for the drive in DVB_TABLE. + ; + ; The following code is common to both cases, that's why + ; device index, LUN index and first sector number must be stored + ; at the same offset in both the DVB_TABLE entries (UD1_*) + ; and the disk emulation work area (DSK_*). + ld a,1 ld (KSLOT##),a ;KSLOT=1 -> device-based push hl - ld l,(iy+4) - ld h,(iy+5) + ld l,(iy+UD1_FSEC##) + ld h,(iy+UD1_FSEC##+1) add hl,de ld ix,TMP_SEC## ld (ix),l ;Calculate absolute sector number ld (ix+1),h - ld l,(iy+6) - ld h,(iy+7) + ld l,(iy+UD1_FSEC##+2) + ld h,(iy+UD1_FSEC##+3) ld de,0 adc hl,de ld (ix+2),l @@ -180,9 +426,9 @@ DIOEN3: pop hl ;Restore transfer address ld de,TMP_SEC## - ld c,(iy+3) ;Set LUN index - pop af ;From here Cy must be kept untouched - ld a,(iy+2) ;Set device index + ld c,(iy+UD1_LI##) ;Set LUN index + pop af ;From here Cy must be kept untouched + ld a,(iy+UD1_DI##) ;Set device index jr DIO_ENTRY_DO_2 @@ -365,233 +611,6 @@ DIO_INC_DE_DVB_END: pop hl ret -;----------------------------------------------------------------------------- - -;This routine is invoked in disk emulation mode prior to any disk access. -;If checks if a valid file change key is being pressed, and if so, -;reloads the NEXT_DSK.DAT file and updates the information in DVB_TABLE. -;If no suitable key is being pressed, or if change is performed ok, returns Z. -;If there is an error reading NEXT_DSK.DAT, returns NZ and A=Error code. - -CHGFILE: - push hl - push de - push bc - push ix - push iy - call CHGF2 - pop iy - pop ix - pop bc - pop de - pop hl - ret - -CHGF2: - ld ix,(DVB_TABLE##) - - ld a,6 ;Check GRAPH key - call SNSKEY - and 100b - jr nz,NOGRAPH - -CHGWAIT: - call CAPSON - call GETCURKEY ;GRAPH pressed: wait for other keys to release... - or a - jr nz,CHGWAIT - -CHGWA2: - call GETCURKEY ;...then to be pressed again. - or a - jr z,CHGWA2 - - jr CHGF3 - -NOGRAPH: - call GETCURKEY - or a - ret z - -CHGF3: - ld c,a - call CAPSON - - ;--- The key with index C is pressed - - ;> Do nothing if chosen file is the same currently in use - - ld a,(ix) - and 7Fh - cp c - call z,CAPSOFF - ret z - - ;> Read .DAT file - - push bc - - ld a,(ix+2) ;.DAT file dev index + 16 * LUN index - ld d,a - rrca - rrca - rrca - rrca - and 111b - ld b,a ;LUN - ld a,d - and 111b ;Device - - ld l,(ix+12) - ld h,(ix+13) - ld (TMP_SEC##),hl - ld l,(ix+14) - ld h,(ix+15) - ld (TMP_SEC##+2),hl - - ld iy,(0F348h-1) ;Master controller slot - ld hl,DEV_RW## - ld (BK4_ADD##),hl - ld c,b - ld b,1 - ld hl,($SECBUF##) - ld de,TMP_SEC## - or a - - push ix - ld ix,CALDRV## - call CALSLT## ;Call DEV_RW - pop ix - pop bc - call CAPSOFF - or a - ret nz - - ;> Set the new file data in work area - - ld a,c - ld (ix),a - set 7,(ix) - set 7,(ix+2) ;File changed flag - - dec a - add a,a ;Each entry is 8 bytes - add a,a - add a,a - ld l,a - ld h,0 - ld bc,24 - add hl,bc - ld de,($SECBUF##) - add hl,de ;HL = Pointer to boot file data - push ix - pop de - inc de - inc de - inc de - ld bc,8 - ldir - - xor a - ret - - - ;Return in A the index of currently pressed key, 0 if none - ;Input: IX = Pointer to entry in DVB_TABLE - -GETCURKEY: - ld b,(ix+11) - ld hl,CHGTBL - ld d,-1 - ld c,1 - - ;B=Number of keys left to test - ;HL=Pointer to current key in table - ;D=Last keyboard row checked - ;E=Last keyboard row value obtained - ;C=Current key number -CHGLOOP: - ld a,(hl) - inc hl - cp d - jr z,IHAVEROW - ld d,a - call SNSKEY - ld e,a -IHAVEROW: - ld a,(hl) - inc hl - and e - ld a,c - ret z - inc c - djnz CHGLOOP - - xor a ;No suitable key pressed - ret - -SNSKEY:: - push bc - ld c,a - di - in a,(0AAh) - and 0F0h - add a,c - out (0AAh),a - ei - in a,(0A9h) - pop bc - ret - -CHGTBL: - db 0,2 ;1 - db 0,4 ;2 - db 0,8 ;3 - db 0,16 ;4 - db 0,32 ;5 - db 0,64 ;6 - db 0,128 ;7 - db 1,1 ;8 - db 1,2 ;9 - db 2,64 ;A - db 2,128 ;B - db 3,1 ;C - db 3,2 ;D - db 3,4 ;E - db 3,8 ;F - db 3,16 ;G - db 3,32 ;H - db 3,64 ;I - db 3,128 ;J - db 4,1 ;K - db 4,2 ;L - db 4,4 ;M - db 4,8 ;N - db 4,16 ;O - db 4,32 ;P - db 4,64 ;Q - db 4,128 ;R - db 5,1 ;S - db 5,2 ;T - db 5,4 ;U - db 5,8 ;V - db 5,16 ;W - -CAPSON: - in a,(0AAh) - and 10111111b - out (0AAh),a - ret - -CAPSOFF: - push af - in a,(0AAh) - or 01000000b - out (0AAh),a - pop af - ret - - ;----------------------------------------------------------------------------- ; ; General disk routines entry @@ -604,7 +623,7 @@ CHG_ENTRY:: jp nc,DO_CALBNK ld d,a - ld a,(iy+2) + ld a,(iy+UD1_DI##) or a jp z,DISKERR @@ -622,8 +641,8 @@ CHG_ENTRY:: xor a ld ix,(DVB_TABLE##) - bit 7,(ix+2) - res 7,(ix+2) + bit 7,(ix+EMU_DEVLUN##) + res 7,(ix+EMU_DEVLUN##) ld b,1 ret z ld a,d @@ -636,9 +655,9 @@ CHGEN_NOEMU: ;Drive-based mapping: ;Return "changed" if partition has changed, "unchanged" otherwise - ld a,(iy+1) + ld a,(iy+UD1_REL##) ld c,a - res 7,(iy+1) + res 7,(iy+UD1_REL##) and 10000000b ;Check partition changed flag ld b,-1 ld a,c @@ -676,17 +695,17 @@ DO_MKDPB: DPBEN2: push hl - ld a,(iy+4) + ld a,(iy+UD1_FSEC##) ld (TMP_SEC##),a - ld a,(iy+5) + ld a,(iy+UD1_FSEC##+1) ld (TMP_SEC##+1),a - ld a,(iy+6) + ld a,(iy+UD1_FSEC##+2) ld (TMP_SEC##+2),a - ld a,(iy+7) + ld a,(iy+UD1_FSEC##+3) ld (TMP_SEC##+3),a - ld a,(iy+2) + ld a,(iy+UD1_DI##) ld b,1 - ld c,(iy+3) + ld c,(iy+UD1_LI##) ld de,TMP_SEC## ld hl,($SECBUF##) or a @@ -815,13 +834,13 @@ IS_DVB_NOEMU: IS_DVB_LOOP: push bc ld a,(KSLOT##) - ld b,(iy) + ld b,(iy+UD1_SLOT##) res 6,b cp b pop bc jr nz,DIO_NEXT - ld a,(iy+1) + ld a,(iy+UD1_REL##) and 01111111b ;Ignore partition changed flag cp c jr nz,DIO_NEXT @@ -870,10 +889,10 @@ IS_EMU: ; Return A=0, Z if partition assigned; A<>0, NZ if NO partition assigned. HAS_PARTITION: - ld a,(iy+4) ;No partition assigned - and (iy+5) ;if sector number is -1 - and (iy+6) - and (iy+7) + ld a,(iy+UD1_FSEC##) ;No partition assigned + and (iy+UD1_FSEC##+1) ;if sector number is -1 + and (iy+UD1_FSEC##+2) + and (iy+UD1_FSEC##+3) inc a jr z,RET_NZ xor a @@ -908,7 +927,8 @@ ASSIGN_PARTITION: ld b,(iy+UD1_DI##) ld c,(iy+UD1_LI##) - ld a,4 + ld a,4 + ld d,0 ld ix,AUTO_ASPART## call CALBNK## @@ -933,9 +953,9 @@ READ_BOOT: ld de,0 ld (TMP_SEC##),de ld (TMP_SEC##+2),de - ld a,(iy+2) + ld a,(iy+UD1_DI##) ld b,1 - ld c,(iy+3) + ld c,(iy+UD1_LI##) ld de,TMP_SEC## ld hl,($SECBUF##) or a @@ -1016,6 +1036,10 @@ DEFDPB: DB 3 DW 7 ; + + ALIGN 7BD0h + ;Here goes the 1K free area at the end of banks 0 and 3 + finish ; end diff --git a/source/kernel/kvar.mac b/source/kernel/kvar.mac index 7d6f10c8..18f37282 100644 --- a/source/kernel/kvar.mac +++ b/source/kernel/kvar.mac @@ -225,6 +225,10 @@ size macro name ;***************************************************************************** ; Entry in the device-based drives table (pointed by DVB_TABLE) in MSX-DOS 1 mode +; +; The table consists of one byte with the number of entries, followed by +; the entries themselves. +; ; WARNING: UD1_SLOT needs to be at the same position as UD_SLOT ifield 0 ;Start at offset zero @@ -238,6 +242,50 @@ size macro name size UD1_SZ ;Total size of unit descriptor +;----------------------------------------------------------------------------- +; +; Work area for the disk emulation mode (pointed by DVB_TABLE) +; +; Bit 7 of DSK_IDX is kept set to indicate that we are in disk emulation mode +; (if reset, it's the count of entries for the device-based drives table +; in normal DOS 1 mode, see UD1_*) +; +; Bit 6 of DSK_IDX is set if we have a Russian keyboard +; +; Bit 7 of EMU_DEVLUN is set after the current image file is changed +; and reset again when disk change is checked. +; +; WARNING: DSK_DEV, DSK_LUN and DSK_FSEC must have the same offset +; as the DI_* equivalents; this is required by DIO_ENTRY in drv.mac. + + ifield 0 ;Start at offset zero + + field 1,DSK_IDX ;Index of current disk image file + field 1,EMU_DEVLUN ;Device + 16 * LUN of emulation data mode + field 1,DSK_DEV ;Device index of current disk image file + field 1,DSK_LUN ;LUN index of current disk image file + field 4,DSK_FSEC ;First sector of current disk image file + field 2,DSK_SIZE ;Size of current disk image file in sectors + field 1,DSK_COUNT ;Number of emulated disk images + field 4,EMU_FSEC ;Sector number of the emulation data file + + size EMU_SZ ;Total size of unit descriptor + +;----------------------------------------------------------------------------- + + ;Temporary work area used at boot time + + const BOOT_TMP,0F980h + + ifield BOOT_TMP + + field EMU_SZ,EMU_TMP ;Temporary location of work area used when setting up disk emulation mode + field 1,IN_EMU ;Set to 1 when disk emulation mode has been entered + field 2,EMU_WK_AREA ;Address of work area as read from the emulation data file + ;NOTE! BOOTKEYS is used in dos1ker.mac, it must be manually updated if it changes + field 5,BOOTKEYS ;To store the state of boot keys + field 1,I_AM_RUSSIAN + field 1,HAVE_KEYS ; ;----------------------------------------------------------------------------- ; diff --git a/source/tools/.gitignore b/source/tools/.gitignore new file mode 100644 index 00000000..ec0e4206 --- /dev/null +++ b/source/tools/.gitignore @@ -0,0 +1,3 @@ +*.com +*.inc +*.COM \ No newline at end of file diff --git a/source/tools/C/.gitignore b/source/tools/C/.gitignore new file mode 100644 index 00000000..a26982a0 --- /dev/null +++ b/source/tools/C/.gitignore @@ -0,0 +1,3 @@ +*.asm +!crt0*.asm +*.com diff --git a/source/kernel/bank5/AsmCall.c b/source/tools/C/AsmCall.c similarity index 69% rename from source/kernel/bank5/AsmCall.c rename to source/tools/C/AsmCall.c index 423c8bc7..49c296bd 100644 --- a/source/kernel/bank5/AsmCall.c +++ b/source/tools/C/AsmCall.c @@ -1,43 +1,18 @@ -#include "asm.h" #include "asmcall.h" //The following is required in the main program: //byte ASMRUT[4]; //byte OUT_FLAGS; //Z80_registers regs; +// +//Also the following initialization is required: +//ASMRUT[0] = 0xC3; -void DriverCall(byte slot, uint routineAddress) +void DosCall(byte function, Z80_registers* regs, register_usage inRegistersDetail, register_usage outRegistersDetail) { - byte registerData[8]; - int i; - - memcpy(registerData, ®s, 8); - - regs.Bytes.A = slot; - regs.Bytes.B = 0xFF; - regs.UWords.DE = routineAddress; - regs.Words.HL = (int)registerData; - - DosCall(_CDRVR, REGS_ALL); - - if(regs.Bytes.A == 0) { - regs.Words.AF = regs.Words.IX; - } -} - - -void DosCall(byte function, register_usage outRegistersDetail) -{ - regs.Bytes.C = function; - SwitchSystemBankThenCall((int)0xF37D, outRegistersDetail); -} - - -void SwitchSystemBankThenCall(int routineAddress, register_usage outRegistersDetail) -{ - *((int*)BK4_ADD) = routineAddress; - AsmCall(CALLB0, ®s, REGS_ALL, outRegistersDetail); + regs->Bytes.C = function; + AsmCall(0x0005,regs,inRegistersDetail < REGS_MAIN ? REGS_MAIN : inRegistersDetail, outRegistersDetail); } diff --git a/source/kernel/bank5/asm.h b/source/tools/C/AsmCall.h similarity index 57% rename from source/kernel/bank5/asm.h rename to source/tools/C/AsmCall.h index fe57a4c7..29c82852 100644 --- a/source/kernel/bank5/asm.h +++ b/source/tools/C/AsmCall.h @@ -1,19 +1,8 @@ -#ifndef __ASM_H -#define __ASM_H +#ifndef __ASMCALL_H +#define __ASMCALL_H #include "types.h" -#ifndef NULL -#define NULL 0 -#endif - - -/* --- Register detail levels --- */ - -// This value tells which registers to pass in/out -// to the routine invoked by AsmCall, DosCall, BiosCall -// and UnapiCall. - typedef enum { REGS_NONE = 0, //No registers at all REGS_AF = 1, //AF only @@ -21,14 +10,6 @@ typedef enum { REGS_ALL = 3 //AF, BC, DE, HL, IX, IY } register_usage; - -/* --- Structure representing the Z80 registers --- - Registers can be accesses as: - Signed or unsigned words (ex: regs.Words.HL, regs.UWords.HL) - Bytes (ex: regs.Bytes.A) - Flags (ex: regs.Flags.Z) - */ - typedef union { struct { byte F; @@ -72,4 +53,10 @@ typedef union { } Flags; } Z80_registers; -#endif + +#define AsmCall(dir, regs, in, out) AsmCallAlt(dir, regs, in, out, 0) + +void DosCall(byte function, Z80_registers* regs, register_usage inRegistersDetail, register_usage outRegistersDetail); +void AsmCallAlt(uint address, Z80_registers* regs, register_usage inRegistersDetail, register_usage outRegistersDetail, int alternateAf); + +#endif //__ASMCALL_H \ No newline at end of file diff --git a/source/tools/C/asm.h b/source/tools/C/asm.h index daed18db..58965ae7 100644 --- a/source/tools/C/asm.h +++ b/source/tools/C/asm.h @@ -1,13 +1,7 @@ #ifndef __ASM_H #define __ASM_H -#ifndef uint -typedef unsigned int uint; -#endif - -#ifndef byte -typedef unsigned char byte; -#endif +#include "types.h" #ifndef NULL #define NULL 0 diff --git a/source/tools/C/compemu.bat b/source/tools/C/compemu.bat index e932865d..4a78c809 100644 --- a/source/tools/C/compemu.bat +++ b/source/tools/C/compemu.bat @@ -1,6 +1,6 @@ @echo off cls -sdcc --code-loc 0x180 --data-loc 0 -mz80 --disable-warning 196 --no-std-crt0 crt0msx_msxdos_advanced.rel msxchar.lib asm.lib emufile.c +sdcc --code-loc 0x180 --data-loc 0 -mz80 --disable-warning 196 --disable-warning 85 --no-std-crt0 crt0msx_msxdos_advanced.rel emufile.c if errorlevel 1 goto :end hex2bin -e com emufile.ihx copy emufile.com ..\..\..\bin\tools\ diff --git a/source/tools/C/compnexboot.bat b/source/tools/C/compnexboot.bat new file mode 100644 index 00000000..782e03e1 --- /dev/null +++ b/source/tools/C/compnexboot.bat @@ -0,0 +1,7 @@ +@echo off +cls +sdcc --code-loc 0x180 --data-loc 0 -mz80 --disable-warning 196 --disable-warning 85 --no-std-crt0 crt0msx_msxdos_advanced.rel nexboot.c +if errorlevel 1 goto :end +hex2bin -e com nexboot.ihx +copy nexboot.com ..\..\..\bin\tools\ +:end diff --git a/source/kernel/bank5/dos.h b/source/tools/C/dos.h similarity index 53% rename from source/kernel/bank5/dos.h rename to source/tools/C/dos.h index c6e50405..6e1c27b0 100644 --- a/source/kernel/bank5/dos.h +++ b/source/tools/C/dos.h @@ -10,7 +10,20 @@ #define MAX_INFO_LENGTH 64 -/* MSX-DOS data structures */ +/* MSX-DOS/Nextor data structures */ + +typedef struct { + byte alwaysFF; + char filename[13]; + byte attributes; + byte timeOfModification[2]; + byte dateOfModification[2]; + unsigned int startCluster; + unsigned long fileSize; + byte logicalDrive; + byte internal[38]; +} fileInfoBlock; + #define DRIVER_IS_DOS250 (1 << 7) #define DRIVER_IS_DEVICE_BASED 1 @@ -34,6 +47,19 @@ typedef struct { char deviceName[MAX_INFO_LENGTH]; } deviceInfo; +#define DRIVE_STATUS_ASSIGNED_TO_DEVICE 1 + + +typedef struct { + byte driveStatus; + byte driverSlotNumber; + byte driverSegmentNumber; + byte relativeDriveNumber; + byte deviceIndex; + byte logicalUnitNumber; + ulong firstSectorNumber; + byte reserved[64 - 10]; +} driveLetterInfo; #define BLOCK_DEVICE 0 #define READ_ONLY_LUN (1 << 1) @@ -47,23 +73,36 @@ typedef struct { uint cylinders; byte heads; byte sectorsPerTrack; - bool suitableForPartitionning; + bool suitableForPartitioning; } lunInfo; /* MSX-DOS functions */ +#define _TERM0 0 #define _DIRIO 0x06 #define _BUFIN 0x0A +#define _DPARM 0x31 +#define _FFIRST 0x40 +#define _FNEXT 0x41 +#define _OPEN 0x43 +#define _CREATE 0x44 +#define _CLOSE 0x45 +#define _READ 0x48 +#define _WRITE 0x49 +#define _PARSE 0x5B +#define _TERM 0x62 #define _EXPLAIN 0x66 +#define _DOSVER 0x6F #define _GDRVR 0x78 #define _GPART 0x7A #define _CDRVR 0x7B - +#define _GDLI 0x79 /* MSX-DOS error codes */ #define _IPART 0xB4 +#define _NOFIL 0xD7 /* Disk driver routines */ @@ -75,7 +114,7 @@ typedef struct { #define LUN_INFO 0x4169 -#define BK4_ADD 0xF84C +#define BK4_ADD 0xF1D0 #endif //__DOS_H \ No newline at end of file diff --git a/source/tools/C/emufile.c b/source/tools/C/emufile.c index 0d80eb39..5004ae2c 100644 --- a/source/tools/C/emufile.c +++ b/source/tools/C/emufile.c @@ -1,21 +1,12 @@ -/* DSK emulation configuration file creation tool for Nextor v1.0 - By Konamiman 2/2015 +/* DSK emulation configuration file creation tool for Nextor v1.1 + By Konamiman 3/2019 Compilation command line: sdcc --code-loc 0x180 --data-loc 0 -mz80 --disable-warning 196 --no-std-crt0 crt0_msxdos_advanced.rel msxchar.rel - asm.lib emufile.c + emufile.c hex2bin -e com emufile.ihx - - ASM.LIB, MSXCHAR.LIB and crt0msx_msxdos_advanced.rel - are available at www.konamiman.com - - (You don't need MSXCHAR.LIB if you manage to put proper PUTCHAR.REL, - GETCHAR.REL and PRINTF.REL in the standard Z80.LIB... I couldn't manage to - do it, I get a "Library not created with SDCCLIB" error) - - Comments are welcome: konamiman@konamiman.com */ /* Includes */ @@ -24,28 +15,15 @@ #include #include #include -#include - -//These are available at www.konamiman.com -#include "asm.h" +#include "types.h" +#include "system.h" +#include "dos.h" +#include "partit.h" +#include "asmcall.h" +#include "strcmpi.h" /* Typedefs */ -typedef unsigned char bool; -typedef unsigned long ulong; - -typedef struct { - byte alwaysFF; - char filename[13]; - byte attributes; - byte timeOfModification[2]; - byte dateOfModification[2]; - unsigned int startCluster; - unsigned long fileSize; - byte logicalDrive; - byte internal[38]; -} FileInfoBlock; - typedef struct { char signature[16]; byte numberOfEntriesInImagesTable; @@ -70,74 +48,90 @@ typedef struct { #define IS_NEXTOR (1 << 7) #define IS_DEVICE_BASED (1) +#define PARSE_FLAG_HAS_FILENAME (1 << 3) +#define PARSE_FLAG_HAS_EXTENSION (1 << 4) +#define PARSE_FLAG_IS_AMBIGUOUS (1 << 5) + #define MallocBase 0x8000 #define MaxFilesToProcess 32 -#define CALSLT 0x001C -#define EXPTBL 0xFCC1 +#define SetupRAMAddress ((byte*)0xA000) -#define _TERM0 0 -#define _DPARM 0x31 -#define _FFIRST 0x40 -#define _FNEXT 0x41 -#define _OPEN 0x43 -#define _CREATE 0x44 -#define _CLOSE 0x45 -#define _WRITE 0x49 -#define _TERM 0x62 -#define _DOSVER 0x6F -#define _GDRVR 0x78 -#define _GDLI 0x79 - -#define _NOFIL 0xD7 /* Strings */ const char* strTitle= - "DSK Emulation Configuration File Creation Tool for Nextor v1.0\r\n" - "By Konamiman, 2/2015\r\n" + "Disk image emulation tool for Nextor v1.1\r\n" + "By Konamiman, 3/2019\r\n" "\r\n"; const char* strUsage= - "Usage: emufile [] [ ...]\r\n" + "Usage: emufile [] [ ...]\r\n" + " emufile set [o|p[[]]]\r\n" + " emufile ?\r\n"; + +const char* strHelp= + "* To create an emulation data file:\r\n" "\r\n" - ": Disk image files to emulate. Can contain wildcards.\r\n" + "emufile [] [ ...]\r\n" + "\r\n" + ": Path and name of emulation data file to create.\r\n" + " Default extension is .EMU\r\n" "\r\n" ":\r\n" "\r\n" - "- o : Path and name of the generated configuration file.\r\n" - " Default is \"\\NEXT_DSK.DAT\"\r\n" - " If it ends with \"\\\" or \":\", file name will be \"NEXT_DSK.DAT\".\r\n" - "- b : The index of the image file to mount at boot time.\r\n" - " Must be 1-9 or A-W. Default is 1.\r\n" - "- a

: Page 3 address for the 16 byte work area.\r\n" - " Must be a hexadecimal number between C000 and FFEF.\r\n" - " If missing or 0, the work area is allocated at boot time.\r\n" - "- r : Reset the computer after generating the file.\r\n" - "- p : Print filenames and associated keys.\r\n" + "-b : The index of the image file to mount at boot time.\r\n" + " Must be 1-9 or A-W. Default is 1.\r\n" + "-a
: Page 3 address for the 16 byte work area.\r\n" + " Must be a hexadecimal number between C000 and FFEF.\r\n" + " If missing or 0, the work area is allocated at boot time.\r\n" + "-p : Print filenames and associated keys after creating the data file.\r\n" + "\r\n" + "TYPE /B the generated file to see the names of the registered files.\r\n" + "\r\n" + "\r\n" + "* To setup an existing emulation data file for booting:\r\n" + "\r\n" + "emufile set [o|p[[]]]\r\n" "\r\n" - "TYPE /B the generated file to see the names of the registered files.\r\n"; + "o: one-time emulation (store emulation data file pointer in RAM).\r\n" + "This is the default if only is specified.\r\n" + "\r\n" + "p: persistent emulation (store emulation data file pointer in partition table).\r\n" + "Use and to specify the device whose\r\n" + "partition table will be written. Default device (if only 'p' is specified)\r\n" + "is the device where the emulation data file is located.\r\n" + "Default (if only 'p' is specified) is 1.\r\n" + "\r\n" + "The computer will reset after successfully finishing the setup.\r\n"; const char* strInvParam = "Invalid parameter"; const char* strCRLF = "\r\n"; +const char* emuDataSignature = "NEXTOR_EMU_DATA"; + /* Global variables */ Z80_registers regs; +byte ASMRUT[4]; +byte OUT_FLAGS; void* mallocPointer; char* outputFileName; int bootFileIndex; -bool autoReset; bool printFilenames; uint workAreaAddress; -FileInfoBlock* fib; +fileInfoBlock* fib; int totalFilesProcessed; -byte* driveInfo; +driveLetterInfo* driveInfo; byte* driveParameters; byte* fileContentsBase; byte* fileNamesBase; byte* fileNamesAppendAddress; +byte fileHandle; +int setupPartitionDeviceIndex; +int setupPartitionLunIndex; +bool setupAsPersistent; /* Some handy code defines */ @@ -150,7 +144,9 @@ byte* fileNamesAppendAddress; void CheckPreconditions(); void CheckPrimaryControllerIsNextor(); void Initialize(); -void ProcessArguments(char** argv, int argc); +bool ProcessArguments(char** argv, int argc); +void ProcessCreateFileArguments(char** argv, int argc); +void ProcessSetupFileArguments(char** argv, int argc); int ProcessOption(char optionLetter, char* optionValue); void ProcessFilename(char* fileName); void TooManyFiles(); @@ -158,17 +154,15 @@ void StartSearchingFiles(char* fileName); void ProcessFileFound(); void GetDriveInfoForFileInFib(); void CheckControllerForFileInFib(); -ulong GetFirstDriveSectorForFileInFib(); ulong GetFirstFileSectorForFileInFib(); void AddFileInFibToFilesTable(ulong sector); +void SetDeviceIndexesOfFilesTableToZeroIfAllInSameDeviceAsDataFile(); void AddFileInFibToFilenamesInfo(); void GenerateFile(); -void ProcessOutputFileOption(char* optionValue); +void AddFileExtension(char* fileName); void ProcessBootIndexOption(char* optionValue); void ProcessWorkAreaAddressOption(char* optionValue); -void ProcessResetOption(); void ProcessPrintFilenamesOption(); - void Terminate(const char* errorMessage); void TerminateWithDosError(byte errorCode); void print(char* s); @@ -176,26 +170,39 @@ void CheckDosVersion(); void* malloc(int size); uint ParseHex(char* hexString); void DoDosCall(byte functionCode); +void SetupFile(); +void DriverCall(byte slot, uint routineAddress); +byte DeviceSectorRW(byte driverSlot, byte deviceIndex, byte lunIndex, ulong sectorNumber, byte* buffer, bool write); +void VerifyDataFileSignature(byte* sectorBuffer); void ResetComputer(); +#define ReadDeviceSector(driverSlot, deviceIndex, lunIndex, sectorNumber, buffer) DeviceSectorRW(driverSlot, deviceIndex, lunIndex, sectorNumber, buffer, false) +#define WriteDeviceSector(driverSlot, deviceIndex, lunIndex, sectorNumber, buffer) DeviceSectorRW(driverSlot, deviceIndex, lunIndex, sectorNumber, buffer, true) + /* MAIN */ int main(char** argv, int argc) { + bool isSetupFile; + + ASMRUT[0] = 0xC3; print(strTitle); - + CheckPreconditions(); Initialize(); - ProcessArguments(argv, argc); + isSetupFile = ProcessArguments(argv, argc); + + if(isSetupFile) { + SetupFile(); + printf("Done. Resetting computer..."); + ResetComputer(); + } if(totalFilesProcessed > 0) { + SetDeviceIndexesOfFilesTableToZeroIfAllInSameDeviceAsDataFile(); GenerateFile(); printf( "%s%s successfully generated!\r\n%i disk image file(s) registered\r\n", printFilenames ? "\r\n" : "", outputFileName, totalFilesProcessed); - if(autoReset) { - print("Resetting computer..."); - ResetComputer(); - } } else { print(strUsage); } @@ -234,10 +241,10 @@ void Initialize() mallocPointer = (void*)MallocBase; outputFileName = malloc(128); - strcpy(outputFileName, "\\NEXT_DSK.DAT"); + *outputFileName = (char)0; - fib = malloc(sizeof(FileInfoBlock)); - driveInfo = malloc(64); + fib = malloc(sizeof(fileInfoBlock)); + driveInfo = malloc(sizeof(driveLetterInfo)); driveParameters = malloc(32); fileContentsBase = malloc( sizeof(GeneratedFileHeader) + @@ -245,44 +252,122 @@ void Initialize() fileNamesBase = malloc(19 * MaxFilesToProcess); fileNamesAppendAddress = fileNamesBase; + fileHandle = 0; bootFileIndex = 1; - autoReset = false; printFilenames = false; workAreaAddress = 0; totalFilesProcessed = 0; } -void ProcessArguments(char** argv, int argc) +bool ProcessArguments(char** argv, int argc) { - int i; - char* currentArg; + if(argc > 0 && argv[0][0] == '?') { + print(strHelp); + Terminate(null); + } - if(argc == 0) { + if(argc < 2) { print(strUsage); Terminate(null); } - + + if(strcmpi(argv[0], "set") == 0) { + ProcessSetupFileArguments(argv, argc); + return true; + } + + ProcessCreateFileArguments(argv, argc); + return false; +} + +void ProcessCreateFileArguments(char** argv, int argc) +{ + int i; + char* currentArg; + bool processingOptions; + + processingOptions = true; + for(i=0; i 9) { + Terminate("Invalid device index"); + } + + if(argv[2][2] == '\0') { + setupPartitionLunIndex = 1; + return; + } + + setupPartitionLunIndex = argv[2][2] - '0'; + if(setupPartitionLunIndex < 1 || setupPartitionLunIndex > 9) { + Terminate("Invalid LUN index"); + } + + if(argv[2][3] != '\0') { + InvalidParameter(); + } } int ProcessOption(char optionLetter, char* optionValue) { optionLetter |= 32; - if(optionLetter == 'o') { - ProcessOutputFileOption(optionValue); - return 1; - } - if(optionLetter == 'b') { ProcessBootIndexOption(optionValue); return 1; @@ -293,11 +378,6 @@ int ProcessOption(char optionLetter, char* optionValue) return 1; } - if(optionLetter == 'r') { - ProcessResetOption(); - return 0; - } - if(optionLetter == 'p') { ProcessPrintFilenamesOption(); return 0; @@ -307,15 +387,17 @@ int ProcessOption(char optionLetter, char* optionValue) return 0; } -void ProcessOutputFileOption(char* optionValue) +void AddFileExtension(char* fileName) { - char* lastCharPointer; - - strcpy(outputFileName, optionValue); - lastCharPointer = outputFileName + strlen(outputFileName) - 1; - if(*lastCharPointer == '\\' || *lastCharPointer == ':') { - strcpy(lastCharPointer + 1, "NEXT_DSK.DAT"); - } + strcpy(outputFileName, fileName); + + regs.Bytes.B = 0; + regs.Words.DE = (int)outputFileName; + DoDosCall(_PARSE); + + if(!(regs.Bytes.B & PARSE_FLAG_HAS_EXTENSION)) { + strcpy((char*)regs.Words.DE, ".EMU"); + } } void ProcessBootIndexOption(char* optionValue) @@ -346,11 +428,6 @@ void ProcessWorkAreaAddressOption(char* optionValue) } } -void ProcessResetOption() -{ - autoReset = true; -} - void ProcessPrintFilenamesOption() { printFilenames = true; @@ -403,8 +480,7 @@ void ProcessFileFound() return; } - sector = GetFirstDriveSectorForFileInFib(); - sector += GetFirstFileSectorForFileInFib(); + sector = driveInfo->firstSectorNumber + GetFirstFileSectorForFileInFib(); AddFileInFibToFilesTable(sector); AddFileInFibToFilenamesInfo(); @@ -425,17 +501,12 @@ void GetDriveInfoForFileInFib() void CheckControllerForFileInFib() { - if(driveInfo[0] != 1 || driveInfo[1] != PrimaryControllerSlot()) { + if(driveInfo->driveStatus != DRIVE_STATUS_ASSIGNED_TO_DEVICE || driveInfo->driverSlotNumber != PrimaryControllerSlot()) { printf("*** Drive %c: is not controlled by the primary Nextor kernel\r\n", fib->logicalDrive - 1 + 'A'); Terminate(null); } } -ulong GetFirstDriveSectorForFileInFib() -{ - return *((ulong*)(driveInfo + 6)); -} - ulong GetFirstFileSectorForFileInFib() { ulong firstDataSector; @@ -462,8 +533,8 @@ void AddFileInFibToFilesTable(ulong sector) sizeof(GeneratedFileHeader) + (sizeof(GeneratedFileTableEntry) * totalFilesProcessed)); - tableEntry->deviceIndex = *(driveInfo + 4); - tableEntry->logicalUnitNumber = *(driveInfo + 5); + tableEntry->deviceIndex = driveInfo->deviceIndex; + tableEntry->logicalUnitNumber = driveInfo->logicalUnitNumber; tableEntry->firstFileSector = sector; tableEntry->fileSizeInSector = (uint)(fib->fileSize >> 9); } @@ -480,11 +551,44 @@ void AddFileInFibToFilenamesInfo() *fileNamesAppendAddress++ = '\n'; } +void SetDeviceIndexesOfFilesTableToZeroIfAllInSameDeviceAsDataFile() +{ + GeneratedFileTableEntry* tableEntry; + int i; + + regs.Bytes.B = 0; + regs.Words.DE = (int)outputFileName; + DoDosCall(_PARSE); + regs.Bytes.A = regs.Bytes.C - 1; //drive number of the data file + regs.Words.HL = (int)driveInfo; + DoDosCall(_GDLI); + + tableEntry = (GeneratedFileTableEntry*)(fileContentsBase + sizeof(GeneratedFileHeader)); + + for(i=0; ideviceIndex != driveInfo->deviceIndex || tableEntry->logicalUnitNumber != driveInfo->logicalUnitNumber) { + return; + } + tableEntry++; + } + + tableEntry = (GeneratedFileTableEntry*)(fileContentsBase + sizeof(GeneratedFileHeader)); + + for(i=0; ideviceIndex = 0; + tableEntry->logicalUnitNumber = 0; + tableEntry++; + } +} + void GenerateFile() { GeneratedFileHeader* header; byte fileHandle; char* fileNamesHeader; + char* bootFileIndexString; if(bootFileIndex > totalFilesProcessed) { bootFileIndex = totalFilesProcessed; @@ -493,7 +597,7 @@ void GenerateFile() } header = (GeneratedFileHeader*)fileContentsBase; - strcpy(header->signature, "Nextor DSK file"); + strcpy(header->signature, emuDataSignature); header->numberOfEntriesInImagesTable = totalFilesProcessed; header->indexOfImageToMountAtBoot = bootFileIndex; header->workAreaAddress = workAreaAddress; @@ -511,7 +615,7 @@ void GenerateFile() (sizeof(GeneratedFileHeader) + (sizeof(GeneratedFileTableEntry) * totalFilesProcessed)); DoDosCall(_WRITE); - + fileNamesHeader = "\fDisk image files registered:\r\n\r\n"; regs.Bytes.B = fileHandle; regs.Words.DE = (int)fileNamesHeader; @@ -522,28 +626,155 @@ void GenerateFile() regs.Words.DE = (int)fileNamesBase; regs.Words.HL = (int)(fileNamesAppendAddress - fileNamesBase); DoDosCall(_WRITE); + + bootFileIndexString = malloc(32); + sprintf(bootFileIndexString, "\r\nBoot file index: %i\r\n", bootFileIndex); + regs.Bytes.B = fileHandle; + regs.Words.DE = (int)bootFileIndexString; + regs.Words.HL = strlen(bootFileIndexString); + DoDosCall(_WRITE); regs.Bytes.B = fileHandle; DoDosCall(_CLOSE); +} + +void SetupFile() +{ + ulong sector; + masterBootRecord* sectorBuffer; + partitionTableEntry* partition; + byte error; + + AddFileExtension(outputFileName); + StartSearchingFiles(outputFileName); + GetDriveInfoForFileInFib(); + CheckControllerForFileInFib(); + + if(fib->fileSize == 0) { + Terminate("*** The emulation data file is empty"); + } + + sectorBuffer = malloc(sizeof(masterBootRecord)); + + VerifyDataFileSignature((byte*)sectorBuffer); + + sector = driveInfo->firstSectorNumber + GetFirstFileSectorForFileInFib(); + + if(setupPartitionDeviceIndex == 0) { + setupPartitionDeviceIndex = driveInfo->deviceIndex; + setupPartitionLunIndex = driveInfo->logicalUnitNumber; + } + + sectorBuffer = malloc(sizeof(masterBootRecord)); + error = ReadDeviceSector(driveInfo->driverSlotNumber, setupPartitionDeviceIndex, setupPartitionLunIndex, 0, (byte*)sectorBuffer); + if(error != 0) { + print("*** Error when reading MBR of device:"); + TerminateWithDosError(error); + } + if(setupAsPersistent) { + partition = &(sectorBuffer->primaryPartitions[0]); + partition->status |= 1; + partition->chsOfFirstSector[0] = driveInfo->deviceIndex; + partition->chsOfFirstSector[1] = driveInfo->logicalUnitNumber; + partition->chsOfFirstSector[2] = ((byte*)§or)[3]; //MSB + partition->chsOfLastSector[0] = ((byte*)§or)[2]; + partition->chsOfLastSector[1] = ((byte*)§or)[1]; + partition->chsOfLastSector[2] = ((byte*)§or)[0]; //LSB + + error = WriteDeviceSector(driveInfo->driverSlotNumber, setupPartitionDeviceIndex, setupPartitionLunIndex, 0, (byte*)sectorBuffer); + if(error != 0) { + print("*** Error when writing MBR of device:"); + TerminateWithDosError(error); + } + } else { + strcpy(SetupRAMAddress, emuDataSignature); + SetupRAMAddress[0x10] = driveInfo->deviceIndex; + SetupRAMAddress[0x11] = driveInfo->logicalUnitNumber; + SetupRAMAddress[0x12] = ((byte*)§or)[0]; //LSB + SetupRAMAddress[0x13] = ((byte*)§or)[1]; + SetupRAMAddress[0x14] = ((byte*)§or)[2]; + SetupRAMAddress[0x15] = ((byte*)§or)[3]; //MSB + } +} + +void VerifyDataFileSignature(byte* sectorBuffer) +{ + regs.Words.DE = (int)outputFileName; + regs.Bytes.A = 1; //read-only + DoDosCall(_OPEN); + fileHandle = regs.Bytes.B; + + regs.Words.DE = (int)sectorBuffer; + regs.Words.HL = 16; + DoDosCall(_READ); + + if(regs.Words.HL < 16 || strcmpi((char*)sectorBuffer, emuDataSignature) != 0) { + Terminate("Invalid emulation data file"); + } +} + +byte DeviceSectorRW(byte driverSlot, byte deviceIndex, byte lunIndex, ulong sectorNumber, byte* buffer, bool write) +{ + regs.Flags.C = write; + regs.Bytes.A = deviceIndex; + regs.Bytes.B = 1; + regs.Bytes.C = lunIndex; + regs.Words.HL = (int)buffer; + regs.Words.DE = (int)§orNumber; + + DriverCall(driverSlot, DEV_RW); + return regs.Bytes.A; +} + +void DriverCall(byte slot, uint routineAddress) +{ + byte registerData[8]; + int i; + + memcpy(registerData, ®s, 8); + + regs.Bytes.A = slot; + regs.Bytes.B = 0xFF; + regs.UWords.DE = routineAddress; + regs.Words.HL = (int)registerData; + + DoDosCall(_CDRVR); + + regs.Words.AF = regs.Words.IX; +} + +void ResetComputer() +{ + regs.Bytes.IYh = *(byte*)EXPTBL; + regs.Words.IX = 0; + AsmCall(CALSLT, ®s, REGS_ALL, REGS_NONE); + + //Just in case, but we should never reach here + Terminate(null); } void Terminate(const char* errorMessage) { + if(fileHandle != 0) { + regs.Bytes.B = fileHandle; + DoDosCall(_CLOSE); + } + if(errorMessage != NULL) { printf("\r\x1BK*** %s\r\n", errorMessage); } regs.Bytes.B = (errorMessage == NULL ? 0 : 1); - DosCall(_TERM, ®s, REGS_MAIN, REGS_NONE); - DosCall(_TERM0, ®s, REGS_MAIN, REGS_NONE); + DoDosCall(_TERM); + DoDosCall(_TERM0); } void TerminateWithDosError(byte errorCode) { regs.Bytes.B = errorCode; - DosCall(_TERM, ®s, REGS_MAIN, REGS_NONE); + DoDosCall(_TERM); } @@ -577,7 +808,7 @@ void CheckDosVersion() { regs.Bytes.B = 0x5A; regs.Words.HL = 0x1234; - regs.Words.DE = 0xABCD; + regs.Words.DE = (int)0xABCD; regs.Words.IX = 0; DosCall(_DOSVER, ®s, REGS_ALL, REGS_ALL); @@ -625,9 +856,7 @@ void DoDosCall(byte functionCode) } } -void ResetComputer() -{ - regs.Bytes.IYh = *(byte*)EXPTBL; - regs.Words.IX = 0; - AsmCall(CALSLT, ®s, REGS_ALL, REGS_NONE); -} \ No newline at end of file +#define COM_FILE +#include "printf.c" +#include "asmcall.c" +#include "strcmpi.c" diff --git a/source/tools/C/nexboot.c b/source/tools/C/nexboot.c new file mode 100644 index 00000000..69adf1ef --- /dev/null +++ b/source/tools/C/nexboot.c @@ -0,0 +1,206 @@ +/* Nextor temporary boot keys configuration tool + By Konamiman 3/2019 + + Compilation command line: + + sdcc --code-loc 0x180 --data-loc 0 -mz80 --disable-warning 196 + --no-std-crt0 crt0_msxdos_advanced.rel msxchar.rel + nexboot.c + hex2bin -e com emufile.ihx +*/ + +#include +#include +#include +#include +#include "types.h" +#include "system.h" +#include "dos.h" +#include "asmcall.h" +#include "strcmpi.h" + +/* Defines */ + +#define false (0) +#define true (!(false)) +#define null ((void*)0) + +#define RamKeysAddress ((byte*)0xA100) + +/* Strings */ + +const char* strTitle= + "One-time boot keys configuration tool for Nextor v1.0\r\n" + "By Konamiman, 3/2019\r\n" + "\r\n"; + +const char* strUsage= + "Usage: nexboot |. [ [ ...]]\r\n" + "\r\n" + ": keys that will be considered as pressed in next boot.\r\n" + " can include the numbers 1 to 9, C (for CTRL) and S (for SHIFT)\r\n," + "or be '.' to not specify any key (if you only want to disable kernels).\r\n" + "\r\n" + "s: slot numbers of the Nextor kernels to disable in the next boot.\r\n" + "They can be followed by a subslot number, e.g. 13 for slot 1, subslot 3.\r\n" + "\r\n" + "The computer will reset after successfully setting the keys.\r\n"; + +const char* strInvParam = "Invalid parameter"; +const char* strInvSlot = "Invalid slot specification"; +const char* strCRLF = "\r\n"; + +/* Global variables */ + +Z80_registers regs; +byte ASMRUT[4]; +byte OUT_FLAGS; +byte keyFlags[5]; + +//First value: byte offset in keyFlags +//Second value: mask to set in the byte in keyFlags +byte keysBySlot[16*2] = { + 3, 0b01000000, //0-0: U + 3, 0b00000100, //1-0: Q + 1, 0b00000100, //2-0: A + 4, 0b00001000, //3-0: Z + + 2, 0b00000100, //0-1: I + 4, 0b00000001, //1-1: W + 3, 0b00010000, //2-1: S + 4, 0b00000010, //3-1: X + + 3, 0b00000001, //0-2: O + 1, 0b01000000, //1-2: E + 1, 0b00100000, //2-2: D + 1, 0b00010000, //3-2: C + + 3, 0b00000010, //0-3: P + 3, 0b00001000, //1-3: R + 1, 0b10000000, //2-3: F + 3, 0b10000000, //3-3: V +}; + +/* Function prototypes */ + +void GetSlotDisableKeys(int count, char** slots); +void GetNumericBits(char* keys); +void SetKeysInRam(); +void Terminate(const char* errorMessage); +void InvalidParameter(); +void ResetComputer(); + +/* MAIN */ + +int main(char** argv, int argc) +{ + ASMRUT[0] = 0xC3; + memset(keyFlags, 0, 5); + + printf(strTitle); + + if(argc == 0) { + printf(strUsage); + Terminate(null); + } + + if(argv[0][0] != '.') { + GetNumericBits(argv[0]); + } + + if(argc > 1) { + GetSlotDisableKeys(argc-1, argv+1); + } + + SetKeysInRam(); + + printf("Done. Resetting computer..."); + ResetComputer(); + + return 0; +} + +void GetNumericBits(char* keys) +{ + byte keysCount; + byte currentKey; + byte i; + + keysCount = strlen(keys); + for(i=0; i= '1' && currentKey <= '7') { + keyFlags[0] |= (1 << currentKey-'0'); + } + else if(currentKey == '8' || currentKey == '9') { + keyFlags[1] |= (1 << currentKey-'8'); + } + else if(currentKey == 's') { + keyFlags[4] |= 0x10; + } + else if(currentKey == 'c') { + keyFlags[4] |= 0x20; + } + else { + Terminate("Invalid key specification"); + } + } +} + +void GetSlotDisableKeys(int count, char** slots) +{ + int i; + char* slot; + byte slotNumber; + + for(i=0; i '3') { + Terminate(strInvSlot); + } + + slotNumber = slot[0] - '0'; + + if(slot[1] != '\0') { + if(slot[1] < '0' || slot[1] > '3') { + Terminate(strInvSlot); + } + + slotNumber |= (slot[1] - '0') << 2; + } + + keyFlags[keysBySlot[slotNumber*2]] |= keysBySlot[(slotNumber*2)+1]; + } +} + +void SetKeysInRam() +{ + strcpy(RamKeysAddress, "NEXTOR_BOOT_KEYS"); + memcpy(RamKeysAddress+0x11, keyFlags, 5); +} + +void Terminate(const char* errorMessage) +{ + if(errorMessage != NULL) { + printf("\r\x1BK*** %s\r\n", errorMessage); + } + + regs.Bytes.B = (errorMessage == NULL ? 0 : 1); + DosCall(_TERM, ®s, REGS_MAIN, REGS_NONE); + DosCall(_TERM0, ®s, REGS_MAIN, REGS_NONE); +} + +void ResetComputer() +{ + regs.Bytes.IYh = *(byte*)EXPTBL; + regs.Words.IX = 0; + AsmCall(CALSLT, ®s, REGS_ALL, REGS_NONE); + + //Just in case, but we should never reach here + Terminate(null); +} + +#define COM_FILE +#include "printf.c" +#include "asmcall.c" diff --git a/source/kernel/bank5/partit.h b/source/tools/C/partit.h similarity index 93% rename from source/kernel/bank5/partit.h rename to source/tools/C/partit.h index ca8019f0..774cdf54 100644 --- a/source/kernel/bank5/partit.h +++ b/source/tools/C/partit.h @@ -1,7 +1,7 @@ #ifndef __PARTIT_H #define __PARTIT_H -#include "types.h" +#include "../../tools/C/types.h" #define MAX_PARTITIONS_TO_HANDLE 256 #define MIN_DEVICE_SIZE_IN_K 10 @@ -40,6 +40,7 @@ typedef struct { byte primaryIndex; byte extendedIndex; byte partitionType; + byte status; ulong sizeInK; uint alignmentPaddingInSectors; } partitionInfo; diff --git a/source/kernel/bank5/printf.c b/source/tools/C/printf.c similarity index 92% rename from source/kernel/bank5/printf.c rename to source/tools/C/printf.c index d788d184..31c38094 100644 --- a/source/kernel/bank5/printf.c +++ b/source/tools/C/printf.c @@ -29,6 +29,8 @@ #include #include "system.h" +#define CONOUT 2 + #ifdef SUPPORT_LONG extern void _ultoa(long val, char* buffer, char base); extern void _ltoa(long val, char* buffer, char base); @@ -67,10 +69,15 @@ static void do_char(const char* buf, char c) __naked ld h,a or l +#ifdef COM_FILE + ld c,#CONOUT + jp z,5 +#else ld a,e jp z,CHPUT +#endif - ld(hl),e + ld (hl),e ret __endasm; diff --git a/source/tools/C/strcmpi.c b/source/tools/C/strcmpi.c new file mode 100644 index 00000000..26c0e8b0 --- /dev/null +++ b/source/tools/C/strcmpi.c @@ -0,0 +1,12 @@ +int strcmpi(const char *a1, const char *a2) { + char c1, c2; + /* Want both assignments to happen but a 0 in both to quit, so it's | not || */ + while((c1=*a1) | (c2=*a2)) { + if (!c1 || !c2 || /* Unneccesary? */ + (islower(c1) ? toupper(c1) : c1) != (islower(c2) ? toupper(c2) : c2)) + return (c1 - c2); + a1++; + a2++; + } + return 0; +} diff --git a/source/tools/C/strcmpi.h b/source/tools/C/strcmpi.h new file mode 100644 index 00000000..d94139c1 --- /dev/null +++ b/source/tools/C/strcmpi.h @@ -0,0 +1,6 @@ +#ifndef __STRCMPI_H +#define __STRCMPI_H + +int strcmpi(const char *a1, const char *a2); + +#endif diff --git a/source/kernel/bank5/system.h b/source/tools/C/system.h similarity index 84% rename from source/kernel/bank5/system.h rename to source/tools/C/system.h index a0aef783..4ab4a7ec 100644 --- a/source/kernel/bank5/system.h +++ b/source/tools/C/system.h @@ -8,11 +8,13 @@ #define ESC 27 #define CURSOR_RIGHT 28 #define CURSOR_LEFT 29 +#define KEY_1 49 /* MSX BIOS routines */ #define SYNCHR 0x0008 +#define CALSLT 0x001C #define INITXT 0x006C #define INIT32 0x006F #define CHPUT 0x00A2 @@ -40,7 +42,6 @@ #define VALTYP 0xF663 #define DAC 0xF7F6 #define SCRMOD 0xFCAF - - +#define EXPTBL 0xFCC1 #endif //__SYSTEM_H \ No newline at end of file diff --git a/source/kernel/bank5/types.h b/source/tools/C/types.h similarity index 100% rename from source/kernel/bank5/types.h rename to source/tools/C/types.h diff --git a/source/tools/C/vsft.c b/source/tools/C/vsft.c index 8976c813..40d9936b 100644 --- a/source/tools/C/vsft.c +++ b/source/tools/C/vsft.c @@ -26,6 +26,7 @@ #include #include #include +#include "strcmpi.h" //These are available at www.konamiman.com #include "asm.h" @@ -147,7 +148,6 @@ void TerminateWithDosError(byte errorCode); void print(char* s); void CheckDosVersion(); void ExtractParameters(char** argv, int argc); -int strcmpi(const char *a1, const char *a2); void GetDriveInfo(); void PrintDriveInfo(); void PrintSizeInK(unsigned long size); @@ -278,21 +278,6 @@ void ExtractParameters(char** argv, int argc) } } - -int strcmpi(const char *a1, const char *a2) { - char c1, c2; - /* Want both assignments to happen but a 0 in both to quit, so it's | not || */ - while((c1=*a1) | (c2=*a2)) { - if (!c1 || !c2 || /* Unneccesary? */ - (islower(c1) ? toupper(c1) : c1) != (islower(c2) ? toupper(c2) : c2)) - return (c1 - c2); - a1++; - a2++; - } - return 0; -} - - void GetDriveInfo() { regs.Words.DE = (int)Buffer; @@ -469,3 +454,5 @@ void WritebootSector() TerminateWithDosError(regs.Bytes.A); } } + +#include "strcmpi.c" diff --git a/source/tools/compile.bat b/source/tools/compile.bat index bea4f0ab..ec9240fd 100644 --- a/source/tools/compile.bat +++ b/source/tools/compile.bat @@ -1,10 +1,10 @@ @echo off cls -copy ..\msxdos25\macros.inc -copy ..\msxdos25\const.inc -copy ..\msxdos25\codes.mac -copy ..\msxdos25\data.mac +copy ..\kernel\macros.inc +copy ..\kernel\const.inc +copy ..\kernel\codes.mac +copy ..\kernel\data.mac for %%A in (CODES,DATA,SHARED) do cpm32 M80 =%%A del codes.mac del data.mac diff --git a/wintools/.gitignore b/wintools/.gitignore new file mode 100644 index 00000000..1b2081ac --- /dev/null +++ b/wintools/.gitignore @@ -0,0 +1 @@ +*.obj diff --git a/wintools/mknexrom.c b/wintools/mknexrom.c index eeed4fe3..72a202c3 100644 --- a/wintools/mknexrom.c +++ b/wintools/mknexrom.c @@ -1,8 +1,8 @@ /* MKNEXROM - Make a Nextor kernel ROM - By Konamiman, 4/2014 + By Konamiman, 3/2019 Usage: - mknexrom [/d:] [/m:] [/e:] [/8:<8K bank select address>] + mknexrom [] [/d:] [/m:] [/e:] [/8:<8K bank select address>] [/k:] This program creates a Nextor kernel ROM from a base file and a driver file, as per the recipe specified in the driver development guide. It also allows modifying @@ -71,6 +71,10 @@ inc a ld (6800h),a ret + + + is a hexadecimal number that contains the value of the boot key invert bytes, + LSB is byte 0 and MSX is byte 1. For example 1002 to invert keys SHIFT and 1. */ /* v1.01 (4/2011): @@ -90,7 +94,10 @@ v1.05 (4/2014): Added the <8K bank select address> parameter. - + + v1.06 (3/2019): + Added the parameter. + Existing full ROM files can now be updated, is optional for these. */ @@ -114,6 +121,7 @@ #define _8K_INIT_PATCH_ADDRESS 0x00F7 //File position where the patch for 8K bank mapper must be written #define LD_XXXX_A_OPCODE 0x32 #define MAPPER_CODE_HEADER_SIZE 3 +#define BOOT_KEYS_INVERTER_OFFSET 0x200 #define safeClose(file) {if(file!=NULL) {fclose(file); file=NULL;}} @@ -140,6 +148,11 @@ int main(int argc, char* argv[]) int i; unsigned short position; int First8KMappingAddress=0; + int hasBootKeys=0; + int bootKeys=0; + char byteBuffer; + int modifyOriginalFile; + int firstModifierArgumentIndex; char* baseFilename=NULL; char* newFilename=NULL; @@ -160,14 +173,23 @@ int main(int argc, char* argv[]) //* Get command line parameters printf("\r\n"); - if(argc<4) { + if(argc<3) { DisplayInfo(); DoExit(0); } baseFilename=argv[1]; - newFilename=argv[2]; - for(i=3; i> 8); + writeCount+=fwrite(&byteBuffer, 1, 1, newFile); + + if(writeCount!=2) { + printf("*** Can't write boot keys inverter bytes to the ROM file: %s\r\n", newFilename); + DoExit(1); + } + } //* Done - printf("ROM file %s created successfully.", newFilename); + if(modifyOriginalFile) { + printf("ROM file %s updated successfully.", baseFilename); + } else { + printf("ROM file %s created successfully.", newFilename); + } + DoExit(0); } @@ -467,12 +526,12 @@ int main(int argc, char* argv[]) void DisplayInfo() { - printf("MKNEXROM v1.05 - Make a Nextor kernel ROM\r\n" - "By Konamiman, 4/2014\r\n" + printf("MKNEXROM v1.06 - Make a Nextor kernel ROM\r\n" + "By Konamiman, 3/2019\r\n" "\r\n" "Usage:\r\n" - "mknexrom [/d:] [/m:]\r\n" - " [/e:] [/8:<8K bank select address>]\r\n" + "mknexrom [] [/d:] [/m:]\r\n" + " [/e:] [/8:<8K bank select address>] [/k:]\r\n" ); } diff --git a/wintools/mknexrom.exe b/wintools/mknexrom.exe index ef0116683958f19d2868821b92a3a685f1ce72d1..63e243543c282346d20fd47bdb09acd8acae8405 100644 GIT binary patch literal 140288 zcmeFaeS8$v^*=tF-6RXyFpDG*0WnHYXut**ZE%Aozy?r)o5Umpo1j(cx*$@R32F%> zPF6FyZspTLt1Yxzw8d|2wN(+V&}?G!fG7|4qbO8^rS+zpY6MC)7}?+Z+?m}ZKGeSY zdwBi+D7<#&&V4xd+;h)8=iGD8Op2Cok*ty=+3<@-C20@t^e&NHg`HI>H#=j-*_m8g>cWwM4QBRvN9`_5^KQR6- zale23a&fO0^^UH)fBbcLKDw?>+)M7b)km;DI})!)l9pI((yNa8Z^p{Hqy$TfWt3Ce zYLTQL8o6f(Q73-SAdjd*=>$ni!j1mL?$XW3BqHLURm!gy6{#*Y5cl|vGNl`x3DQ)N z`jSh2f^=pyx=l`yCVoj3%07hh{GsK*GlNk5l7Ckyx8JRx?A7n165&N-HSvx$$&{p< zuUL26Ey^vD^!=5{rLp^Pe;D^6|MEeQD~xJV7g0D9G`N5&;6CJEz9cnYvF`TOcik$9 zF-aJksCU8V>dhO{?7zwX4=8ZpGylq1kB?tIPvUQY`LtJTRjtD-pj_**GmqWNUtJ(- z=$-+8f?r}q_F}%{8p?98GJ6SsDpnjpp=ZD=Dr__>cp~ht0yN+i?;*BY)ghsoyw5gL zi+o+3^CIPiPQ>#%GUa_m4y`lO9a1O0M1_an2Nv=^hg0jnS{>2u8KBH?G7`8`kD>>{ zckY&%;43BLF}i#C&9epG?TI2Ab+x%$MTHAlDkX~fHL)5ZU(|TmtdUNM5hsK{GOi+4E4a>cnlVG=)uR4@HtV1?~p~AR%^G`%KYh1qfx)a?>--mVn{EMm%MlOQTepK6-8r<(%V++JMnvK6w}7Mn_Th~N2EM$fN2w8rE%|eYH)@YJ8aK2+phxo- zUh7{qw7|=^#ak2_3_?T=28lt6eQ7kg23crowrC-1F&{IEX40YU6-=b2`Z8#K_oj;Z z4a@wEPsH4A7l3Wu+i8yX3Z_x63vMHBEb%=qxP~&lyj8Sx)bACHnlDKkW9d4i$N6>< z_-X^Z-@+FdaDDbmfSX{IVm@1}82e6Ix8|Z&C$VkBM{;^boRqVI;Ek4TQ{Z~>Ar(c51N~f|C-f1*4K@6Ou`LgMOjp&u7 zQlrp`QFDUys5;sMTW}}H;oDd`6@ueJ?~j_ZjmkHgXG{Qqu^p| zODHnZEAl^^>ARVRcdbL*0sp42s(T0j9zTs(RRW;MB zs*dw5x)fEzDPl%Z^{_FtSUDS_@A(6wz1Q~&b^kp9hPqb_FhZ@ZIt*D#Br&vCR9&nY zt3tg(Xf~3O@$#6iGc(ehq4(|9{d$m=ktsHmJDX6Qaq#cv62>p;&XykQo>{X8KFFR$+aLGr{QWgC!83>D~X zLZX;AO(!6>_C$fX7^zqraszEsd}nB++bE}m_grC&lytW?S7>mWH!Ae{^0Uz0oA%g9 zUpB_ZQmI-o|MaXe)OBFRTCkb`=(~;D{5;;K(P)EZA)(r1)Y8lE6OzSY0%F_lCR9L! zK*vWU9_s`vJ6VwOi`h0(wI#8_AN_>TaX=k`y0i!ysl%D^4#&khgw!$-9b zM$m;Zv9>(hq*u%e^8E=wS>R!!0`C-jW8X;zQ20XMQ7Q`VA=LP9h7_5W6Y&WZmiUen zVh<p@}Ip<%T9g z+?dFp7?ljf1y_6q@#n=t`qzj*>;6i_rxM~t*k3}zVad6MB5sI%xnUES!O&GipAvqN z5J?V$T0T-lpjD7)Rm>+1MXO#&U#b8~nRE9|>hO4CtizTwf>MyeLdkWF^2W^L7sPsX z7z)m?r;Hx?=4pa}fo3`I7tuK}B%xN!?~64On8t83x&QI2hmfOwFU_Ngo56IxEreTs z9Jk91+*rB*W*Bo`Zm^VH7kr=@P}C_VBNzrwiSHGHbQU5C3kqaCep-yu0HHNobYU36 z9Ef7462rYsEKUsApt8jnWp^_1&|VVvlA0Q4m4g^~EcfC;>H&6~fHelZ@EFXUB?k2t zBNJU8BxOondHE8vXM>3TAFf1LmtmAnF-l^dv!{%?v<%M2 zDY3lbW12Bl%$(Wn3zv&0%wxl9F-T#w$qgT4Y%vwq){wpxUC&}->oJAqE4FECY)GXd zCd|OlIXlc7lnQNixT|q%A{9b9_8~Jy;#&=LV2Q!-GRW*TvJ8~`R^nu8Sj=mLJuqzO z)}(8lml){A)$|`hBeJg` zFU+}_GYt37sM4E;_GK(2Qpbagv5dOwgV->-`*W{B9rWj@uhE6JcP*O3@YrRHNWzd~q+4nB7kCg=1Sd5H{(z)8KV+T< zw^2q3zjtWw%xEBiyFwBBm$oT1+E~R>8MhbJkQHfq#Z;*CaQS2HUbaJ|OKA7Oes4jiEUdo%V0v28s)?-~BgJZW&2 zIE%3vEfJ2Ejwnd6$X3jpCET@`ddY}2CwN2a`=g@8FNU;O{C#RM(QJYG@ZSVI4mb^f zUNM#%oHY;;H(W~9Y+imZ+7i2ZB5_wr%vl3hP^>-5YCYBc zJ52jfk5X}PNtP|UV?uM^p~)TWl_?Uq#ocjgT?z|TZe@~g%R1FMgA9X!6#k$bcxL?w z&X1o$EqeL69Y`*F6x8kI0p$2CdJ-RNi1zA+W@Y`c_xX=tB>8@soiFj-&>s92(Xi^r zl2lm<4PMNbBZKe61;$m1uXq|NehocT^6yZ=YPuBCWeP4{UivdCnuRpLC-NiPQIbN% zKY(NaJWH!TncsLhA0evjiQz_Gz|Jwq|Hx(EDBcMUUQAT6N zun&*!!Ge&wKf=YAMYSeUt*?n%?TOSFz@>0v)7$7RsvhSPK(k8zB#>miuIQX=lnLd0 zy@8kFWLH)A6Drv2(ew;}iN47n5cN=NOgS$yYuTe$@ehAMP`-~zVYxg&w_d&-maDe{ zg$w>cT;)I(kq6XU)o@Hr zG@n&h`+)=i9+bpddAe9p?`=AK0I0p9`le2rjrTCNa(*|eMb$1o8}|b|6?xqXCg^kETmV_(s^I=4iSdNpCdWfm>B8>ecsT0Y(2fz6>qXn?dga4(ox2s+l@F#ji(Be*;&#y%aZ7wq+@>^&+l&U>wm+1(2RG)C zc0MKUww=%59`x9EzD&=7<8W%UCq|&NEcpKz74CcvPwk1ja3#Fk6Q2^LAWGsMGv&7} zTh%PJ*S(Bqnt0=xiB+jDNsQn*)CEO+2&G~`u{kSpxUX}p8_DL`t@9l2j&%;L zWvcs4_3y6c>Z(@O67DbOOT^MqGH-h<1IX>`0DCg8Eo^fiQk)Q>`+Mczjsn~F&T6i1 zea2EvD8aobsmX1L2T&JVYg*X9$E-9otF~FqRjvF7kBWzpki`d(Um5Ox#v;(wdK`6g zUqdTNu{~qyY%OQ1J#bb@)XrPfTHXTI!pvS4IICXjJA_*Nqo1NRI+uON>9NarR0?M` zhp!iO394r*K$|~MZ9yQdBN`)+?l}V?3OV`26Hoks+8Y^YV&tu8OC(e*7!)`)kza|) zIpDYZGE&gh0uo~o1bd2>!{(TSA?8bJ)nj?M)kFW}OLTyxE_pEpLSf~c#tbUH2D9-Z zm1T###k?95D5S#W+TB^w#!Jjq@{A>XG4u2=NR|3rfNhqyhFFM}mRVsI)YkA-1d8)t zpekr1*AeMQxSC(2d3wO0YTaC#2uVq*t93}~1z1UZGDIESi!iyBl_vEC#TeL!sHL5_ z7!}^=&>~SanHNA@gi{Qn??k$??`Wma2_CzcID+*OB%6_abdfomY1-{)us+Ucw?}BP zW@522PsBxpABd(;#N$j#WEhE{rw5hNM5W#!bhD?&K_enx2I&!Mm+KIvd2r0-48iz)WIOZ)gn|Zqk8PejHnQ=z7g=(-+zJyRoMP zJOS>U#N$|b^48|oJ%57H(7NXkUE|WJ6yga|K!_(Cx4bsZZ{^O`4}MB6@s26DWD5Gi|+KU_@B*ltZo7LRvn*|HP z=#Qw4b;hLn+*{Y**`-d=?si($i&=i!+|0xuT&PT#dkNjr=3Yv-)VWgrBNipe)m+tL zllV`dgAZs^dTF_|mX`11Fa&;27x(G)7gn%q0#RioJ7{X!x3o5!`}DeQXfmqXOLgh; zRdt7&R|kAKSL92#Md1wsofl*|_0?I``R8BK##$8{@EPVq!i+V%A|{d&7z>QLtc%9P$~qw?J5B#Wd>o_ljr zf}~8GyOwV0bG=DcNg0Jq+>()LmDJH}ZUi`K2Q9itgpKxv0 zyh~Qq)z>Ovg(;)7g9#=KE34{VQT-&HvMVc%@xwbwV@E{^`I22(N;jvn(A6nh4(XmA zy{wmHb5XC>m834 z+!~$Y1mh272yibcy$V+AVCdq!lFF9atOs3=Tz(^*Dy-1XmO8}qit4KF0%Q$sZQB16 zOIekpyrRt$mDqfHaJ|#82+F{b2)G%g2=^K;0+ zK8<qngaKadbMcCHm!#AOy)`yDE*l-D$` zl-D*()`RlsWUbw)ebAeI&;U`hB=~q1>PY5o%Sw53GJXr4bjhSk4qfu;;-$;YbXgnx zLme8`chj{m1brJ-{}>(<>v#P%@jij_x{0R&6u*T|tvyrg&P3k&p1#nV7@TDQe`Qcv}Tz=x7z*D(g0)@|zx;V2=hWX48-tqSx`vcAx!wcE9B zyHT$G!vt!q14vDFW0n(nX&`k*S&6r}*w;KWE@OpAb-kiv25!@*5JXhXVax2OJ>7L7 zTkFuypI6*~FgDp0I}~)ykq}Q6_l-VDnz4y!Kzg_C6(rmR_H~Kw0$WX@KNY($ zVGRzcKXFL?eCHQc1|+QNQF8~t`AV{vU$YGhh{oqT0~GoDApg!@EP+ZgPiZOosHT@+ zi^VED2g#gfA^cY?$;YT7>M5hV{3IG`sgx1LdTfP7nRO*L@Mqz|dsLRB3Z4f5m;rR2 z9!<Nd>)x4q_dy^}v9NUx3Rc#p+!95Nv zfOq(#e7f<3?dJ-?H08dj7>+NKE|h{S-2h+=a@`4{IU(!^Js;rn>Z<6J8vz}dmizLk z)oi*@3cQ~umY0+Dq8VB{2AhVHqUkrI9YBbtOQ_WXx=;!ht7WjM;|p7Vb4cr(so^rZ zP|9!Pt)x>-oYO%ObgUAXn4${f!Fcu>U|zf#1l~hbb{%ndfYpf56FRjMpJ<`Pd3sJT z-{wB7o)x=op>HlP-$&e}T_Y(@?V6|phmSFx+GSv2Tm5;0rFLO_LIUn2_!K&Z(Sj?> z=#a{H&s8v@2`O6tRWa@RSphan$ks&z5MV7~A;6r>JGF#)vr2dx*cXcPbMlKAAI5E& z*MHtuk6uiJ*A&LyAk>;+%A(d(62>HkqsrCV#;oa4CCRO1O|O{&G0Ys#>QJC0hc`Y8 zK|Ib7#0#Fa^BZVUQQ~%5LNAcqHC;`nBz84J>Yz-jzsE*6U>1rUti&;=*sdmuvyWED z!qVd3OVe4SvzsW2eBZNVCwo*dk4LzZ>@=+pA1 zQBa-18v9E5O*y#P-q!{XfTY|mzw|e&tUZVHO8Ks(XM#0nSQM#hr`8Pv;jTiM3U{r^ z3D)Fj{q+3CO8IK}Z3k?Hi}BP&Pc8IBcEw$<(PIxi-jx~LoU{IgV2z{uX%loLSQ7zl zQSD#D27*Ii)6)>x^caV250?Yl(t%*jz`udBZ5Uj78UmLd<8W^p;DmU_)3KJR^CdBFn zXO9Zz$)eX{gZ&I^^1iK@BNNj!_7)Jy-rrOhZCn^#dV}_Ni+Wl#nS>_nFi=Ig_MuJt z$oA>!CkBA>GeB)iGcFzY9mTH)zgVA5h1SM})*-lw=izu6b&R}WW9e(BrJ%@*m)<~Q zG9J~BjU~0tSN~xhit9h3E2b+6zokxG$}@4P&cS76J}zs#xYXQ?%cixaMS26OZLUDI z%_~rC^S4oL^IfR6c>}6#-n=$u0M|kKt6MPqb(6IZGqsPglY0`ph>*rZC>3VF=hv@SVzJ`dJ7u{rej zWM!pk0}K96B5tR3R!)nu8p~0b^fwTLRv-&wLH^2oT-JDTsks@KO>0r`ZRBBmxNJZk z#uwa8G&79->(rgVZ3U+G?}yO9{Wc_zQxD$5{{0f>_gf6i&=}&YDCl6#&M!mh$mqC3&@aR zkYJ0{)0N%b(4<3mywG1-kFB&A`#P;z9GZFTWu#$?ob1j4J_EsO7See;F^!iBK(%&w;I1VuK(3P|J6URiT5hoci<%?68G*r)QPNo|{O0khiCt{}nbMZ~q_o zh|Y>mqO+6uJIE6cmCTl;HD_W6PfiX}_U9ey(dd<8m`^{5VNMZatTbUmi5k@x(1z0J zFP^t(FwZ#VRnz$=aCo*$W1%#;3rWx*T*3++723h*mJm($khrn2WL z7z1nLw*r1EQ%_QC!>5=8#7Iz3gRm~tG@dfp-+c6kQ>a#!Pu*FyE}Y#Ob<6C5Bf#xF zR4{2X&cLmzRrA{|_lzjvmr}qC>L)bW^YsLIcSwxzZW`fF{yJoY8T^q!D2H`1!tT95 zl?GJK7ZQdvB6G~UEOH=#(sKSg(3gB|N+xmD1a=6l$0FJX*RFam*E&(~-HV54-#l8} z*xQ3O>b^ToQpZzUnc9wAbuicJ5G~FY%&;g^dD0+C*8nB|`Cw6RvGC9HEB-G0q1|Pm zZ#n-5q4z~p{`BM^m4Ae@O9b&aeGk*$&bRgN=hU~vOhFQx)@UK~7@&K45xjF_eLr|-b4}ulbc0LR;X1-XeQIy^ezbMJx?v5QXVVbZ zRt&hsC3*rshSZdQ7<&9o+3hee_Zl2~R8Ge-tYK>(__kY&1n-qlFyD z^D-7+k6~kYI9;|>ouMIiDqbMeO~P>~DQyr#=zw2{DQK521=`(rVmae9)$d&1JHnaW zAI9l&kKbO|JHnn_I{*h5O-c6+qEcEni6$Wq4VN<3iXXdayYTXBucSfVIebTH5&Q~! zaAE{ymf(WvOwGW8n4#4=Ab`*eK509z!Ga`g7^IuY8?6n*8~k@@-fBq0IiRK?-{XB! z+wVcZpvPgnIg+NKJsd)3f-f(irp5w>Zc76KFH7ecU}|V ztp2gfNXy0aM|PQ096dND)TX&QUCjk^JdVvN8x!Yv?CWjp?QjA+3f?zzoXGhYIlb<8 zmFdIk8M%?oNgI>ght?$^=;mW(q_#i0XKX@p9XrR0GW5~Ja?iZC-E@?Hei#ApvEKl#Ra0@i>jVBx` z#uR{^|B#v*Lk9;Wlvl_NFagBb6jZCRUN>PTNYU;}Qr9EtIy+~rebXJx>)Zk_#D17l zq5h;*&AH4GB#WwUqh+eJ@jBd~$>z^d)6@liOL=(-zy5K+Jx4foxX*8#w%O)>ecfcJ z8-(wAaZ>*X;%3iP6hl2=1pF>=F!%;0$_P3?!tCJeqR_@hWrrSdmpM289m;5<&E3A? z1T~$5oTGS*Y&c>)_>4s#g?OQ9_t?X2G5f)=6JQeIeC3t>)gv3bd|*yaFtMST#Fv8;Pg({0y>@MZR+jknr*gc1qIZ79at$ zK((bb<6MfwvdOXJzVSF7De)2-zZ1*NDHeE!11z=wc$}pU)W^onZAcPJ&7ieQ?Y{d@ zlY{8ta*Xo}Er(VBGwd@vuc8(P<4~JP)FyCbD! z;-$Q%PGFOAsJqG{Nu?D8?=Belm6%1>F&3FqX|J{Fm39P7mzGv={us!!ALP)BB4j`G zxL@5oN`7!ZFmRui?`y%`r0T9_OePT+%+<@b zZ^OJn=5)g-|D~qJGs5bUSIG3zVSl6RVD{#;ZO3grTSSjI42thR+XHy9vQppm;r=jIL zXvreh{xNT`_UaWB>trtWo=k8(wNJ!)r$FgS5QM$1ow!!_bgk;l)uB~P!XT)nh&L^< zPjfZrHx~6=-GQjIgq!rLGhr){4?|dF2lWD-Y6`s#U*_yC#XK^5_97dr;w(GIP zr}q&nLT)3dI;Mq{okUPg-Nx}#p^?vQ1PupDp}Bu@y#@R@P}&{As1T?POR*opmzZp~ z$DuC4%2y!84dMVb2VnZLG^+F2STGb2cj46w3adn1xVnGAq%wcCrO`e{sLy9dg zLA4^z+4^=jnduljNt$y0Fgh@n*Z!!xMNMWc-H5A}=F~A=$N;N zFVr(7rTo$B#L)2&g;+R8$F6CdAv3#e!dq4khUJXeVziR>WWaLb2(OD8=YsUz1R=1l zge0Ps1B%>(l{Rcjh^r}f;SqmAiI-mi;OtdB5TQ3bFz?%XkYJ}*_2-7pC*f5J$MeMG zFa)yj%Pi%0!JalVY4rupQ1uqJjqZAYMtht*mE6HDf+XxgFgAe&C4wAl_Y&HY2t{z7OI+Vmkza0$SkM=Gu++ zIRf_$>w|jnAzsH=pAjsu)a8zZ-0TP= zyr@~;S7-m)JjvQYM@>hh0{8QxZHM~}^%VnOgo=kAv5EnY*+v5mCqk987C6f3rI?%e z-(CYLVr#3(Lk2{iMVXbCpj<&h>@3y=0!WT!hvpPHCPe$*njBF^*UcHJCYfE%cfY58 z1k)xL%t({QZxt4k1pr{${G#GIe~>XfHx&p{gS42B5MQDVw6Gz zyAgbcX_~}T3Q`!yYSUn~UC1x`ZcG;PvU`W@M94r=PC!1wIAvq)nP5^?vg zPh@Sn8u6Ayzrj5xKu}Kv5@y;$dv>oSIlRjK@w(L}tP3i5&V8i)U?R{d5ZU@|uY?p_u*iwa^K&3i2Jk`Z8lI@O%lGuR#s211RmybuB33#{(1}#dpnsE^6ioX4e*vj zDdKvqXXpHk0I2r*^VAZ-2QScl174vB&n)M)U{i=vdI4#C5Fh#pK18+oe$p|XfoCnc zsO{w+0&rzhE8@jKnHHO5TAFE#G;YC>7A|8oK0+A{t2$MYArkU#RqT1|=}nC)1YwgJ z7At6<0Dn2q1=riGZQ%qfd~U{QN~uP0X+9G}MtK73=k!h#tFkY$M)Xay*+Eu5HE?7z z$+?{1by3#pI-)O~iW#nJ$zez9&du56K;N@1&0UGM$ckdC}4ey>Kd@Io~2- zt9#Ryx=;=oQFZ+Sm9!Wt9fXSAL}fRt9TfDr#Egx(I2ZSk~iR0~t zW+f?_%#y=NnjD2JAct8}p<8usd?&t@D;CQ`x99~ny}+&)IP?OiUXZ32WatGG^@2>j zAWJWpx>7I5(F<}L3-a{(e9W|7zW`TQTrnAiIp9x;#e^_<{r*K%iWd%(DB>3z5>JMX zC}U5WUI;UMqF$KB+N!HsG7RjoQ|$-JZ3`Vza0S9wl@ZK>AnyWOI9;0?xoRHRaP(sx z*)Tq>j~$@fd|SAnoNxLK@JJ4Bu$Ow-q9u9?TeL_Y#b1J&EQd6D4|gU*L$Z1=R!;S< z1iY`^k)VqwbY+3l786P=3EZQ*1%q8%1L^wupWcKlhm@8e**yP_CAaUxTu-vMth9L{b@z?dFq~D zfc-!vEFMVR6|UE+`SLb2jLjYyq($~pCb2p=)FdV~Wi(m9J)@frHMLy*hBBg{$1-_n#K+pkJOk{*p$??zj16K2GXgXj=3^K0A)Yh zKrYUa{Pp!1eXqX3!6xBlAxt+z05UwXi~J+;N@6d10G*(NbPLoPRDhjtM+<$SL(9Ds z5euFH_d@47gcCaeX3|)j4`~rd~b0u{sZy)a!gRm0pg-D5!im*DA6@K+d7g}jLp$w(YbAY|nRc*(%d&L*j`a3<~eSK%2*Mep}wNZLNSCdh&7 zM6HbOYjOXuDqrfu&jEbW@tcI-Wc;S%cO`!EzJi$=&s1h;+=>qyal0~3XowU%s}r@w znfCBlTy0?|u9omfTr3?`y@%w6_)JVTE87-vdt( zcmXqehF4w0z@}U~AH|q`|&!5mu%-UWsos8ga0)Vug(of*Rik(dfc`h}h z?q16*^@8BM1eAiv5yQASO5uXM)yn00iZVWLgOZweuR0S2@HR=|sYsA16TTP;A`2ptX#}fP z9Ap(Z{kCv|-?~gMm>y>i$N=`S>zIF8rM$0jrWUzv^J=+)cDL@(=4+L2XpsWBf!q~Z zWWI8(7Fn?AA}z8|{$9PvDph5yjVIAHt%XOCH>r<-+^`Z0PpqOtSVeMx9!tCLz%{ozM-E&84B4wI z^{Ro!s`IdSt25`ZR``k_c^g`kud`O{-;qda^9;-g+Z*0dQjp4K`%xu4nzbJ0C>(*T zOk|Zsn#yO^ox2-*_H)bBRBD?D=Zo!G5`xF-&fTJns5@7n;6>dqm>uuy*`P%-+ZLn_ z6kJtS~H#0ffpV$7%dOsO)kB9Hijv`AU8BKIAb8YEQfh` zls~DxaQ1^xw981Et_Knq)n^q$h-<-HC8wkvS%CwX5KAWjF?1!64p=ZGFY$S zv1(e=(wTMr-&T@c&2{|?)kM8~Dr-q32W4358_)pkj*lZcOW@~iqMojKt>i6 zXac;9c#)TMtX?=9gTlLLX{D?H?@&ir0ol-=0seKgWMV(UIs(Vg=DlbQ41&U$Vw};M zsorA1Ka5(`rG@U;b-^dR?`d#CVW#%VRB+@?G_l&IsW^2-^JvX%{xfpxSJK$N4I#5o z9VZw7tQ)WKF6JIqQ~7L2vl;40P$YkzE}rgycv=jKtU=4As$E-|+1FM$bA9k$OVh}C zko5i8Z#`pKp_k{HiUc&RFsFw|W6aP$#5a22Hdp4D^I2+)Q+^?Tz!)iw=HbTfAkC>)Ka;dF6E2q>e9Mx$~gXlKdw7IxV!|LX;JhbRjId<` z;pIlQEtah$LW6~`1*5u-h39^@FiHLcN-v@Dh9`W!a38X5^6vZr;bJxyHM&#A!L>DJ zqb(3!pW64H_J-7VOzX_omuAxZ){bZ|oJwO4j|OjOC;E_&{UMj|A_(omR2ydNJ*{?t z0wh%jtpGS0)Ddt9PXeXGNfmr2RV8VVjK0Qen{w$qws3Y`ZjRzGc4KXpoG7gt)2<^+ zm8RI70gP7cPr%`6{2q|Z)V#m-36;Nqi2feT@=DqQXVc{(A*!7kx2dnQ!i-1oQd$Kz zKuGGz;ZZAbUx`FwQ(;D9GEF@7+{%hGS&JcTN7V1H!;tmjO!&6#d;+Y&R?I#HANvcWwW}M#v3RFRdVH!e?v; zp~r{<5-6g8pQYfD%0an;mw{lPt;Og~LhSlB5u(-0p}X*b6hlxJ;lmOIA~FU`a7{%q ze@H>0i2k6h>jaAR7|VL$1^U~y2o_m&KG&KjqCRlWdx-T?{765F>hMXj6~n?qULO`7 zlEyzk?muK@Gf*m1abj!xA8ro z*5e%90163Rw<%9js##%fpm`H?*=*M_EZT3&FW}9I1bRc->ra9o2$HJT%b&#C>sZ#H z(&ckJy~?Ge(}IN=aDerSI)-A)1Fhz}t8>+t!WWa38on@IuO`>9KuN5nqZ&4P#3AH$ zUAqUoJjDAlWO!-j@UZ)%<1vecJPK9aXm4!149{a4J6x`p4KNqBNDlt1l_(5BskL0VVIXq+*E%$3`CeZX> z%LAg8Vv8n+t?*O;`h0iQ8TI$ZlP9vm*he*EAC)9@aLn(4-r=R5OTpLJvf<0VFW44M z_TXSoL_Havnp`*>Xn1At%Hcc&F%@(eqvNe}_$SJGVQAne2jVlGAHF@#6(f+u#w(nM z$m7GB~^Aft}XwbtkjU90L;YJR=D9?r$F222%cjNS@ z$nl8lNT};#ZNCL3bMIyxY!~2D+a~8@=j*YfG`M(k=)}1C6OvT7IR)oH&M8=q5~VV9 zdwf(>+0~g+POZ1STueA|?7?aoc zJd8;m(*^J*s8~ zZQsDxBap;*a&Zk7H3S3nAvwLa4s4te3{V-wEhLDSH(vk?p{RjBH5UWjtDr!tCdUPV zG#wXU4cBWc`0t({Ldar@$p@o}4?w7Pn4kFI=!Jw(oYtSOV&SX5s*1#)z3MBWY#CnV ztjBIsFT&NLOvg1rNv}tU2!^xnq76ypEUrl>Cnhp6rp+5pucOT9hOpt)#Mu-bU?KEg zyv_)^@b8Ys%Ajwb2$rbtabi*jCkQ2&?CJ3RQ~YH*&$=}}Pv86&xt{aGmj;8q1Nb@} ze9drHJOy0J%^WYk0epd%)>v6qHCP%iYfell%2X2?>9tLKuWZS4L#X^!T|bHbOzC;z zmM`jh=CH2wp@05G*N2}S(lvcmf_R#}Ucql$V7MD-pMz~QdmWz+fSG|+%)fOtva0OC zqJF)oD_F#J^*9!va8fKpQE8*6A179RFd9CrgwDxT^OvTgew@12_0Pb!R2uKIgSvFa zm`$DW(P-7w(OA@9*S}b9cn)QC{ddR>zY>Y1azjug*2oPFNVxFDu4r9<4!$}8tLJsL z2_H4+<*(17^PMx;ua3!EMqxo`0C&=Sz%A+zU&vm^mlG`fNmOd;&})HLFM1=1ROZAP zG4^1=d+h`>qs?>Pf|i>_O@UF4@)2sej^$QG<*lvPYkx`7T1V(ry-lI%Ie8;Cz!DB= zJSRLE&$r}VXg*hj$Kbgj{`?IH(~hXSb;Fck6OEm^arY}$ye}VxM0}l(LWk%^Pyzc* z558)5)1U+GYP%dDiGhlL%^j>5oQJm()ht5%Vw_MLxL?m(P{kx?j`E=~M0^_KKSTJ^ z&mjyXZXSX}_?NC@b+zXu^^#!GasDKN`p8R#Et6DNOJ5(PPancxaSFGn+KOQtK;KK?|00D#(-=G14moP!{R?ny4 zBVwi*f|*_sg($(S5@piODSaxIk4)vG|9}`;WaRp+RmVmWJnPZ=PrPY3_#FjwN@9@1 zPyW6bng1bd0+k#G^-^8!r;?J;XV7*$(Y6Shi)j0V!3oD85kWMAsIGia21gs^cK11i zM?t06ZN^7Z6K`;zQ~ya>_aMu}d2anD&mb6W<4h3N)eO3BZC<2xS@Y$mJ!j$r%P=cB zvd`(0^i9|Xgu=71QJ&!+5uS$Fh9LFK%f0-4U<2bRjJKc%Gld7J8((lS40J=N!brnO zDq^XeI5B}9f!1^20J9e1hG%qjpeg0*#+RHyu1-*TYba12afEYn-c)5;u;>h5jgBEX z`;Ja%*1A5`nv=Wftd>ej1bW>Jj{tOHHk3<6V=|{e?@D~jP?6=`@DY3YbadfQ46iJ& z;IOQvrg5SapNoW$rJ|(p^>yc_DGQqRHyy?oTwDgL)?A1?gjdaI+#$4TM%4AMkOSnc zLc{gw4dO(u>z}4}hT%(^CI^;J)v`Q$7FDrlMFNwRf8&U$rU;Gp?q`h7OKlE^46Bg zZP(Qkx7S(UOgTiUx~M)nyq~If<_eJDn8jp0N_F)ivOB`N{!LgGz=CNSej0eRqkVI< z`!1rs$EjtKbwP%s$KgkG_?Mu*EKC;lAliQGS0a93%gt)Ov<|<``28He!}xuO-z1Q6 zI)1tMRpMt@$$0gHNc|+x1F4_h5GQqlaMM(^nslCn$M8o(sj@8;I&rZv7JOAr*wI61 zCQ9o&$tn-OGo%?B$YvSQQnN=9j_ZL1i|tJvO^TOKgpaMVGW=@;c6&Z-l}I%FQ{z#) z*=G3p1WbQ|IYq;ffd|kiwhk>ev3VN~!B;WyAi)z@mq)A|KMi| zh($2}u=p->lc-iMVYSoYAe^E_6E-Gl(X34q_}`bs&9_UDM9>2E&fT{rz;1$V9xU3! zSH4f5=l~qpHP~+Bz}5ry%*5V@^BgQiYB%Wd^GRz>(|>{boS z>(AJ(&=*PSKA8bW8O~rm1L4HFPqNiiYWqXc7A>^SC?X_)Ebw%y-)(A*SvRd(^P%vi zc!q!=>juwHhA+S~1cmwBiRj`Gw$~%zhbZumToKMA&~AWk^mM@_%YaEn0W(&=eFff| zp+XJzPWS?m=UhP;v{&_};IuoWF}t0&h@-H_-m;_EKK zMNLD7D(h8U?yBSK(os-$v}TmnVI#^-0uYpxBdqaHQS}hNCd(pOVZoikWQ{R~Hvj8F zUKT~Vmw|5)cuB+i0W2K!xy!CXPaZ%{RPErO%!13Ps)wBp=d;>g3KGwR_Y~6x)^YLX za^jRrvD~PkMI8YP5>X1h;jCQ=%1E?>e3I(IiTh}Eu(F=;sI#7d1SP5Oy)mcz-eqsq z)xIL#gw2L$kM^iIj0UgOW?_a0_aBHOWN!|Sb$a_lZ12jwT2H3<*x1KGPm~>ay9&`j zHM4^VnySe`G~-LcbD9>d@$uJ0aw^$+baVpWVBMxG#K%6vG9Zys@?ovgdF;@bDkt^R z``Lc}T-7_QpOV3Ty8dN9z0}X_FX(3?IfI~>a;vXUuh9xu+t||8tdhLD6Znd<_)`4Q zjpPs;^d=_ZZ7rPNDJek&W)!Z5hYlQckiuUs!8bU%Y$@$1T8dW(X26!WN<2+~5?0S1 z3jSh+SaQAaSz?c&S8>Fn;B!FufIp0OA6vnN1{x`@@K@mA0>uIN0$vfWJFSz4iV0VU=rR&f0?fP ze^FqHyMIMq2{bh~s=1~AE_o-%$eT)Z`1*8`kSld7e-;po7^(2?&lC8hUVCOJfzJ#j z@BmK8h7foa0e&-kkieV|;0XlI7o(k|)t-@*%V6BX;RLoKpHf9B|IwAA&gB%VjMxN& z&f5i@SAdM-g*Ivf;2+KgnME~&%nARJ%qL@H9wo>OSJg?^k(K&r5c<^^p%HLr=a&LY z1k8Sd?@+*D0rBt0-+!BiDK+H$aTYhIv;y#X!D_Y$FYmwuzM&*O5lIQ^>?`f?|0S*b5iYg|57U!I{apQta-Y+RnDFP}OX*ab-1Elx?hB@MU{ zpaMGpAu5VumkKh#_SQDZ!b0)LEBfnU6v&DQ74|k_IMeho!SB*{eS+6#JmD>Q;t9SS zw1@vqyLBxBmwZsBEA;uRSt~`8QT!8xgLq>@-VJNwBZy->fyohPz(z&aQgmnq79WMW z8FFM!wL_hTQoY)_Qm;;HtRAaZXCO2LF&&N7SqR=}0wdwCQWerp6%qxfdNAm{{2#S2 z)Y(#s=gdMOv^@-cOL#;S9Th^Aqxbz(1)h=~IJ-OQ=1fsHiV)x_ih>3(Y;ZznuY=dt zp5InD)#dWZgZhVacjfEp{?S*82+lIQyn->$=z<*^G6utkA5lc z?S+o9=%?F*M(7jLRBEy`7N+5Jan6)d>=FyCAxNY`I}bp`b!Vbl-90vZvX$X0?2_+i z7_#r?SMZIj4!UHaGk(Jj_{s%UQq4+F#4F{a+_#-7eT^y^HfE7SK%B^T(!6z$r}Yu| zWmCyG)Gk4c0(`b2(oNo7WQS2nhFaZbJ?6HHIk1eKi2L-0G%U~!vb?t)7KCEW#~%=A z4Ljw%ZRTSFgEa#;_(a!{rp2~~PJHPSc0Wx0>$LYT(poaI54oDNal(Ek*8}S)LL22N zb)bvZycvSs-621;3{y#80fBFb%HROhn(sqFa3%%{-o*P2i>#r(w@D8aMG$_g6KCLn z+S98=@@4Hq5IMLAal$b2`OJy*LIgb9Tx*84a#A}2WzmHY!LsA|t|R;c6i;q%^L%QV z{3hPCur^kGN&);uCnvX0emy1hTZ@{|^eTpsTa|%tka)US*>RMhYE!F%6P8BLd7O;W z;s2Frnd$z0U0YR;TW1iRf>ALzlJ;F>Gg|n?|VnsYWeF%uus_O?mvJ?u!ygV z5)~ZOebE^lAqXOM2_l^&B5^AI$9RKC(KwN?{*U8bhv7u})FjeLR>r@KNY^6>WkjBJ#T)PvSk3jsba`?mfxdpbN?BzbX zX}U?N_rX-4RNP&$2~2ecUovgy7V6{_y21ORfS;a;mqa3yPtlP}M;#8%lrj7!H1>+u z#M1b+A7EoPn%_AjYe2jYn+A`gaa@z>Isz9>27T4gky{Fk%$0!eyXJ5B21Vb^k!ljz zcM!$nI;+jGAida5(SuDMM9r3xti%4y)og7mfgMup?arpzJsA2Z5#JV~pzICjSzD+p z(R?T8o6p!_9kGdf5QU3wp{;J9vDHTK_tx+xN~d)RD&U=`qBQL-2|mEaqBC&8X9T@A z?P@7lV#5*O`Ho9F=$nimq6|AIyqMyIBMQ2pSA3uhud%Y$H@X&K{rU5kWrxTrgO@7= zX12B<4jHQi2O5jJ`12XWR#Hpv7NxAEnnqv)_h$Tx+)LJ36Rt z$gb~w1qthZYl|M-g%mttfye2778KsWDb=Y5PU5cbm<}UGfBrbq?!8o3Znz@}610DW z9I(-n$9oU=)A~O92WkJ0-LQ)rf;ni?_kp!dHoTmenHpkS%Bbbk@f4x z>dytJ0TVsVH#!XGxSH|V^B%%L)WrKeNPB~#s_y_g#=AwY5Urg?LncrJ=ryh*2vuE1fyFo;Uu7S2h;f(p5g_(xXueXIu#p*O^U1rOj(uPObU zv{U4=8ms@ZW%6!E;HRwxury`|eug{i*8@jUFZ4k|MbI|WAdi75y^ieqB|u?uCU}{s zhU478b~Fpx0uLj!0AnB$THC$+?cboLATD0&0Jq|Ar9AMzm_xRgYG9KzUr_%+@MVnp zTadN_U_(bVyHrRY`Naz`kM9+O#Uc<140a(FK|cn2R&Ee)%*2*}tX+cU<}&C`BAi=; z&(l=M-w&-z3JPNB&l7!vf~8>wBn7uo1$`SWWO#x{vP1f|KOr5qvp4h|ltL}MMvgBF zV-jg9p`07YT+#CO!B&8F7q8A~kME_qm4XZLm)xkD2vDW{m%gnFP*@+W@Q110`Sr?8 z?p}P0_VMRqO)!_D5&n`O)!im|z}DE8^^&zgRKl>W0fK`$r$+b#RJf8vFu)h;+xDOo z!r@VztjGB+8TuI=@2Aj24QqO#KQwGd|}feVPN zg388R3nm^WLc)I_-Zdl$=G|DPu&`z_u`;v8LNZpV9JmdNml-P+Q~etCm=~N4TNx|H zuRU=H&P=S1KjHQzf}<9_p%;Tg4d&^75MYS2so5ZB6RcsJJr7O6&?Qkoh+33Vtg0JG z^w6pj^7ad)Ekxbc_^Oh%YxWLdhp&>LUp?2uB&exVWAjWh+K`}M!DsKhOgt`h^M58m9|3@&67+K<_;(~I zWGG2cA^5EAL)FDO_s5W+Fhagag1#)&#+OS_Ql6iepofqflb|HU3<+w;)&IK^l;rTg zD?telwvBLPpOc^j=L;k#Wq*+bJ@+3-P`FJXL4_E9o{;!ACFqkciTRER(U=648-7Xf zgy_!>&|=a>S`OSiM2ae&xCE60jU)-l>iZna3=`S8Mu&!=Fzu>ia-fG=cXm@`?Y{x! z^os&(ylX(t5>q(ErFQr>lCe)h#{T-NWvtxr9e{|-+4UF3Wb9CTw!0K{u*V%THW(d3 zBn%teO~8ugk*GEGq z60xNT(p0*G&kzW0zmq28B+?{5U#6#RyYPfRN^n-+@l8w#^!@Wfl%CVK(R8`DJx(nf zFo5V2RyP%x#=bG_ zlo6*4!8VQk0>ojG?i4N9UP4hA`<-O$8wx5YSW8qGbG85`#V})kurSswjD6}euCu9Y z!`L6vZ|4h`5do8=+GmV?Vb};<+BbpT;Y#XRT9q*~fBYav(%4Oo?A~Bl@5xP}ZXHPw_@8kDo+u*>cuHWd2Mzce zzG{{c!aHc@P;-3;kw0eU5C;6F-NMWnfo=_=!;79s=)j04`M?B^{oXL*sl_lOo`53C ze=L9)Dkv(9_|Gv`Y4?vICX5d9VF)+;9FJt?QubF3wVNUmVW0~l8V0&RO5ba!7eZpF zfj(5dkO5<;7fQtq^s|EodKiP$@?IbVy;lzWiJoHCcFYRyrgK9W=rI0;dU>5N-$ph2 z*DK519b}*f4FkQC^@G z%{y`KI2#?v4XL0JI)Qa=c2Zzk=lDQabQrub(E?cK)P}-4*ftt76I3dMmobnII_g3) z46)7yHw1-@@baSP$U2X&dUA+26QlqwrbRERARNp&B@BUpxn97G+m^dPAmJ@_)E z#a@bp-%eBbrT8zq$=Ir5O&rw&#A@()>@a;EI}D!(+3NVd%W!`OzUTTw;3dQ$tn?jU z?C1D+2kICC@W?#!bF|10{FtV6M=!d<7T@r581jK|Gzo7qA&tPxJANzX4ui%cS?M$+ zCa>Ceic`{2VRee;8R%cc)x2^OXPy^OX`pSPJvC``5rhe>p(823Ytw2zvNY1BiRS z{J>iRPpV?NEU3aTX-8#nSxhzXi@Pj7H=6S9nP57jBe*OGeR5gMK_+P`D*P&p$>9D3 zTL_pY=oE@vzAulO4H4*s&2WKERe94hv97^B*ud@u6n7}*-Dn~2hG;2lh2RcKHynX? zL(GuAgBEuKMO+^RY^1>`Z|gxJQjfqk?-=6Uz_K=kXUw}{2+z-YH%#GqOgF?)ACW)^ zPk1+$eb&1X7oLO%BjHIJpS&BbLU;~$Y2ZUx0_Z$_2MJFY<|Og3McxS&YPdGYWBP@z z4SZDNm}RJoWX!Qb)3tF(aDouuf=UbBpTvacAWxXC4WgfEFgc$Vd<(&I1I~c2!tB|!4R5PgV*9h)2tg_k6;yJmqAnbGXNzn#-@=##8({? zSjX317jg0$fQxf7+!mi%iGw05Try}NQMX?>&|SY4&@j_L_A@5?08VVgA=x4rI;McY z`@62Q;Y`@?B=EJ*+3)M4p}!?s=}Tue*Ac2GrtkChild?T6Rn5v1)nzesR>6W!~aJ{ zv3&opY0l2EQ~pftgNs8SCRSn)&lCG(AJq4fjD-*&Qw4`@bx~A(P$04>-UB@UkD|Em zkTK&*BF?dCXMw-g8%&#&jhzK?x53=nx%H~u-Csj*c+nRd&aIap=*3ik&jOt0`P{m7 zBmC=@o2$)q(;$jVZulXJ*(pQSvuy&uQ$gD^#x~Ktf8Cw#}>nJqI% z=H2+2^WIrAN2Jp-bKd#yXU>CX%^Vr>y#KeEBbA%`TdAs{TO%_^CgA^i<`{Z?F>-F> zAV+aMgFblNtK})ondNZGGBwQn$anN_-v4CYtVGrbX^AFit>i3Maw-b{R!=nJ4V)>7 zNj=mOJwYqrYo?0X#3aln7=pX)=2Qp{MigDvooIf$bFE3|?ccmCuOI2x9Cp%|i?BTT z;zyL*9_!Z98c^V3XxEQS>z%-JZguroo`@%(7m`Q47cI6>ar zR}wZ+eq)_F6gnifS5^3wnqnH7)tXkqG{=uhY*&Xu__ARR)+i>?z^Rm1-dwHzeq1*- zZlAB!$6`K;=*vS4YwSfi07|ep{%OsB1)H^I|7Itu^6(jZ=yGF|Guo{1WUnrd-sFt@_9T~@a8*RSYR`}L6hzGO za=c1xPesWr73I;dL0Xepsv{HCH_3vYy?YQ$Is_+sz560FX71fE_mw626hwY3 z9)7mRCkHkgj$J~RZYqwt4Y4(_;-rH4#Wp ztq>{0Oyndk_v94?eK)-!z>w0Yo@S|>e55?O$*E(s*>vmtNXK1IDTcM#O+AbO`6W;Di@uQ>VNkGxddBF52V| zwvg-szE>b47lRR2_6p?b;E_8|9C>FV@QH`QAEj*eh?8I0E5?fN4INPvFfkhF@tq{A zE!>ISk@B<%G)mNYELSX?r%oQ_C#+QiMksjWlws2Lt9dfVzK;aCqR-hA>wOG z41#aOvLnBN9`58Lh~le8j=W26s|xy`--+)}95T8M@KIko@=mzE7lhUkAaXZi+WL}1 z44SA|n2L$#th~^uZHLNlR*fIZ_+bi;T5`bX1U*H}Iff(aeiQMvc&g31ow?>zQDkAt1CtclDk=zq*$DACu$x}PA!<1m#?Spp?8NG(@H~cydV^`%c4q`Smnm^#} z*py0ixv64X;RttOTZ!e9GyKI?8UT5F=(7hPHm=E7{Z_ zQjs+ge7vt@2i@MUxVKCt9BqXQzw-%df=pbjXvD<4i}iJ*%X^~}n2FvP#+UZu$c?V9 zXmKuKH#__@2g2{1VE6L&ZgCAvE?(|^H8d0lGKAP+4Jr--_{+P(%EplkWQbhQgF@M! zr`g>0b^O&4emnihiKZ1-t_V%%Yl4v$J~IK|jx(9t-wmJ14gM7xt&Cz|TehCV0b_d} zLB+RY7oSd}!3N`M0-&433I9s2nt*Gr>5{7pxT?WzzMyy>CQU_M;|ca`O|WA^u;a)P z(e*CEYo8k!#!B{I|N;)I4iFh z0$Hw1@^M>4+qM+r8Z`IuA`WA!jS2vQVGiIm_KHnoj`5?G83^R&QZn14rh^*&cw z=E=TAyzBcuEGoDZ@B9=$B>oTZ-$r3+{CD#|i~rO4|31%W@~iE4)dPGdx;jS*{9|~? z37jPz4cZaodSHFu{Rf$u{LYeJF>S`nzuNM?a1f$7H4ay50_D#(=AQ1APB|s8q;Z(GT30A z`<|pO7G!pKsB%kzr)e=msX@X-&>RHBp3}zz%ehm zC=O6EE+)vu3tTX_Z06HFCAsp1dq&%4{y3~Q1()do2EfJ<{7e3^xcN5b-B;o=@sEtt z!DK6$Pv_hE?%=aj{$HpgkEC(5VH^mRbh+Qvnh`BNl<;xK3v5ob`1=W$c5woW7Qc|Z z6&EYPIGvzRWR-xVfeDs>to&wnLUlVX1V%4@3KRDQrwPxy+7--dCKK(}5h z^_T!Y;xs0yjD9D8tQ9WMwzlAk$Y~P}&$aY=Ft#c~&hFxQ2{=a$T^02&z*FQBJ@4EU zBvX!cab>%9gvixS5jomHBCBth_tgPLz&KNbJY>7e=xOz|l#R9?ZWvx4a;-FaBHLZ9 zSq*2_g(it18S81NVfEFyt>7+T8q9M~(|wd-yoE4#Tf>=!q4MbUF}ToRsrRkmis<$B zR^S`f1+QuS8W!_I*9>n?Ywc+rZtWfIz#jgZ;b1}Q>z=1yBO=2e(>wYco~Kt_vB2~A zq0yceF0T0~^e1x$JNzeK%S(E)2;njPIaO-c&{{SM+(ChDLug8EPf4~cAIoXN&We)8 z;1;$(MR7HjobhheXT{>&@KB2GMo58!5Gia`scco_dlq7d!TA((4wUHKPK{m&;JNzq zD&|;K7H7Fy&-43@l=W+CB}z(mI3*><0%06Gv*UZC;r#@=EW1)kXrJTow3aw9NfK36Rlsq}P9nm}SDAb0`z(ar!l zNxT~NS@i^_1)$Z(CkEUM{w6$U2Bir?s+p$#?RK$q{>;;oE*XEUEDIKVy2hTeZ=ZxC zE54{M6(OnVPTc)ewk64ed_cm*cL>D^&TF-U?9U`vZ9NFRD>J|rKRCsI4EuAj(b4UW zL*f2dekaE7kJ;?@#vn}b2sy88IvJb?$;MlBs!(p6Cd}VOi(~SYybk#E(d5;~$*Yn0 zm6lgP@KzC*{g!!I#;xk%jD>d`(KIly10YdDygXUOdq02=zss zlP^U0VOuuBpDk|~&dJ`C&=Eu|o3o?4sqkpH(>Zu(Zuesi{0klit7&bQj^7LxL$9DS z5=;020g0crnYHbc@C5hJWl4be>u5|ONStgV>Kf7sVz~}V@E?-YVt6#DQ24}b#Nm0I z_gqJM^HX1$FVPzL!dCghb0NO)Uc<6BLPFX+%_8V#eLuUK+xzT75J!Nw7Cf&7#xltX z^5EOEA9|A4-k#v({GrOq$|DDfx-l*1iDFyqwL0h3gz4KVgWsS7L zoY3UDTS!{Bf=<+nH1yFS0^iznEJ<1;mUDo23)LsQg|O_~=agdP)+>@~z$5`G*H zsA$#axfJ@ma#rm)+yiJ%cPH=ZT zw1}rhQC)|U2u89-V$)p2^&sq}n;*$1i~zV=yx7VUtAq-{#T435SJz$4i6%B}8}FD` zbNzJjy7NRouOkP&}ahKk{~2U0i`N&IV; zn%v5%>5cfUrp!D^k=ngzJ&gCCHPm|2c$%MMEG5YgV9jgdB`5Og7m>5_3gEUn2j@aod^?jDzDztXr2$5KNRk)_nQ zigXklj3WeFAl4^LH#0?h(Fkn|-{SW4){Gn>Jf} zp?%BB;I)l~QLclRHx^0Wh&mEHg}ZTeJM6wzcxZUJa_k*s`gK ztaq7Nv9CC3<=9gsQZ=-z&jZy-1|EFqHwG5p&YD&=2?RMA@}J`?R5QMqIKU19d=O##@D{ZB zk@kVy_z~xQb@z0vo^_16$EGn#-CB`at*-h4ZkwW4e!iCq zkplBd3v+R#oPLZtzg`ZiUBB8&PQ>ffGBlm%r4OIviwFn@A69blmU*LK0M-wc`_XHgH$u3ij3r0Fb_H5e_Y9uB5CiY6Yg} z*5F{n@CBhOpmpc#F9ki(&)6FZFCYNauql{Y`7aCVlP`8ynG;L-y0bg&))MMTFah~^ zaG92LxcGej(h0%KF%-H`ny4G78~0Ntjc(k^ajlCvR`x;A#jcV9Z4_u(j+D9SY^vYNm?m#Y`1GLx8D zYAUQZvy*T{DPypT#1cZc_0SVe=DxIHqjGdP9PBh+&_iztB1PEXnqr6j3u zsK#-$bt<+okD8OK)g{a$D*roP)zsw2xa^cmX@I3#X)l+5>Kn;@T!xB|%{J1ijZxEG zuD(fz=nkimE?v{_SB+AD71)G52F`^3p)FrD(&_qJ^N+!mR0a^oS1S8mRESt;xvb*V z#LH8Cd?ntPt7Q|c^aoq?r^(cAT;z3>bPm@Gg-;=*?n*ogdAlTYw#|& z?TjEw8S9Z{wj!3y+-0@~er7G>JZTF~Qn z0%P%SC4gJ&is|!PZ=HUL=jqh&a zMU_lb7|Z9gu32t-Axk3agibb&W^+fh*lU9mi6_{#g+w(GBCk2kx6e9NoTQ-SsiH{A zf{Z;YVS0-0i;HJKsY6@c7-$uMJk1lq9@apM^ERnL~N@Ty!!f55iJ_%{Iw8t6z7 zftjd5@*(?Iq1z==)EV$q)uKts=~0)-3Iv;WM)>WIk^AjUiRjE`dN{NE3i<;s<)IPk zv@^Min6yL;w^K|XdE-)mIaV?2x}KH9_kq{iW@9o)uMJ7BJpmx?STwkdTjD(@%JUyX z$pJwg3(rnb5)Ez-S)_jw(csRLOgfaX6nNWN1wLCju0WB6{i6ameWJjZB$L%FI@-XY ze25dNt=d>5{Is}_#2G*1e3(9CyEFf&vDuYBl;3~k;E@AI_IpP?&Aa$k-Um81SjT7z z@!{C!qDvQ{n{fnkH+V-ko)>TeIg`0rh%_r+T}bN?n8kd2<_$jjNPZ&r=t{P$Tja?^KljB>wNl@R3Y=TSd|DPfo*)rZwGxCD z0lRV-1vFHj7UW!DOw*k2KEH9b^w$n&{`>i7=%|Czo!=q>F{eFEnnAA;UQ=S!z3Zfp zZZXnP$6_r@oX(LWz2N6#UeTW*i~W2jUa}NxGjeE9{u@X3=XW0I^{yKNz|~lH3dkkj z>EM4Ep?=``eW%SIN`UK3zj}(}pq0Iba%_<-{THJSxhbcC z>KBgEJV<8-VK>fD>zc^5*7jbvy9X)8BL1k-O)@xE{ssxpI3>L7Q4T!75UWo34?&9_ zm%LFYPwaUbpS|&IOw(d>JLKz+ofzpK3C@Ed%G9U!Z*hhZf~_XA50O zBi#h`WzvXrPu1$gnr%holaon1dp?g%TwXCb?v}*o%LXwfOfWgl6^UFWu@%UPDK4X6 z_VJW^c)Src!biu@xFPL+h&T+8oES26@XFAP?i8E4gLGCkccEyIaByAK#+khLTbwjNCA*0sT&b zeTPrY2XYSv@*SsEiqEmalrJJeIlBANdD|~iH`5RCZK)MKjMz>P-j!1(IE)$V!Pb(c z3ap4LT6R=*?PTc!VF|oCKs3t4;=|pVQxx%`P(EG`Fb?3?NTHSSS1sG2nQsDRlp_p$ z5`__)9YJA4+~RJXy^_?CdN&2t%lK2LtkBj^U@*@81P0^OPhc>L{*A7mz{zD?=;_BL(?Z7lE(ih(lRQBMVXo=bz3(y(B+bV;|igt&utd7QL*g}L)kQ}?R>S1 zX=Onq4s_YA^VzurT`9qIQ4KbjS-+NfU`~)nDT8krZ#C4Pv~BP-&4Cp+d`IK3h<#J! z)}q-0TqzQ==TqYIL_&>93@Vu?L-V#TRF~>cB1*BT&oP;RYIw^S)Kl4-E3OSd^MEfV z(?!pgJ?cCEmYgm9#vqniXU&)1fCrP9L;2JNQKvz|$#6oDlthjboGEwTolGMHTQWC+R=tNd#wX@0GMq9o*Y*456s~Ujz8*aY=oO0d zLVR+0h^ zF;D+PZuP0uUK+6z)DgSe>;hLXOMQpw8Yf=Ag9Ft%H?3FOHumC4UW|*$*LX?{6f}>K z|00Z{XzZ#*VC_=ByOjkN!1(+G(iAc9IS2Nx?j?%C*O)rUqck2_39zWe1B8^;%SiKa zuCb6OVI+E7{(k4E{N446{C(<>{Qd1q{H?wJJ45;>dP@K7>eWBZd-TsE?fU2Ezv1V> zZ#4JwWB8ne@a7^a7pJ-C(e(kI3F-a_fI~Wwn~zfk)+A5#1*uPQ5t}xj-3js0P;8o$ ztEjFvN&uVQv_cX_$D=iux*NLJ(hYFk5(nd_0B4NxY6x#fStyx>c+Nm7$5raK1&qCmLqIe z*IB!4D!Z&dV1Isw)7I_}q$r_m?6ZhF#_2Z_mNo?WZuh!h6rLz}aZz|^;l}r(#eWMA zP2Q49NHM~nHLl}}IaCRGK}E!+fD593`jtG2ETUDa zqtFtswe`XfKvuH5)Grc`_E?Xy#yB|o$sIV6|MHr_0k6-!ak1yWgi#93C^56u^YECE zqg=l#2*6@+In5t%#g^O;gBhFlZHvix-ON-tGsi4k&@nNf#?f3zC!(^6=Xk&x;T*q0 zvP9UF*tDfQK`cyv!M0KPx}^tT6$|8#T*29bGbg-fSKTf0aFzU#tAJhE6K{^o!&l^w zTm=YiL|^DUr{&=(`6E}bO23Q0vBW$g1gW>|f{fWw=dN5PfU$^WxRYL)sE<5hGMM$o ztX(;KDa9rn7!c9ZzCgXTbdq^1Z3qulhn57=>vH%^rFt0Kcr64B&f(d7{p=gbXPJJe zRJ;V_rUUf0L?B_ezYo+uu8i*c?DTay^GB3cyq|`k&0FvGG*{7YNreY|?S~d6LY`9{ zoz;A|)ZekwIx|7kjD7isn9xV|d0*37j0#vOr_pKNAYp8n=ITS~cp2C8nC~=YOpWGO z!z{L%`y71a98I5aL^?4WW$BTF`C8w3pI0Bi5_7W7eUJ`v$sf52%u>)M#+Y%SGbb|- zj01r)3B?@Ro(s_hC9KnwlZt5l9WFbGH0zP66eZ3YYDB0?KSf;}3(Y4{Xx=|m$0stI zxt~zgYoj>zE9MOCe2{MC+w&~RqrdJ8GDYr?KXL_s{D`iPRd>Rej8iF^X|ZXySlQ!( zOVp5(bF2K3tAJD0j>|sftn9kQ>(|9Dyp1yS;Q8xzO3oJfBUgb`b@Bf_`WX+waKHMpkoy1iFv&53Vfukpcw(5;f<)o;>DjFU!<8-bjQx`EG%II~UG z0|v*v@x%1Yz2Udt40l|xJhBKa6&{@f$+N7SMMD?+pBD;1psiq5_*&e`Vpmx!Fno~> z8DQh6lovX&UQRcGthxd@GJcyCDZ(+r&Gi@YbvZHy9P1;Y6W%31;$R!Bc}UK;hI2Qo z>_#i7TIQoD0`=qA;@xU5j*NtCjs+bt-^oPcaC3(vCbowqlZ?~<)d@ykg z<*du8^Q8I=RpH2^c1u0PjA4yb@Pk_z5TD3AJH99%k|Ql+x7lf=@$3fHgXZF|#Fjwx ziXcxTrXlv*VMQ$wb(83ANhCE)N2!c{ERE3I!~sZrUl>vKGM`CGMDLO>bp;mGZIv2) zC0T<5m}giuSR$SBkaSRV*4H`yL_)84KL~zCBXVq}g_!{0XHL*59OpYb` zCPE<{SX`Lk6I!-&5*ZQj$vy=ij*|i=5dD1R1piN!tJ!=;CJjtwh;!%Z@oWhrJ=-XC z@08%HGS*WnR5tCwDg#9mpwI4@Sk)4jIZitno_UU?DWNn@(Igo3xn!RS3c7Pw^6)I` zlj`VK+{W~sMyF1`a-g$4xZEhj$0=`!SaP?!(DZD-q8eoQwVa7+%GJZU`n>NQ3Qi1U zt?8eT#vWr%G17Kg5nj^*AFt`3lQvEVAwm_ln+bmPHYBLVyxgyL&`{AW&0)~VH&NQ- zS7+d`%2k2rALXT}$mQV64$j6b#53NxQXuLdR7B*JzPM0drExWrIjCO7M6agp1v2!{ zLA-)aKaz$CKvF3ZK2;j^wXqZyuoP;;^?!vQ|4;f7z1}JD>X0**-^h<%@5H#&H_~RK z#oqpHDF&*rN0G}vG=$Kr#@oN0C+Kn5K57uq7%n-itOyT}2Cr+qWwvvm(;mEPpwkta zSP`4{Bfi84&c#LUU>F6-uvU=xMjY8uAu5O-m*=#unC)y?KA)miTIxOTXy~U&Nh@px z2hy?Z{RNK2I&XM;4o-#q9Sx>6te)Rs-edH1m&|VzHwU6#+Jou*37j_50v}>*IIxCx zH&7c3Zafn`-2@m1sh_A@sUvaE+d;k-i$*E0$h<@%^UUMYWu7k&Fqx)nW14D^KErUf z^%P~vqm|(p@sO*zqS_*ve?XRMcR8GAy1Hm7<0=up{(_ZLrP^={w~Vq!Tl%P(Wcrnz zmx<+tn3jXCI!NZO)^&fOfQ3>3%Zms@#@D6S`1qu9^>!um@yBux84!XhfX5sEpk=a(^i7 zsL(}DdY{%#T*NoVYbW-}R}#cP!U?*hmsK)NAiHnH%oUeXJS}nFd69yU{pp6)m5!oa(YoO>h_7#pF&yYM|=S=Vm$yej;4)#{7 zAIdco>QOztLr+_LE2}~cO7ofPf6;UOwF1MfCu{eL$@AqD<@T$uQ!i2K%Ct)^O{f-g zVw(CsFXN})*WTClhpZK4?SvG#>yFBp-n|;8HAc5au4Q}L%UJ{)kP$)jR|qlrHUe2D zh$phu71=r~QV`kd43}ml_ZOL7=#-?CE()Ot2{RWTFlqtj71p6HV%q4xaxK~QO}74< zqyNs57wzu*5-{Z$2b?E6kf_OJI|}!>!(AUoXMLYZZ!R~krtP;_L=VChy3DT{YUzfk z-~DT$G6uL66ZiLfp2)z4YTXFbZQu~eX8P3^C7CenABCQiPv$0cl~RjExY`szBe&62 zXqD2{Aufz`>$GrK*E<~)_aC6U6&?VuH(p=;tbCC;r~MOf;TT2`Qe*xy!TI|cg&cJb z#l%OULNo(dfoat5B6sD^{A1Ma`lc>V(@pH;)FK|+l_$;G^vrrfICHEBUBO9#tQz`> zZ}sWJmt0B@O0LJ+*;zuG*?JE1B#5cYC?%*S;}YAP14Z|%x8NPwdltdNLCI;Dq$zia z3#IJp=rlb|kIIlz+@oos4Z^rRE_sB*xLWRZS$CtsODGmSY*e_>AwQ~Wb+3MP;<_5W z;&C4)LTHGS9m8fU+bzAkmMu?@#Jaw_ zpsV^4*QOAMd@M8`fBf->M3*WY4kpHSEQqk?877SQ6-ze;=PccVCU!%Aa^(IKseIoF z#;7OF&IW5vf${7q5vwqpnc0&zLEe-&X^O3KrI;vPd5kD{wku;#*ezqFH+X|#5FR-@ zYJ=5bmFsDGnnz(ZF}PH=mn*_5Cpa&xGEloHr>FT23Pj63D?BO7yu5Kz18JYI_sNkL z89ndJt=Gp`A_cw403UV8T16q`9K zkj~pu{nnj)dyeF_+oJB-ro9-y6$ZMgz0Xh0)z|)>9OGa8Ef!n50bNg$$cInO@}tr~ zX#qj}waoSYXgx+nk38~7L;VoMBUoM6K%a16#|##=0c)gOy@x~wK@^L>P^`I9eH z9Rc)dnV-IFs3P;2h#jTSJ^n%*vstHQP{ff)aTa$%&6Aa2MjQ4=i^Mx^U01lbC?Ziw zteMTL=k(IBH+Nd^Cw89w+OR)nYZs1HGH2QvSo!0!``jEXtalWJ!SZf<;|)$>aT6c- zM=5T1qUIAdtYrWsWrQw7K}CKe1N(?jPWbInV8yU{$S`hnhTk3u?{!9QBr?T#miZGk zD>}Po(&ooBX^7X{dDi=NeYYl-w2Y5RMLCNo(hXw54ep%-9ciK2>Y-CIvepsIog|z> zeqUuyiU?cN9Eqcyse(H31-vj1$6xV$zLdR1COu^fS!rtLW$>34VI|(&s3v7|7)^I& zAZ4wlYY;GZU~ue3_%=C<=&xBcIv*nBW~2G?1}Y8M!6a@g)$P_@XkxV*xr;9{eIVv; z^|#x&K_!KIyQ@;2PYvbt6`CwxN$dtR%5qWra+cZ%`L%AP$?#tP z##H^q(!rzWwvV30&4f>7S%c+ZPy`Bx@MPFY>3xb3adG^0c}tza)xzDBtBO@LvcE=b z6_x^_tXr&VhrGUigh>EKVDLbAg4Qk_k<0S5mWjTu zPj7aX8cY}#qnD$Oo7Vd|h*aM-R1hIDgVhDbE$KO0J181bcY`-0l-{r^eZCWo<{jzt zKZ-i1q9@_#YJ31tSXl6yj4tu+Iu~3^Zi*VtWCka;OfNwn+9%rtb=!1Nt1If)9(x&L zfMiEiIxJVCz4IK-jFvRxeeHTD_AmsXR^`&GG1NDwV$*_FEAI@~bDG%z9g0_TU`6`; z(%{9dRR92?iaObFCL`o*nQl(*PRooZX}Kl+Qt?0UH!s8FH6xS(ntWP!T1JU^KKA%% ztAs1KDnkY?OA?4-Yi5ajLiecW-U}hJ=FB+b+Pb1}{-Z@9mpi3}E0eV6mgIdPBzLTz zQAPjvo!jH<=X*A*k55=yXb<|_+QR%#c5|ifX5z<5H&?Tcdwl9#-P^!9h(VO+nXFnb zcn(bj3V}waaC0&^sWvh_+>J}ckhb0T`c7?H=y?XVq1Id0ACNweI(_Vt1icut9)b>| zBg8s7`kv!?d<>44i~Y$6V{jrd2G$WdTz{Oya#SkviLofF#a0JjMx-ZHg$WtR_$;+C zuR#BR=Tm%80vUQ(thrX(@mCkOdGU9j<$3|STSm-_p0c*kH-c*KgOE5*(J1pGJ#3>g zY&)Ry3|l-^aDw#>5+#Q3l;_@KkXbYL9}nMzz`0T>GUR;_erNRTVZ^|fU6BRC5B?b< z9u)sp@s(IaU&|0zxvV3aUOQDI@k1ls-moqG5{wOvjy_>iqRw;t(Ys@Dg@zF~9*>;z+!HZH3hmG=Qcd_Slhb$uTrfP4B{+KV}F4t@ty5{i}I{aN^G z==NNpId5VsKf2e*)*oniJEe8SjD_<)&ghLgXSS@Gv2eUK6>2*0eX z((??i-{*qIFq9cOCt8!@ePh!UJ**DigwnYTKzlsTw6jM!_A_SD^(icheH$^q(Tgok z!!b9tPM8g=CeKeQFARxMN=k^|#)xWL0g%PBlZEualyPT^PcYwfgszo&OGOlx_H zU+XaL2|vcQ@n*+IN$~(0ZNs_Ck`UPE12T6XDdLgnH&0W)KWPiE|`H&)#L_a}X9Q!UrYIoH|&=8OG$b@(Ichk5ZVmnXCI?ck7r6s%U4PD7BQfzA|9^SfMxvGWNYHf||k|4|fnNlR7C?|J@ZAgTUp4}M1e zOu`s~t&07rubpl&ItJx*JWH*o=sAm2Ao&IL!#{H9IV7vKo|uU7OmQRPzNTc};2z9r z5BDKb@%C;^#p1IJL)tUwX3-?~t5(WGSs3Pr5df_QDdtS&)L#*0f_jIq^a#(1*FE2| z+`KB)+qwq?+bBLKBP%?)tk=jbo_Sc12;tPL1=9k|jH-?gtZ>XPWlTIxFG$S@=f1*m zDfde=JWW66iFDN?)|-_rDYyU(-N1%rqZ{U;G-rxy;YYD6h#?%Qbx%8$ubsLWz40F+3^D8)9fjZcz#OS(7nRGAfr+Z-Og-8 z^zs!cg}`Fg2O757=iBPni9{U(li0K;t(|=pElCO82pAIw6-3^L6|Ya}6m2?1Xm*0` zRAHni%gC?ZlPjZVeViRW$#jb@U1?s@?K{E9#Y;+-6Xzj5ORB=MlUr_f)B|$EtQf0V z3N?F7DiWM=xKE7w;LJ}|s=qUZISm;@=KY7?ZKywCCd6!vhRxFVT&o!I|=9SSS z%l1$~qzdw-S>1sZS@Z3|ZPn^7tv(Tn=27EK5ST2%=*jq~X(ELv6e8tLeop;e>X^%s zHE9S@t&qaX9wK(uM~ycqC_$`*Suu{7mr;LX-Ekvyv|9Z_D@xQ)tYXwJ`HgqjU*DwU z12I-fw|a$cvS^mzx@e)zmBoDIAV-g$&}8+sWH!X&ubE|3CR#Sc@Co5WC}}awAx~od zOe1}bc|?!>$lOjGYJ24RK=>UkqZ~-?Aa`6b|Ko9ybCZpftug>tK{Mlrm9t(|#KymB zJas<}A2Y&{vr4Zxpr5#|(tlTffpFfDs&7ZicE?8~5_-~Dk(Pt`q61T_~Sb4J!`Uiob zLitm66vFdwKa>J|hrm@xxh&3?6oDHDV3qHXx5x91i7C84(!6*36eILNt8;qGifN~b z{jv=4x_RG9y zw*8gdWQ*+DM!!aU_eZ00fjVbhL%9AWX9bKa6+u7eyWhNyFq@v|TZCyUj+7np9`tF? z-77s%_GIfV_JsqT&fxj2E9{pw{PCj}-zn+pzmY1C(!xto;hERVvp=c+Idt>WWq$&* zqqKg3;9mG%^7y<3;3XbbsZh3+ zkTukkZH#$2{Ar8&#u6zcHxA{OA}OO~KLBVKaRS_~6iS&Io{)b|5@1bgM|{NE#Cxc&!r&%HufV!of1P=vRh zHbtf6vZg+fqoORl$Os*0L>)&QhZB6KGynRQ6&aT?^2|E#TiZ@BPaT5|^}RUAJZe^w z>AggzPiE2S|7;#Gs&>mDtou`(*_K%nzie1#U+63`cUucR;`>p-x?a>$zTd>H>);ck zp&yA2%uxRC5P+eaQco^mA|@>K1@vT0xGEf~FAJDpxZ9yk*Lj|qU8(+z13*o!w<|P1 zjI1>LQATK5AaiXc_H^;*SuwQONTz#Iy!9g+_k;bVO?V<{pEz5@3E3;3wf4v=V^qiw z{!)-1%g3o<+ak83rD_PLH=}4(xb0E8S9Ivf*O%CW=gH|T{v;M$l#|>~<7m6%$XA;i zafo_54~?C;V`z&&k*stWRoUUUuj?2}yK8TOu!QmD2aEoZvBH(ZcIh}AX&y3V(LEmd z&S@?lf84uo(Lh! zrK31~{Ntv|%kfQ>57X59{$W!+XEilPntBe8J~fV6W8>&gY~1XZ#;7%p*^y@XjAI|f zGinXv^UF1$l}_Wgb*SqmnhR<1k2b9Z0LJqvPNrAvdUMaxv^A84O`X{xSY8p^u`cc#_uz zmC|GH=qisrB~?sLii;e(B#EK35~*^((UXVKXNlAMTdA$*-Vzcg`z%e{w^`HU*nDex zh%JqO(p zi(fkaYT_H}c`o_v|J$K1A|L2d_gZ;XbgZ}+e@}6}G4-n}5)6_^p0pziG>f3Bnw(Y3 zu|c*m#0a^{8!x6r7c-p(s_j-Weg7$24_aqb&hf(?j`!JG4UP{)>#f&Z(g4x`9u3$z zTSu@SIhi`KNeDdy8jn*p>xl^a(T`u$Bk}FBSdJ zH2#FX5HFRyC;7D5Id=a70vz*~WA}gIv*r(tRarUF`lA#CaSPZUe_Tv{NK}cjhP7iN z!?s8`=0I$@^(Wam;??mf`t(+Wi%jQB1F7r1-LUIbA#upr**DbG9C|b$t>v;8T$U(|=`V;^mYG$ldgLKb0xyVjmZi^$u67&txX$(FwtG`V_h{GN)(h)I zBcsmnNNbT>sSrNkBF~=^T@3=5E3(=dnS^l&a_n6ITXicnNWNpHiwCimi4Rrbz&5Lx;)?% z_Iuhhdd@Tm0t@!7{o#kiv-RWTPCl0Jqg&(oT$1k(Pyb)?EfYUm8)|Cir%MToDDHmx zqp>C8Vy8}iK^GBkTKMb?I}#b>Yw--fIy=LuS<$kSB3V?oQ8o74#*a|!**2Al$Q$(t z*V;I3UPFC9tfw*>zRk!I^dv`knUe`#rlap&9!r{d9JS=DKC#s_H zFEhHLWvXLHycH`18(x*gr%rGx=WTGNf$vWt-Z*(`%<1aFm)Y<4S`x?nb{u$$LDizn zp=i}mi|-7@f&_B6E8w_U5JKdz9NR4%inKzV>lbEp9usD2fv;ai=wxDqy3A_?rf9mZ z`P0C=<&C{GXM3Km8p0=LxZ{tmiH9V~S$R9hRsr7=Boa`4p3=jifmf2JF?XGGsl0B{ z=d=VcR${c+pXKENJz7SuISJh%NQdE}bGA6b9l1tFyd>e$!lNg)EJEU=jn*f0C5+a? zUdD-akI{P41pV8VEJKXe-#H{yK%_%sM(ZM{ggPUJ%0gv|3?(HpIsTyvX-pP4<9nnd zMFqQ$xT{0J_jOrf**1yGhU;u0 zfh7~#;pQF?wTP=v4h~|#ElaMwhWY6`-MG~yr^V2mIw!=V65)qSeXpFdEc0tmL=@zG z5A!F%qk{hk+(0mmpvSe~3JjEJk+rN|o|LOsDlD3XePQTycsrBx67PEFwu|%I3wYDj{igXB{+d~scxN%X#4iEw^H8wlV{6wDo0m(&eOZ<}WZkIxs z!yJ@Mlhm4nG8!U0N2u^AqS3wH%nDy9jkAR>bjc5vNMln?cegbx>L+?SC64`|Tv?qP znpRk!wHduPy%|iIQvfuNXiN9Jk z!%tz?R_d~j=%EGLz-y@7^NcUMygCvZQ4^4`$hr9#)5ihA;P&g(J(OcCGOsGsD=@Sk zl)3C@W0YG9u1X;Q5mO37S(`zxLhi0EU#KURS|QcAbbVw|L;Y#J%v55DqRZMKvyF`D zlJVA-biQ`9$HCmNnTI%XP!GZN$%^{2tAQ%JJfG}M?Ef}9_quF=#DQjm$iUex;-xamKkU0p3jc2mxoR-7Tc=u zQ0lg?vPO{;VU_zw0N2*!bq>BEp-#{$q!_P7-B%jj-uHqTVkMATKYp#9Sp#-;uJ>SwbG_TqZKgF8Qa~|qSp#_o zUL4xe_f4`x$hK`9`@9D`*#F_@LsizN`#sfr9YcJ1x+lwC>j`$$dJ-Sc;^Tk)2Ome@ zQROoB$(v5W8Xi}%eH)CV1MOH3dG6Ov_+_qv4tsEp$e-SeW*2+k4^Co}C=|QUjuh{{ z(CNGbeE~+;IDB?TlHu@Qy`A*tA(|RpT7ierV9=e+c~Ej59+ocE;v^hom#)t144*jR z=#XxWx=T#Yiywy4ll|J0ON?vjS6+FCt!kuG4bIHNq0`1eDNedrBo%bA=l&9wBF z*zojZQCAtBf6|7&Uoc-20~K8i3i(;xeSl8ecX-$uFR`YVBg!Lanjs+=#iyWp7-yQw z`M+DQ8`>oabQ0&MK$06uO+lp#isgd&tu`EN=C|^a}N3 z_L~G=pmNdQx|HMxo|S^+18wqwk$H)V)+9cFqJ)Vh7=a%%hic9)YRdS!ekoDZRw?R< zWKok6MTt-X(+#^5%Z$QI!b zxu^-G_7s&$tGTI-lzu_~v~1)fSkrP7{=q6z!p6WT#Q_O1&KFDvv9iTDe>DTE--`Jy zI2{7dFoYHVDbh;<+2$m%I!C5qLbRkE*2G&!VaKJJkHu{3@Rprp2t{nx26SJl9L%Ut zQ%N8-j@`XfrCZmryBDdEUaRx(Uaa0rTo$Nz5|{JUvBc#9btrLJq+U#1u29d#FL&QY zOV!V~gI61CQYwuR(+;cE@x}=Dpfpz4N7_viycV$1NSGdjtokNNlI_);)Am(143IXj zQg2>P=a;Oi@oJ=sVD>WMq=C!d>PAUkuHIkBlwtlvN>;6B2jR)*<%!UG%-yXm#OQy> zMJBQ1oP~!3e2zhk5*+EU-`I*P|3_v}Cjfs+74epG`s(hWft-oH&?Biiz{El`fSigg zk&@K8q^eXu=Ut82ULAj!sq-hTykc83k#egxW2)+ zX2#}z1SqSZYjvq#KMw+eu8vZ8SB<%R&8^w+J2&2txm0* zyr9j7&e(f+$JA|3@9?HfHk1jR(Nj@Hn^|)YfursW zq?jKB9Ok>@EaStc;4a}hXEn#}NihVNNY2N-_${`isY$D$O)DoB`m(lUtIzKd#tKMA z^&qE~zIKlDBHg{oiO6>BcT-`+uz!LhZNd}M5yCai!9om%Mowl%queSPf zvHn_Y$M`8mKLa4p_%0k9woEs=uW#Le{Xc7JrX+2s&=+^n3xk|t>f5iFE<=>JB>=`+`|ZV8d2tZY@QePsz-K8hMHPO2X-gnp~B4$ z2XVDpHVA*w^se*a?2>U7VPiMO9G3C zTent#&1(?^4VQ#cTXIUxcNr$H?|5)(!*C(IZQ03&j%&;maL!$(W3)(AD^siKA}pOh zKS!@_(c++IJ1%CdsiJv3-Rg@yvAF$2s(yZ=1U#H9UOB##tCH-a+E6@x;zWB$veLE0amj zm!ugRXOJ|5q-7*syHgTcsTw*KwRl=q+5wEOe}(7^A`|FM99DYtQ6;|p6W%2>3mFsm zRViLy&PJT)a+uh_DV@fsz*UV|C>%xAO880uO!njymSxG3MqnAPKfMrTU>=s?NP)l4 zh2)XbT}A$0>t#p$mE)kJqg<7j$bkoVn_y~px>kYDCkL7h%XwH%N7Yu?nmxJWv@q=P zC|2sT7(^$rR_NMr`-DQDd&>;zNZ9MDT&4#2_!k;w zv#3psin4UWg;I49o{JUkAfrS=(ZTy>86SiT7Gmz`SQy=8=bO`7OYC~yo*uVUIHz}p z`|XY%M?ah)mBARbE3ez(bJy*}44rxQO-tOi7CO5*x;mx6mmOpU`i!bs#&SG67X>dj zZgygsb5Gjf8{H-Lg@HRZcwgJ*GCIFI7_*h61Tx0oI&6MtxIQN(l-*FcDC7w^z`ew+ z@GsVRFn&4*<>Lohq{mVE130b(M8ezF{sj>Snhhv;p;*!S(~L3h5DWl>aokAXRhQ6@XO@f=z)Hn?dvb2{GO*5LBFEPs4hbIu-C21%F|%#d12 z8NRA)u$aWw;YKG`Isn~gdk=)<^VjIX>Zt8;7A&%HXS~Juq%Vwaup7&r&Fwp;0hh@@ zR;$Z29qo23VknCoM=@;{Bu)Kls*q+MGLfut!|1r4V?PjR5TFYOkIFYgsM6}iUD3+* z2bf%cU{R%7aGsEjS<=<8D+K{5C!!NX<W6HnGuKLQ5n_Dc2d%mY3m<|gsy)>^aP?t+Ct0zreuHKBBzj*Jm0%OZjRf%E{b zkgaK2z};=PtwC!f3dP4JF>LVbs486D_Jzea@~*9%1wh!d+xUt22q@Oxc8k6gXW_P6 zx%5|ip03Y%evN+mN_Y?r|4|2a3W~h|k`oENByrqACqPi3g7}@C`~pd%PH&Iz)KLuUd7(DKwi4Q;%h40#CGibiPilg{0XEsww1V;y>tgS(lbBmo z*_do!1SQ0?zIr?yt*o=Cb2_?_uU!%^CLw;T5Tb;XFf?5)_zh%8V@TggnP5l@Ft{MF zZ$25W&$b2MWbN8EABE6{M~j0~!=t|7r0{4-a6-3l1SG$e1iSE!V3I#Cd;$bOEdvV` zR;oXs$`PL7vi!Y;H#v8>w>b+ZZc6L+4cSdcOBqJ>IGt&rNbKKu8_rduCPm?|1SVjLW~HZukeO zrohgdmwzJbE;L6h5A)oAkl|aXIAMv_#@BwPR;9Ox_u30H-5e00A8}J9RfOxJQMwA0 zQ<0CCt9$Vq#Za~ekHm2kbl%tmWszcS4EWdyRl?8`ZF?-+RTJ+(dp)QCe~@w6DTC z!1175?LS`@<}64&GW%0P6iy^bFtJmf@tvNFD^2|=Eh{{c*nX|0^QDQ_(oqov|K;j- z{%Q~1>KAh8l>7md!QymSt<-Pz5h5p+S_eBF?#>DKLz$Ez;%*vTBibXY zBk%ILa#E!fEV)*2(vleqX=HC$^8%_c$Nc6TTfKiUK8H0kK{02m2c z1aH1vT^)$|5n>Z_WEp}TONc$)ItG_3e;W%)eVxCC&0Nf?^{#Ypc9#1-JaOnI{uGD$G zJ2Y9>*{Q$eX>ODiTH+gZW2*fCyuT?Lqbqw2x6vf_+M z(m*j}t*oq2tx|+&L~zYEr$(!e-V9GOpM9Fsx2!r~OFYf`bb?B$+Zlne$1gebh=KB% zsH7eE1?TkuGsj*r)Nv*S0N3S$;Cg_A#ms@hSLgP_V@X_H^i*sy{RxcmvVL~`A;;@% zXv_Hw!4Chx35CM)kBLfYwz%K{qPy80oI`hizP+t`Ca zuN*$s8n5QPCak)RDuGWSNN@eX#o@R$oLAM)J=9TTUT6aIIvlK+3UwFOO!NTF3Q{S9 z%ou6AX^YcQhE)teYxpP~5B*F;J$Mf-GCrtO3+aDkKgW&N@;dpP1zcNLb)3+uhvyP| zQsGYfUhHa>O1kR-Bd_tk36v|H78QyB0)rITM z+h_C?6MLHQWWAeR0rwhxc&PNld^uhhnDXTmsD&@+OxTPBPx3!%5{;7WAn&cH^IB#X zb_?~%7grnWvI(x(0_V+&*YMp~>{m)zp%I8MM^PF(7{1==tX4~<&f+g*-kTq*mVe5f zta9V22beNrdxFS9tF#Kw75UDO*sQz8-)3ORoufDyr2gYQlW%MPu+M zLnmvsw=|32^U`bJTvyt?y}_wB3)p(K`lGcf`ouA|Rj0{6MsXPwm$vkp)~-;>ZhPKA z4&}v>U3HW&cr>!>3;g=;U6R2J90KBL%{*FkiEsI#?PU3s&f zZ04+Z*;C?Wr&G3}KU`xRrSNtNZ}_crx^2BwK)O`@@s~2Qz*-&IApGp>4)P@B&!@yD z4W+K><*D!VbE48MEO!z8^L1ul{>wDTzWh_F(N3!XaP}Lv!~125LiTI&nQj83CE&BF z2~T%aT3PRkmH;GEt~RhQ2*qiKPpfs~Mx9L%I{qRZU^is{Nl3k6JKs|eT6z6Z=XK>2 zP_AU9P%RHQSZAUDnky_!nk_weDmsBGAo^@R%;KOUrjW-QJog2k5 zo=EPtsPh3aiD3ta)lr|NSXMYZqQ%0j>)Qs`m=Gok29AeytzM^*>S zDgFN?rQ}+rBz9U0k03D_oHDHHV-f}~sKNWYBQezL8C?lN^49{P z)PR)T8a~pd(s<62f7kkvwA{&e%GE|ljG>Vv(4!4Isk;I2x;?K$NYu_brIvZ`I2yo|JG z#XO}#u&_!~#VkW!2j%s4dCf%JlPloYNHQ(>YaSW4#saOZ6aC=OFZdFrXUPkfu^g<> z__t6K#%CSXU-%<-q~LtylSCy}nHCHXivj5VJKhjh`k~vbpIfb;HTowmOUr^0AD{jBkUXBoxt=49@AOy(qsa9s8j~PV zVlCmXu9Ke2k3~1-0L~G1Gq_))#*wcH*hl2o62e~hZS-qy1U?!SJny4c=hXAC8%#HJ-{r_Bpn}TGn)p+nw4WLL0(Fo7E801Phedw4-`1 zdYVqt*!*KJNU=s&OH=9yQ>e(>v+;Cm^WRAvjmqEdW_g?|R!kLkc2G0Z+p{UN+e)2_ z$L8jDQBk)NT`%;9N{Yt>T0T_GFZr;wuT&*)&hb}F)#~KC>e$oL^h(vfNEUn%S=e1A z6}TD zzu0>aV_kM4ZL7WdL8nu5k`V{L#f1<6q;R$0IDvRR;e$& zL5d;JbtQHVfzPv^)vWa9(hnXnhG5iAhcC9NpUUW?vfo3VV&*am(WY~ z-O8=t842b2K`Og3htZSlrj}ajKKWR1QsI_W!3oBeQck^}H&J7&KlD>OIkj#nmE`N( z-u&Rjyp5~((@^h^TIzkj>iMYC(qx5b1W8; zIN*mpPrI-gVx>5Xz56x~U^OqwnYW@P=RP}1g&JJ0BB57ryXp{8skW z(nE#IgvffDcas`fYTpz5j;qMOS{1p=cM?e16VZko`bF>$3Q+O{m$Vi`WP*8~rzZ;; zn$dVh2-l{mt@qhT=2|iR9DL1-?cPJ1{|rIGfGBhTsSs#$X!lQsW6q6jm9!9xUYYso z7h2@ywCaac2*cq(T6CwIqBhhTDbbs83$RCTND04d553#>6hrSuVD z0A!&aLD1E&)?vEtd0Ie~hFZ(An^rA4Cp0tv<-)2ge0(7VBJ#R>t}n|>F*;!;9mGJB z?PI-YfRZ-9aUK<64&0s46Lzg{(}PUFxMYTn>)9o!|GXVr<_GT#4_z9(ZCM`oo2MO#@a7cn-c>uQYt%hev8E|&pMGv3M@A{ zv?0N=hzL%^9O_>lNl<@TJDDu3%Id%}zcH$8n_2umv9CaaevAq3?e;Vs;kUKOj!s%V zOxpZoh384suh7>D*SUkU3eVF)=74_wmK^*%O+O;J`YH*{&laqU5sC3w-}iaM^s_4) zU#`@V5U~e|CaEnH0(W59 z`1;jRZfn45yp3Or3E*Y5>X649m@^t5OU_Z1YA52cxVQ)j5#diIu%;FZq15Ur^aLkF z2|5{ucn|s!y-66q^C%`>vQebXG`W)V5p0l$zR07ko&1A1qy*_3OA zvB-wuU>v38^n)Bv6UkzjR(R@tS5tdJtsfO<*fSR^SVw{t&qTE=fOa7Tsa&LvW<9tvf;EN|0Y^^^N@tbbEhBmzCdbtc{3%g>k z=!7>(_8@5sX@J41hKua56lY~$_B(8X#no=aA(45Z8zma51|x)a>~#^Z#s*>pf<06I zuKii_>m0b;pcg6RX2Vi3r@?`tlQ0hPDc(eG&)AAq6$q(_wz8ual#FIxM{YV? zH8U-*ri?1^rmyWeLbPRP7{auhn?zAe;L;Co0j+d_cElX8f5~zh^CGs9ApQjV4|L4( z5|&ZPVlQD|0{`)2%BQe}xab^2pK!j>uU_I*44McLt&5cBp{N*?DIvjwrg5zVo6y)8 zVTK8<0XH;+EP5Mng6>STFObV525^nsvnyht|5X-~Qt#+kM+>$~2}zR)1z_Yu^y3NO z!zqXF3$IZ_2ar}|)qe-JNLESdwm5*WeeOXsse64I98a;BeXs?BGfoCf;GD^FWCA}K zpz6rIx@t2RIF6OVgyI8zm zLb2;2Xa8YdLDm=j2U*{8m#i;o{*XXt@LCyk_=XFAdjnWU{{@ETh19j~z$og#DC)qd zmJVc!DveW+6;~#IA@xId?@fbO?7dc7JhV&RCk3=a#7JS3JH35uPVwq~+BSsu^qzRn zaY+R`Q7$UO^(0|ZSc15{g%vI|;nz7@hEWhRZ$=ts#A&L^{so;4Ri|1HIqpit+&L08 z#`5FUS`URYBv=gb(|Y(iL;S^%05It}L*!yeH?4=CGvp4cLpd6)M}RY=N(>3odUSJ! zl!zf=T93ibkRQd6QCg2-&X6y}kO-|um^0)(F=U+9W0W)Gbunb3)+53hq8CG^Xg$U` zLtdZ|m*kprk-{sD)}s+eWome&m_@GjXmW-;DTXMt9-Om~?qbMbtw*pkL@9<0(|QbW zhTO-+)m;%zq2eIJqlx@2vS8*Itu0{YL~VLCUM!Cz^#t=uP);5i>RJYZt9!8caw%TX z0$$mmL=D;}qXg{d@P?&eWBDiZE++3=ktt zs|b4rVs!>#<5uHtL83Okj*jW*L!iEXk`Gm&Jh6(ifeI{k<~dQd@i-p{gK)FgOr&#W1?{joESVmYfWP* zo&|9GXa~L%|yOA zww2fv&pGA~x59@rp!wC{taT!iy0g=mA62J{5{6I_p~4gR0Wjd1S_j1W^ApJauP>!R zPqm>)inGd%g`~$F1sZlm3%|XGaO!Z^^C>Qx=oo+85y4AD!X^=T)ymoh5F%i76&0;( z#ixLw*DI@;rR>bVPKh?qIU1_@fzN2+Ju2MYM~{_^72Z|y#79dOM_PKFV`9r_@@_qv z@R5nS!~uklmeJ(>??#i)W24E(_~>YQ9xWqC@qRXkjvWbinwgGwA@3yCpVd=%X0A4e z$$#KJ3B}tmohKKzRw5fc>qAJFm`8+Az=ci#^Q`+!0jdb`nE2a$>EtFCzNb9&KsE+- zScS7#5XGAVmQr7Ee&|Pu2pGe?oqtGtQB7dm51WGx=kmk(^bO8cW9sW1x(oH$1vS(5VBLw6wKj(9LlMrp$^zr zQiF5*YlPtW4DV<9j!@;$E~EkcW{^|GIt!ybIQ_Fb5NuR+Y{Z(9ledj*E@9oX8vBqB zhB8}j5g7{D2GUQ*J)#GSYs(*ZnrS(WO9L1g6wJ~z{^$omDy*-upvm|uWU@Q3)G(ac zl0MdW6XZegy%{Qp!jAne$s=2lFF2j`JwUK)0;VY6NoPIhD4*7#fc0ze^0YkYY})`x zT_alP4YV-vicVPKVNk|tkA@h|JTMc8&sH2Gt7(jksuRZuu37J0aE=3)u`XkE&(Psi z_UV#VLjl@fNlpADWQ3ad8f5$*%1EPbAC>saEwMxl0FYo-hH3u=Yg9+4mm9!oIEI4^@G{jqHb& z@M0THVI+t5HD6hg)}mM8g=a*R93|xWLKqT8ft@HMi_$V;iidCy-TRru6G&!wzZN=S zinS~=u#86KZ=;&GQH9&Y%7y1nU~uOttSLc@-y@uyy-7H!;*3e9(EOb{^*SDBp!r&R zcU^$~Y4E*MBYLyu^{2mv2_PsmD?zDhR^h(V?Dy(Z#%BL@L!jo3X3Y^fhWIl=B&0=2 z2Vxa2>de6KTlZ%xJE$7v=GBU!#Q*@xl8i}bI8gbO zFvGOPh8*jsUNSl;IiSDu9O#0$r&1!2-pyntKz4gflxXMRSK`8P=0DD)G3GN3DLh| z$O9=<%y(1_e#fqHt$f%Tc*{&l~)_RLv51Z9E7!jEXJ_Y$C z0pq<+6N-9AewY6gw33Bj2H>AL$MafISP_j#A}0 z)z`3<4YNK~d6+J$uOSrz3y`Dr!F*9*iKSZ1Uo7S?7V{U2`Ab;-lgeYfCEh+NnGS4u z^_J24A*#KWzyeE^oG=G_HxPHF%8T$#wHHb2EmVDh6PA_d+UCnZG}GzET9tuPwV@FV1SMTZXX~Cr}x#KHnc~2bdlXh zdD2dK(SKRjCjTp!wzfO(5 z-czQKq4(?PWfDf1WElMz$tZ{Q8oUGqbsW3|2lZXfG5V1p1VzvsKn!2@1C4LsyC2}t zAiN8HBk-#PzA^X--5C4?H*z3jN<>yQjq14}$C0)+Zylu#IZkN-Kc&UwptNWOe=;yb zK`eC2liDIxHr>Of3lnkFV2`f9L0epGELs6!rhEVERsekT>z}pcFl))VKWPb@#(!vu z*pB~AGm1hBlqH`7=bSj0xJ=%H%M+wy9y$8*WtLy$#>)~upQeo`=B#QjysnufC7{)` z{@_=Gb^!n6l}7VrhX~Qmv42({h(4e`^4Fe2Kb$4pVsa2}(U*i<^e$hPbs3n(&_`mV zHh3x_%A*8KRI;3PFc9V5S|LagdSTxcbU_SL=Y3CR#d z800xJti)80K4!|OSB$XeSER+8XA?V#f^h#&9=lJS$ovBytu6QzpO+Z#s{3$GgB*va zy{NhM;b|^aEuLPD5VgWSNQ$1@2+{6h?6`~nADdZ{0W07|;CA4J1FW`W zWqUzD`A@Y<<wmtP&FM~p6?H(TA=gG9vbpcwMX95JoO%AB*FnZe0-g1j|`uK z@CjJP8kedidJy*Xa?ljYLh2r8A!4)&I^#1IF7@I@8j~?Kcmpv6Fmm7=03ot_zn#lk z9&2n1=6ZW$U`Jx4(iROQ(Po(E6BdDE0#Xu>sNts9 zejq`HGWkNG59-AoApjb=jTu#(z7L{0^KG%nHhQ`ql0_xy3l+i5c%R!LxQFa??2$O3 z<9V0}I2pk(uEgwr<@R(wIET$s1gp&LuqE(@poRi2!izJ&5=0XizQI_r8U^8zD(3+f zFzlm!SoBzIZV@zB*k?HT^*US-p+aW>zVOorUs6sVf-n38;R{Qc7rx}2p?iUs#2%om zvmf41R)hG0Knv~-UIkuKyEL~aAmF?(I5JUTz0Nm6m9vsnt)^pI9%O2d^LJ4k7ok_t zPo{o|HeZ!9gQfAK=d=m%!ou9jwoqiVaxT=lsB(rO2*)(iT6YF{ARZ_-j~1gbA_)!3 zWWCMP91XUv#eug;zl z@MB7;sJj1YDN4VaaMaOR$=TL1n=z87s}6bbchPNh3xYu-Xv9j9VpE_3=iA$+$l#|I z%tzWjAb?tN6>DN5o(iEqo@$AZNcw4~061AW?o=1({eW$WMAn=s?8|YV(RCW7E{I8{ zfQDdz&mU)Q-1{-bFB& zKzt5?g~Zf^D?eX26Kkl@9T_HDN8)tZ-J-1)8N^ zmE*o=S33pI>>v!Ymjq+7AFPl07LHeEqNeN%Yh;;i)rUEJ9v>v+1#{Xk<4G8hgm2_)6RXrAk z#W>fO^&oETm}qz<|frETEgwrH+ky%yd9Y zYqz+6K)$L@_y&*@aoPR6!Ia9m`FV)H{LA}PHYi?Bc*e0^u$x);qnIp82>G2-sLdH? zKydVoz56L(7-6U~bQXSk4KW(5#lCn4JdF>mEax$igmahSkMlLjn99h{#AK#W;T!l0 zxc~ra2g4!M6`wIC)j>5|B&0>@=?@ymz-g`Xvj|=oI~LRijPOAD4Z_3SPX!;G@JVTd z1~NTt5k>={(g+HdEl_oyZx~*$^CMeoHv*7{5sTKL66p9wQ9K!Xp+b&6Y$=5Dhw#cj zQUf#D_T@CPZpi{3Ydd4AfegQ0JjzXQDQ<}tKB4GG3c-MDwF!!bBOxGl4x6y>1yUDs zbik`E#5Y+W^;)kx;~Qc3!TJuLLFx-x{!n7qIaftu@$`JI%seLHEie}0CR^stKI5z< zca|dfk?Mg3sf&<2PSGEVl<^LKiEzhAH7b0SzsZJ1?Gu=ouu(_G@PHma>XI7)3|o#+ z;A&hWGIbyUs~{}ZvKjV*^-#Kaj4Wha9{u7emooX>aqapO1kOW18NylnSzoG$j%znC zNHQ3I>vfKahMoXVfkVTeVSS1s7_xZf`+=Q2aW_`wpIBKidHzC9Sq{TV;wZ{ z1M1ctT!S&qmlBux1BYR#i_yMm9YX)CPS(?*LI`M!v9%r1C9PUQba7Fw{453W4?KD; zBT{o4!G?mxGrTJR?o2|(tHk}{oPoF=5yv8X*7eT> zQxya;q;p8pH7rt!jQ|p4Zt)UG1VZ-%PI79@oxWZ)R}U@>Y0hiDaE z=$v&p^z(2ldyaI9i1maRA4*n+X4TTV{w!G;X|xDFn1t9<+i>N0F=3{N@Ptx9{BONye3!md983&igkMHih)2Fwl*5V8eqROj& zL>CpV0}vRSjWw^3kO5{s16pYe5Q|pef(gs689}57GMKawV+c?V7Xdd$xc{>_*kMnm zkqm_r`PeLPZ=R^oS{|j}e*Y{QQh|=`Q7CiKZ}06yZem3S{Z_{4w^osU3nkWIPo~q+ zjG0s+6!r^mp(-Y7tIEDk10|!;x%GI^&%TdwdSKUBh@C_#IW* z-yu+2r~2FH_zf+dJ{=6DP-x=H{2Pewq97@ccqYARmOs_fkSDeIphDlAjGBpzl2GX7 zYQ-RG1!J{*w$O{UqEJBuBcvKhNQ3fbTp%3@pDEq~YDd!Z}*>vh&>RwS09H2wyR9KcEzG8K*kBQ9p z+Jy!SS_NG}xjy!anbCNu!O9J0zxwa;#@j>b;Rc@|pVCB3Q((qk!pabtBK@ukR+lc0ox&10}jnJKQG~}Bm`F=9gM{O>w7}Cg=~Ud`rY8%fQU&s z#p`}W5)4Ev%Kn+7hp%l1#Y)`ZiKLKdg#I_uIFvbZh`|Fk4eZ_c}9QvJy#R#ZU>84}+ZWHe(<{3L3Hu0Bu|ls2fTPG{eh;z06Af6$Iz5In+K@@MElfES#c!hQs3nKW z&8au#48|6r+GI8D9tMx`(|I@xabrze2H-2}K`53f)oT^lr;ML&cz~F~oQ?DYNDFh` zgb!z0kjhor^}rPfD%ou)l{UK#D>bJIp+<|`cpp?;^J^#Rba@h-;-}EX|0JC3c2(a`e;!K-9 zz+dBobZ9I%NX=X+{}<8>Ek=;)jb8yN8U4LVo%$dx%{wLSc`*ln%w*oma^haS0nz+H z0*Ai?^7$reh}rL3NHs0e-c6VDc>W+@JVOlTbbG$Ue2}t)=H1;X z#{F;t*mX8kNn-jr)Mxfk(K_P1Qc)0P_X3HPP6VH_UJWgV z3c5%WOJg!q_nOQ!9+2LdEdgK1R$9lh)n3BDFuzvvANrM$fPSUHCJY+;=lx2ZPW?)# z`tyDjd*{FDSIR;CDvk(uzY;kAv0tgb~Rt8J)W-OH?o;v+C*rzdl^5aUk-E& zOf5O@kC}Cf&!I4={IUGf!%`(xmYT#olkg(po;Kg{tbC(Gnyw^eO5$YjH0`Fz@WXJd zW8xqV*+Mgse`vYo!8cg0Nf~#H-zlK$3Qj!{{PELOrtIN_hT2oK6lAkm>24S93I8|R z)l-)D=gs=w)hx-MHEY;^ZdQ2NpEL_vA=tXmdK>_&f0*MpZqN|w#Hv zTFreP^)}qbLP4m+EL)3TI>j!gjiRydN?A(ZIWSz1^Px2o1`LMfe1u>AzPM^yu1jOg z@*!gNVxJI$(%YptG!_sbJX>5L0G9IsvYF*M?;U_HIx!^_wh2#{BjrI_op9m?YsRWH z{vh=i?gbraY5ozwm~v=%*M5KjPs|(HJIQm9?QN>;5AngX1fj*yi&)MVHf-NbE1S$> z%4QzpDQ-M}3_KAv>^<1@W)4L=#6siUWl2ESh%HngN(8n~BwnRr7r? zXJS&~0F5`s*64ROuJ#^H!DfKlL>?EoxA5Ttmp@1a{}s@zf9W0ldv{i2W4h|KVQ9mj z*L)KRwX8z(Cc>ra?|EsS=1mNIc49D_$q)V)PqUd4n9MXMv!UmKKWREh3mcf_*k&Q_ zXo&ITS%F}&#VLb2g&-m!Z{w(MIYSTJc5;59rDOZem1>{FvHup#t%c4s_cEJ8`ZXRRfyAvv%>t)Q|>Ye{0^rg?L{n4 zHu8uYz6i#6a6jZYupEh_QyeY?zH^{ph^(q*Lu408ai;NXeuc2*Lvq5)|n z=5W)GttZzgBxoq7wS~qMtu53MjAHZ`YYQ#w|7L9&exhY)upO+0v!aJ7@LR+h4g9NGn+hv26Kb{?2MKD?| z8-$ogmJPx*`Zfa0hS*tX*-&L$C_kG%A?&UwP9;?i*}>w)>4aH(no_xz4%Zxe4}olk z?`AMibu`0i;dRb%HWFxtlZVftjIC!ltPitciou&c4Ktfki38W3gf}JE!bAnT*A{0R z)`EPFHVnFzV5`qQ zK_iM`fEII-D@L=*={CWZhy&cQ_q7d|S<`4hIGc9da7kPm9r}otkwuMaHM0JyBYKOC zdaN6&Mp8G3jYv_%hm?e#YG7B0%>2Q)?aOlgo_>yKV1n_!Hx9Jkv9jCR-PB@mDqw(u zW}SIZk56Ks(zkKFTfGDlE@?l2YM~kXu$O?Guy`<@o9w=egXza(u||A+;>|QrrwdQc zM`M{-uDAW`#Q~J28l6P{gkO_fl-rrn2O=_ovU(C#<_iP!&6D$BaxT*H zivk+a3qflPv{){CfHhTFN}t~Ntdfa-pFj(YOIJxPwMu0^F`nM?l@%MWOOzI6VZ5?n zzS26^`L0P6fAAQ9kPVf&d#&K0ncWl!`#adI4^Yi1+&HBsybYzov5Xgh052gXEc_dU!-P(K`|mZKle zqB-b>0%voSmMR}K0iUcn-lE?F-B4nI!d>vq*2={eUGue6d!a=ItWECc=jkAz9Uvg6 zK_E!pl=cBBk(hb&RNN2LKT7bm#!z)u%gweR=%;Y;=$XL)Q>8u58s^Q|z47jP9wf+o z8dHz7CEtLy06o+e#x;4EhN81A$l>Z5xj2l_7QjzeUuUzZDN-~=nNQmFF{rM2uy*L0 zoK104j9hI&J8JzcLfgP&pmJM?vlARAPCA1I7QwurK+K#`b$6%DP-RQ10>68o(LG7b zE0JgmB7ZMPzZr7q?PvqG*d`(lR_Eb`bGq;v*2Gx86q4GPM*|O-^p?v~Wf_3HOblJ3 zPb!XGWtru2TV+0td^e1+S`Ld1#2En=bk$xg3Phrwz>p6l7na=w8UpbM;X#O}ex)m< z=$8i;0xt+gSS_1@b;{c#7`%Y>l--B1q0epvXfO!{TN6}XEtPlDQthEEq9A8^%rBM) zFUtFcl~+WJ=omRlT)Ndt%Oj9OI}fNr3gHNl6r17&CRE@Mm}F=K4ns?`E)yC<^T9L+ zv{KsRz?KuCvEW6IU)z;E{%(aQ|Zi735r6)wPYH?ruB^cE_99W)A<>E6fp+ z^|QPjxl`bx@CF9e#`B?l#aRN&pLK)8XIluUBo_?5q{Lxm+D*bErY(*5i#pV%gEWfq z0MQ3$qF%zt1foKbsw^Qb9;YUk(w_JJCGK1}N`Tg>KUbJ@4+RiF#{1H=@=2<1PRdG5 zW;x0NLQjPhG&Go3ONJ1RE@qA9TXiHSDe~d4)-_xc|H;~^v39BG~$CRU>*xRdy z@X+PaA|_@$0xJBgK0Ge+l)&!EvtOQ7BWuv!URlPMVTun6vGA9~G#l3Ys?9Sb{BFvy zevBh`oIl=>awj{8c7BCt%@*_X3=ttGc?O9HIskm*MP%g7)H>cW3AT~p!SUoRi1|5q zy*ZnI)9i~BA{uLbDDiG;8`v9j2(x9kRNpkqK>c^g#)*x9r3VMAQ0R(8*xenw8Lp0t zp^ql+7%j#+bJQ}Lr#lC@Y68Hl=Q!;uSxgL-CSp21hm~9|Hjv*$(22+~FAU)U&{BA1K?kSF6F)?oqIq&TCODlWE%xn?UW3{fcIg^R~&44wrBDELOVojTHu*VP< zs0nw``*)!Wc?*SMJgtWkD#`jO{;cPn{ch)32_jIgk_k!LhpHUBz&ZHlTFMU7?!(0) z0{z3{m@Hfw7!%bpA|GigHBtYwwlPiX99L{0gg8g5mJNrMom*#TjS~m4{+tu2O{}+$ z@ds)2gp`C7YAtIc#Wa8?KpcvuwdQP`@M+{lieu6_h{btzTVr_Ss3gC-s!;o2AgQh~1ERNXbK|nV200q6r2#9v} z6FSXv(W0Z~A}zER!#rfM{yG*dkV>nN*sDN7f~nUaR4>o%Z2u|52C*t|qJhbz-FkV4 zT+$q^??*)P+jb3K;tujb5V-cB3++ZuF}8Dqj40cVc*D1p6-0gCl&FGn5(hWOz8+Nw zX4Ie3yY?kCje#6jI|g3&Qp!A}e8PEn#`zgqvDg^#$%EKqzC^WC9%R3bRgrhB_e7Yl zu|T5QCJ#!#O)`l`H1mtag99mO}oyHDkZn43|nY zu;~B{#>(g?oWm6r#A{skzz)IKrO^@SUN4{ytO%WifR^S~^fbn(q#q3900Dk{Q z1Uj2L7+(8SKI0z$(RLsX!=Zy2x(%YBFlr|t!mSca{{tPX)KO57zF30eCKx|(<@^Na zMPe&~ULxUhcX4)^c}4T%?T@GN*Xrmn80vGQiJ7|86nDlHS8j?Uz3sViHKsVh6n6s_ zHcW9)iQWh!#=@=7=t)dh3T76CQ1CHZmQiQ0a8`^Ueo|lID@5=Hu(^<)Bwuj%lsh`! z09PXqkxDS3KwHL2fCwcFHMp%HR#-%z^B>VhMuViIaB+?sGyd=z>0FAc(J{kG)Y{Qe z-ok@T+dpwN5d<0FGLN+fIR}(C^q)};uv6PywX%tUCXg=`gD@{!$}1YG?XO=PHlpXiDYF_GFanmOB)|aiy;XyP7>krxiByc z7vu|ZO`A#BOTGD0l^9YPcW*O3NMI6a#vu)bkQA7=?WRq*c)PM3UmCrq%}x>SAvAq6 zoy?tpVFkhZ5feQVOg745{Zv{hGJN+&e)s$y4Xq=6eQMTw>HA^j2*k=^ER>AAp5{67 z$||Y!+Q>rqtnd|#tTHHRO)Cp69$BUL-VZD~(xeSG-ZFQ7ymNtJT3evn4hlcuy)S$V zfh-bJh&FkdV&uX$d;&9=6Q&7@5Im` zK#T(ipIqzROd)AyE1vQJGX-uhlHz>k%VvUM zo1kkct{=RuB+f$UGmMI=potGI@c=7$9+hJT1%z~j&k z%y6iz#2V=RgBqie&$r9aj}4a~U<7-S_p!JrQkv(~K8LPQ?H%uF(pA80oMGX5<=EV* zH?xaZcf`>fw+f31q6c7F*_2lsgrw^&K~aEFvrLeYO@3Vdy$m;7Y1Eiy*BKeX47$s4?_5*T{ zw5W{4iiq5}*+Dnx2whdWCk77y$B4qZ+FvKwyRQ!%>(B}7j|An7%2egN#xfkiy$Tm& z+{GxDkamHOs{#$bD_W5ZaSYV`gsz6l^~a}YEffQTzsSjR_ki)-g_EX1aM=w<7TEjC zM6rdsd-RY{sB0wFS?#PGA*~ZoBQ8V(2`O z0<~GP#V9XgaTK~k6oA>b0*juNZ$m%CuB;RwS>O=AVXo^wxT5l`AG25tUP#?ELzR=r zWG$|1U>y)=9M*Mc`9?90j>BlPfXNTTK#{rH*yw5KE$l(TLOT9nN1-YDhYZ-*TwH)q z8=4m;fp9gMV~fZfh27+yGcH=_eG3rcUgs&i4nZjGh&SOU+DvzejBL_5Ncm-w#rypv(flXpwkenYEB=3{C4(2E` z@tj~#*+vB=^YWl%W7Rr5X|BT^Mq%)%y^2R9Yyp*iLBb1Ig9MTgKtrtNSwV844MJvY zMn?Sa2af_yZbBc7Kpw1$EV&DUyT?#-d9o_s;u%hC z?Q8pl4@Ix7+eI*}01S6ja{!#Xno5sd2t;l9-8aDFiDca=8IoXFu%eyY+kjS!txiFE zCscBk6A!%Z49E>wI&pmRBgG)~uacSjJ-E|Aoe$QVSi3i_5~??!Ku_>-nw$%-w!wMx z9g2rB4MaXfWE+aq1z~W5sk|Ia+i}3L5~VoR)1GkQhDaeipfjvnSyA$ z2M!<^EK@$But$=DvMLCqrbwa%9_MH$3p}0wV~BaZBE>seNE0KlpHQK>hnhR#nmJ9#Q-pLVN6fcNOp8@6xFK29 zu^#cqv3%hZO{OFr^Ux3rTmf8RvZ@2{NvjOjF(-DBwoL@9KEDW9IBFrVS4|`y!}(eF zo6*))sbW7+N*BUKL^H(Z-%;h4QqFwJsrRb%Sd8MV2Wo*D`*XF>U65W>8|BSM$?OSW@h^+k_*s3h2O*9WE5i5{dZNDN-&F0F3 z2`G89SV5%Wl*Y(%M~dCDI?&%afMlJdA8~c z123YL7j2KXY!f1zT54Ori7;v_F0Xcn*{W@IR76v`4L9Ep4P9(`6>aXIFbYF~2-CM= z=M*dPu5tE8b|A6ejyB%V^Y`#qfkj6AySWn9onFQuGam7)OjcCFGLjyKM)e-GWQw-c z8kPBSTMt9KWPZy$fRlMrnt8qXyU})e@(-gsB%8L(Cm6q?zduaFN@BZe+LVe9XWK*^ zaGTegsV$||rT0rMxVWg!sSf33Rm*W$;Lpp-jaIx5P3M*33w7-Ca~y&HA5>~97HhR# zbpnHcuNW9tOMfpty8bA@SYOo&rqY_y8lNM71(~3t5nt?@6q7JcTz+v9Sp||hunRQo zY&WeN#NTW-7p#@#__hgFSC)lA+=YWL05=!DqQCVyOYk=WCTZCuv?R0|T_;Y^*sZ9>RIjqt(Mn?bz0zjov36xKy-mhr z>yoj)dD>EgJgqpXi^VMUvbl<*xonb3LU2=4xP3BaKnXKEa`p-spgTnS^2AgaQY&Qw1V z)t`F94B7RmRZ%cGFdOyal2)l}Oor}tv`1!Js&Kx5f$D1v|DJAP(J|0;JG>lToQv>8 zgCm;9Vby^MoXP!+ja^iKy9l5}?jd7i+jU9$s1zybau`W!BKjKz4^oUMQRQsHOoWN$ z9RR(Sc#NS0-1RwHjM`37*HD@m#Xjj#rBGKz4M*x-l%gGijDku(itummN zT4xlxsqyO z5qZEmQ}Y<40ROKb#r0>p5CVcqA=eA3?c>luEd7L))`k5=d+8D-T#cksdQ+Xc#>yV8 zY^9U!fI~z_j$S+(7jEHBt-}EsIZ{{(?ufSg>hKN_Sj42-lEE|?E(GA7I+0lAq^o@K zl$bB3wNTa!cjBAll1Pd{Y!cDA0u?kA1Xo3Gi3WZbVv4yUJ?34j&o! zN&xg`7&=fkTX9P^wY@O9(l)cQT!?2?z@kB`_dWomQ;4#5SA9sa1B!D|dxTMHypI8_^oDXPjjPiV(hQ%mNM zM(AAmhqvTcQhp@(>JNE8WOGCKm8MT}aGjCKqh)zO=4(6Ntk(www8kkP^uy=wgOVXJTXN77@IVtej0lF(w;Dgs#W0h3)zsD&M zsxgm+fxak5xzdbjG~&cn`xD zv-XuK_KEIL`W_%g*@w0ceYuA-w8tZ%SnFuE+nv9*s>;sBYt6OQ1esN;$}Sf{RI9R~ zw30R?P$4Y0?U+yRz8Pk_sZFIwwqZGNR%_f zE7WnZc!GV=MK-x34c;IJ0w0)%OjE9|e!r{O^$L2h&4jP)7g)6>@>n_a0%6&#qZ1%)p#gS}P)B9?1knGX6;Cb5 zYFH2bPKu4%0sk5(?$rptUSXlPLi2L!=R-qN3r&Vz;@xV0oGwwtOm-M5^_qSmN;C5aB%s>Q|+DqE81#A!la4y0C#5=nu*w`9MLnEQ{NQP{h6ZZtsDK1bHI{xGoqTL_)GRgue__VKn2>-dg-vFg11TpeH&Vk^V5uom zL)!)AsdVQ-d|Wp^GQpLEN~x4p&WRGDtHDhK6#y_{$bsQ%1<`P*GzHZEdK&vSlaF+Z z_I*e`Ir$pM2Qq`P?=A9?deOd@c*z0BU78s(QfD@twwB)Xrw#rXg0tE()>sYi*~fut z)`rjwbuMc9ZlG^WN&C%S{=5X7hsG)|Dx))Hr_-OIOD})BKkpfsFY1N$7QMhZRL1~U z^Yvb~$S7M^yGLbYRAtwA7xOjRhzAYqaCy!6T@@gV4|5&Qz&$X6ee}ZYbWM`kzBrqM zVb?Ok@2CQY7(L7tHg;co8_Gg`kNP42=Y24U%*GN(M&rrk-ih$cZ=MQE;y5^6L+65CHfwFA-B5sR&BzP+m}mr#BQf#A~^fuBkpwhmwS z#zvdnO*(Bw(@Dy^(gwyA9GbY8WIm&S7@~yaNJ48#@ zr7ElgbOw=(t=F|x8~Vx6VAE7zi=c+mR3-EzyFO*7reO?JQQ4;1ihZ}RYbOUbf-i3c0!ImE}xJLk|S0_BJ5Ya#Idgay+(V-K0m; zc*5jh7xiyCn6%ZZy{xo8s!SZ_;u_5+N(aTxj6I^c^)8G7@{rCs^-uZB60U% z)q%2xQH$%lic~oot2dal5RbI1cj=%^o$D(`R+%HwF7ju==pu$t7BQVO$|5eJXgir% zjNvDaf}yy*k$$SZv7RuzEVF=fwJYhLUg4{4PV?p`Dr6`SkB=Yhe(tJb2nw47#GkI z*9~z2XjcH*6+rpj?NXy%r|pqwBgFt1#H!2eWj5B13up)0jdpZn?FewU!w>E7LOawe zCDS0QT=1O1%LzRAeB3~zFa@DfS%km725)@J8>$gKv!U9FR-i~GBDh+1dagUC*yPOn z5$PQ>?`zUMRiEacuCnsrWzVecdHOQCF7%Z3M639(N>Be{B_@(NOp!%EX}%KwSjn1hAp-{|1FL6x8BS2*3d7#)bkL6jRr@5ZW>tT96zk zB6+%bN{}K1dhb;-OV?th1urhIH9Op)Uars@gc3$Y#y3v?G`(OEp^fh6cT@x9LB*iO zld^YC-_>|S4sL=uE*=E^Y1aeoB#vd%;O2=ZHjJoCYlGC6QrY+?6p=~IQ5S2mh4ip> z3*vo)vTkEaXJ%mof@+{rj)oWH+Ux_Iv0`|+7=9kgk0?O{*!Udl4Et>Jf&$1Dw|*c+ z{V`7FJ=JT!qi`?|u3DwqGus#P9+wqLP*aFMTAdVJd z2`rivczmua(YSo@vQf3zR7Zs7H55`+`i`nSD(x}VI25DTOb`PNc7T+R@{&~}7fh&& zFi#m#ry651{E7nh)uE|@AjaLw13a7)-UA49oW6|88v`F0{G727YGWSCIM;~#;tkc0 z=VbZzgJ?YXbc!8!z6PzV!3KWf^*Z0*@l_}Z^U@Pj3wY3)P?3B6aN;g49_j`$GfPSQ zJFv$vM`lPsakE#bezeH)K~Fmmra!exXTj`SkMd{o z<){EfDjM>!g9Ab9eZYr2^0+=0b~UDpfd;!0Y-3i-6?L?-ocB5GXl{NLGB6FH$7OZ0 z`^MW2W1S=PWN3jgUyfZ=BFQrJ>O(*J)AS=TC?LOuL1s8IKYlLg$>uQ*ybFwJ8fn!( z1-|QFMqbhP%dXL1#?b~r9T9X6L7oUYX@7fuJWFmK(~Qi>`n&kkL_a9>|Nr;jVqhZ_ zbnk*Ifx8S>57)lElp6py25t^q8eA^i2XJ50x4)Dt#cu`N4Y(#azYfR)Hx4cpZZ+KN za2w%1g!>Zi5L_wTWw@JgO>ph~q+D;fL2%>XqTv?9>ESZr{tovE+%C97a3ye;;qJl7 zJEC4V4csuead6Ra32>=!tKr^)+YWaKt{mG-<}{$==Gz%A#}xFqNu}=0#TKGW<>DLb;(V>`_=a#I5G^$RWZeHi9rRJ~cfuHFfy{F@%(`v#{}L zNl7fo`8_j9ADx(LNTTyDOEYQN68)0I)Fm$`jZK4ZL1OC6qy_pV%a`d^vwYpYkK}^k z2E&bln+P`xE&*-@+*-J7xD9Y0z-@=y1@|Ld0bCJWDO@>R1zZ(e4V(aX1FjD49vrtj zl9R(J;C$iKaDH$BaNXcEa6xdva0B25!wrKAgBt}G0XGhABHR?XD7aa0bKvH|CBQ9& zTMU;9w*pQNw;FCOTrS*3xDViVz~#Z6fUAPz_Mm>a2)G2eOt|fEd2lsw^1XlwZX(ivjNK8jBiec&ch49lye7t_~5{ke_e0*|Zy58kq ziT+-m=1fNAq`E%h618+Cb?&x;kZ$wIIb7`M62utH#d&smaj-kO9V`m zejw63f!~l2_;LNge-2)*FN=GEdlJ8W;7|-V3i*+odj`J)@EhEp<6gz@d^oyC^+l$& z@H~NdSSa8I!aWH`Mhl)nrco%MFZ^ra=EEhdOx7p9kebvFc@tK?(8^EP>c=JM*Q`id zo=nkP0_I*~swQ2Zh)JYbWJpX~D25YamMs$fE2+PL0fZR{=?F~_(J!I}2_KC`{KBN< zL_?}xvtao$S2oRp)aB`hG!ZW9)5NrYpWj)2>+DPPB7O;|mipbLw~ltli=h8`DG4i= zr0ET4{lX>bD^e2|BrQ!^rq?V@TtV$iTCDjC5L%~c!HuQ`j8RWZ(AL8c5wTeaFrHRWD7bPwHE95<%?oSa&u(j@o$FS6b=||GJaQ$yn zCoEjEEO9A@`x5silBP*so~EI;yW$e{NvoIWTMcVh3Z!uljDK5&JI!ALLv8#6&i+HW zkIYy7;R4%tcXxU`<%m94`g;^x(lUQC=uiqrhKI zk+3)c|2S^-iq-h1@It5;r%)&mh1B$)3&u&sfU`&{hlLdXf|nUmQ$;Vw)hK6)Co%Pc zf%6Mr^k6Bth+lryk1zdTz(>CHo%q}Sorky2v)=B%pgW6Sxcm2E9!E~Sk^J}j9kr?B z#5`)-hNO)H#=LM&qU-&Br@sB3`v~C?(oJ3#Q*=96}K+E*z=iRw#3U=VKvK|tv{vs{+K+p=ZHZvsqXncji+9Uo}6zz zk4CHiHfV=p?6+U6?b7S5h?4bpl_f{A`zh^ftsDD%HK{#S+NJXRtdC9{PK>SCxpQ8j z?>LX&7Ww~JHshPU5Br<{mavgFB5YH>>woC9{jG1JKmTZg=TqN48&?%yk?HeAb6te( ztsSMAU0w{tDQscbl%ekw#u$GdGr1YN^P6Q5hQRg6gS4Mq$as+S<;;t#Hh-eoHS_-Af}MRfK0Eb_oXZ+$eR!|5 z_l&4u)!w^zI>dDF8&i=HH{$F+JI6M53;R2F*6+L5_pkc&<;3Q_?Nbt!=+k!H&5Nwj znw}d+@=tkhRxDX@@KDl9jr~a9&0B;;9hZ4`+!AtU=t~`@Pdrre$yMEqbzP_dKdj!^ zAkEWveUpo;+hr)Y@VVc9+vQ7Xs-!8;2Cwq3s$ZJ__Soqsi#PR~z4P+fe%E$<@Y%nx zxuP+XOK;q(%MDz2bg9pr=wKAL2%u@pGJQ=sPopB&i?quxFs2q zW%t!vqPwgyYzHl^`rG}Z47soU!+-QoFOK})bn%T372|bN7yEv8;rF-y5p=1;jm3le zjr;zeHzTw5SdU5P+@8MJ_DP?W8RnPBUi89;*No5KQGFG&vEA-WE_ru<&B;?o&t)tf z{b{$Udw;sPV$1pPNdLXlj+MUjUWb}<8%9PvcX{;A`^#5N?R)JT9~x!qA+vXSpPJ+Q z+3~)K(Qg>LrC9F0VOS}Q8*p;M*2oV%6vfYY9@r`roxDCf??Lsq<0Q9sy{ZXH?~_)R zb$?&Y*B%|cB3{tG{9N4jlF-P@&n;c5>UAeH`f79sOP_bo*@Ls~@0?zxoz&y&fjuW^ z!oGT^tmMJ^3qM_)_Ilpp*&oL(`PMY5eb7rfaBy&u-TF=Lv@GW97jArE>V2#7;U{}) zZdG@>b1*qHGxz(apBb?4@Y@%^?5tRL@65Cm$MCi((Tn`{Ux+xSePZ?E%|l|_#ouX{YV9+IzhAuNZDsm5YaJdr1IO-K zVh9;HAUozW^{t+zT*S+TS6|pCq~w;XufF$F(b3r^_3S;drDqO3oHOLLeX`EFDY6m8 zQ#*gj9qoBJZ_1jFGmEul1OHXq*n8>x_f281ly_cJlD4v7^+)@!u9+s=Si_bMFmu$N znU}geqh|AUoA&<4%U@VEeHbji#fDs*b8*zkIgatYJFbn{5o@^Kcjls1ofho9W{>yz z{mPONLg?_V9y{LHKcs%Fs%NhYW1la7=eMpqKj}PrF(_=@!sd)aPs)p*-Sz8l)#s;u z{I~QA-ZdZGd~Q*jk2-#ScK7c3w(o?cznwqHe&XGb_)Vk3RQ2Dzt?_$$b=jpcWtNM* zpXnHL>6`WOSASc@AG^M7?u;j8;m=(k1GXTHw90!kymfKaW4`}-(6H~eE#LOj=w&Yl zf8Vgm@@#3*sYO+dJHB3|E&l4e=%Q5RmMxn&%fz|i>km!7_mpkMRN=x)M|*X<@13Qa zoKpV9xwTWO6(4-M*}&zFs_8^!a}j?(qrNRal(sOy*YeaG4|lHi>;KL4rV;Pj`*a)} zGDX=|_OW(UbMS$t+*NbNezAR;grE9i6jnXBXKZv^hRYl=|ufoHgo?4Jzx@hSyo;x;AZ@eQr@=5iK zts?`~=RQx*8F#?e{-iA6jTM_mR?HA)e0z1;!%kjLem3<`^|_rs&;9zso3Gs1U(zcg z`3z_5`0+Kvl@oXRKbf6H;Ma6oweaC@r(X(RxwZC5zl`K5_d*BV-goz{HmVLwHcm<3 zq3W9u(LplGC-%SlJ!V?7{r&IxjGlD& zu`=x1sW-fqbSjf}X}-PtnXh;5w=Tb_=ypilL?gb)kI1sEY8()LuKK0-p1l6E_k!tZ zm7RBdGyeG}&X!b2pJ=WeUt$jG(C@2LfqOguAU_gv!gKF2`@besJnOyXn6%>PThp%% z$&9wXwPVhc!^ZTG^L|$kH+N`qc&OGaSoHf-KPRt@s^0$s4hvl3u0>sZB&YJKJxaCd z?JtZT^wGAD)$lS#0eDvhSExoBe4*F>3kBWYJ)s?Vq$HSld@Kn}-4;!}Y3-4Rsz1}S)tS0`; z5BR%Y4{qfC{H5jjXG%_dle1!U&n>5y4itO?GCD2axMY6yfVUP-9P#m{c2%ljb4GRg zeq;T_eg|Xvt{rrqH*DRIsqL`m!oUp^PcD5`UK8|BcEIAK=t3FJKXPwQB5%Vy(v+4^_D8T^^q#O)B3RxPQZ?(#%Xfv>k=+vjEc*A=RNG7zj=^yJVMw~ z_PW*jHtr-hel_RD|Nq z0crmj`hTO|7D%b|UjLzH35Tb2q=Cb4D?hyS&l&pP`B`z|A1YUDAr&tEqcSH=8_z9S zmWOjFD!2Zh@AJ%ofxPtk z?QdWE|Gj>{!|UPwe4qRMc4nTL9Y0$r$}AG*LqkjWQV7K9vlA!e6?rDmd7@soUeuch zWs9RCA)&Y=3H!IylHzP{X{kWJ&qrT8We?W$O*H?}gL@~t^tVBeeFS^xb4J?%4SQPz(~Clv2-Gu;Dz9y{z7`oH5AmQLX6f?@H( zZ=vcO@xpUZ^z4J%1sBB&tDy$I?-o2z&AYh!H^y-{LGOQhFh6fPEm%xo}7 zTNqMgegzb{HTz}C1<471nT9U%GY^W)=li(`r0}WjP}~JjWM2qnfbv0&gerlev{pe; zT37pd14!mKLQyztpvXV!nC&7T@XHT^l+Gca z3Wdri_jS}E)Nv@o8#vd6YKDr~i?d&-bx`}DLigdE6{-fR1IqR$&U&FXLe)bxL503` z{xg3M8=t&vj4H&aqo3aY+H?PZ<(&cfrIAjLlinB@Q3mv6p66W!jjY*h1kDpxusr0! zgx+U#zkQJYrErQd4woWKN+Hbzfgy`5jlU+HKC~!GsTX0<{E!RTi}ZRR=^;{CQ@+oa zXFk91xg^jprRMy8&;EYq*Z3`E^HvV>qQ^|NMJ0UxxcQqVntOG>lw)3o=Zm|7l^V^V zyasrzy6>~aO>ya?ek_}B%MlK}+0x&8(M-GiSEq;kW@Bb9K`E5sO;;>Jt7IwjVg$*7 z4ZZuKd7j!}&zj}=?D>96fA>Z!f$o%f;Gfn6#aJt3;eW*$()Vk^;i2;!Qk&r`kigy% zSpFWi5}`MP`n$QnRg-Q;Db?rBv)4J*rVk}j47c>QFBT<6WkV&?dvxJFUC+H9PtW%7 z%lCreh&;Z;J2kJs8}G|2jh{V#I-7IIoQ@SUOT6>hn+d$<3xXM$2fjlLFk|l!1LSFe z?-2d|y51|&oJD5mdap=xBDqOPn3d`4N(G-QnK`{m@y^aH^rjW3Bur0)Q#P-~`+TXz z1$o((NP&MrlIATb%qzk>m*S#X-m=_c54p|GE)^D}O^vldPn0YvNegCAPneUK)U`g+ z*F#{mz9zzwC|X|^kvXl6C_FN!H4^E)lSEMjPq)Mi!hXE_g9?QTg9?X=fQp1NKt)4| zPzqEsR4UYBs0=6%R4!Bjln<&5ssd^yR29@3sI^e*pf*6&Le)W$`+BHGs3xdps6$Xk zq1vHNL3Ki%h6+7^cc)NPcl1O5)25-JKR2Fe7bK&3!sKovld`wDOkR5esBR0Gs*s8*;GP^X|yLxmqg z`k+#v=9d=Kh8lAjW$LAdanoeRQ$9<7z&pSC0v22uy}@+IY^cwvCB%DjbHURpOH%wp0ZT-}Jm z@6yN5!be1*X3d)H@l38{;dt=G7-r!ykfsukkeuu&EOgMSoYrqNe!veKS&?_hl#oUE zPn{wSGio_Fm5t5ho<=*}AFXa!G=BfxG7qN|VQ?2bJo=16w;2zcJ`JI}(&Ootd3-c8 zbeqjUn3U$J2rUbo1)0hREs>FAO4SU1-iTDj@!%40KK%K>Ic!eB9tU|}200Pt*&q+U zoP|o^@OWsXrFiuGlAb<~p~p*WEj>mn}m zbOpN5)7aB29wk6es-LsK$tW)m{#W|rCyD-I1OsgOpP|cyTydAlLNa#Ch4^zIt*nV4 zHMH(qz}EUKqW{JJ3@E>zf6;i~#s7MmpIJ)A40f)+HQ4#|{_E*}HTF#UAC3cl)n8x; zHwfK-_{`L=`qTXz{ukFg&wADB8*W_l`o?qa*WESu+wmkgjt#yBS0-V8=rgrg&i-xw6kf~%dhNybyzJ{ z`p385b$rqH(8X7vdL_*+UyReqPjG9W)?p1ld~i@Z)tu(VNtQ~+LF?;@@2~_ zDpy>!7@uX%IJ^DtR$jO2`u}wP|I_jR%jF+GB_T0s>a^tPGiIjDnmq^i6UHwS5bS;~JqAr1P$Jkj}e0K-wR4f^?=Od>qftib6p;Lkb7! ztS1trGads-XF}27Ku`qf+{*^iKEVyrSy3`L1WW}l2GhX^Fax{<%mwKz$_LUJTm?8B ztODr`_F9mx>#GLoY^w&O&nwh|mxFcSD6k$hfQ{f4U=uhRtU>vW0h=L5fi2)zuoa{i ztZm?UupOjLLpSg4H0^eGNDVtOcoE)PW1ZdXU;cBZ%(> z2~8lal$yco!4@zG4d4(M47P!Nz!P8yNbRjJ*a`UpFyuJe1sD#7f+N9xAngGz0;3^^ zfhKSO=mrOpJvazV2g5-RI2fe1Jp`n-eKF{Rc?7r;yaZee4h1)Wkzg%29NY$u02{$e z!QJ3Uum!vfJPKY8wu7Ui7B4u# z2+#!@Kn;um-JlJO2NS^rFcnM$bHOCA44ev9fz!Zs;B>GCoB?hDXM*)$3b+HD4K{;w zz(Zgv*apr6Pk;--PH+(z@>jGcFaq>~QD8o30t>)Ia5b0;24MhM42FO-j^P7KLN4Tf zB!m6IDliOO2Zn<+;Kkq;FaoRxhk`r65nwZT8Q2EKfG0pF7}AdN0>i-sa3q)yn!q3o zREb~+m<4y&{lSng;0_E2onSN=WI($D`+;ZT zSV8vS8nOqg$vztCA$xEe*@KN_9)t9dIoLwx;88Lc(Lc!?JVoZ9@FmPm=$~LeFcRz! zMv=J<Q5+9{LF_j2@3fSw$-<3wBYyXU)ny!Z3F zqjOk#Xnv=M=5u@a=qp&hxPAq5&-K)9bvM*@W6=UAo&3$wR92qUhAC~7ozx;B|9ahJvGntJsXypx zpgy7Nsb6&Kc^jj2QvcA+3t3(0>8E<+`qBWu)Nd&LDkI(xrwenT=lv>ywLgAN#?wLL zErpy8H@sg>VdY5UD)moluQZlY`=jzLV)@bg47o}5*BMW7Dog^~5bp!L-v+j`1eV7F zgh=_N^5y-6*Y^}wUV(KP=w8o%5?lT2`AlMMfzLb1tex^a<9kwwgXcM(^|9r5^h4e0UB zVrk*!Hl5{`hnvdGdAPG!4e)Y1bGX!tcx%zaO=ES-!{u$3hnvXq6c|>|Iw)kls%IMK zpyldyJHxN1JT7GEEybup60bQu{ww`?;dMfNQ7t_0}}U@f>0+yL$bYr$qP6zQ4(Zi9RuxEss|=`7<4@F?VLl9ApZupKhZzo)?K zK;cw8`^*lV`2<6ZgiK{mXFefd6l9u%MDS*i&Vc%Y3S=5P=`4uOhLRy~2GhVhzzmT3 zZ2|ZcSOGo?(isDl+#1NYf&$WcA+P~5oneGR4h3r=KLl^jfN9{nUr2 z+yl}X)ELkJ*$alF{OIf{266#NXHnxo8{}Lt5^{eq5poJB!hIZ=3b_ z8Mqeqk>DZ7Pk?P8&EX=<2Y@Fa&jAJaiv~I&F9qq0ZWI{u9qq*sF64n=IAme2SYmf+@Fqkhd>U8d>1$pOar6AyTJ_DUksWc z-v;^+t_5^MUIpgDJ_1aEypZf6Ujn8>UIco;8ZrmhfmPrpuo|obE8u=8SPMCw>>&>W zw?U@WUM=ENz(&Zw2X}*8!4_~Ccof_SR>R+LupRPMWDj{XcnY!y6uyraUIN0wS3m<; z4~k$T=mz(Kso-m14g8M)GaxSpX>b1tSOEEDa1Hn(xDos_*Z|%G*23SV;6BLrg00}y zU^?<4gU2DS0GlAY!4AlO0IML|K;egYp$b?F*$#$5UJceE+>u};*a=PrL-6wvK9KK&=#z>1+?~nBDL!9ku`!A3J*=F# z-pl$3*XObMl-RUMan2leh$D-iTM7DKEFujw8qGSFZxViw_ko% zKr0j4H<6ocRz4JOEJ}y!mY*AV*nG~{!sMUKDPI1W2d=08x_JSsUv5sHyC-uxyP!KK zsE5&-jP^TA*f_}7VVTSw*JrVGa6Lcm()E-kuIK6F`aBjl*Dqyt!1YA|;rLiP;O6|K zhU@8b7~97qWSQ>x)>Kay>s`()CpCy1qMJA8QlboOX!1oALnjW&U!bJ*L;Mr~Ntk z($6*WSl;>B5I-^G=L`IljPFtS$sE`7`qK5Z9^iWVuj_f6;O2#FZOHfPJYIfAz}qfA zd*Yv`;b$4TIqmDHP189G>G|m*KcC_!nEd=DleGta?!!+K>0C1wrAc|@dvM;4xt^bP z@^_g_+4#cGR+g~x;pZdytX=VQ3Z5SQe1S`JhCydq`7F=;93`KPH~id)pH%YmBz}6y z&lGrj<>x^BbdsNc@KE`#iJubE*&*eD`ZwQ!QIFU4g{+SGc@O>9&*AtI=KD<=`}A{a+JBPFeQ|p_3kb9) zInbW=t2}n@o=T@%rt`>5HWu)`H6LpO$L~P%z%iJcm!h4~Xi8^Nw4$assD8P5Pxmy6 z>g7OsJ@0frN1rApzx-^A&op$FNV(*>6dpStt&Mqc0i?3DhKUm6>Deem;A z`s5p(0aE&Wh*3We2<4NT1^6=85EpKULung8X{& zn1EdZowqE&sx}Jd1;tAw3a{tWK}&W#9hw}%bvn7!{hzK~J;PI_o6*&CbX%-WX5REZ z4<8KgB%41@(Fyx17+l}QicP5(Cmz(&pBges`f8NgGh7}j{nyPoyVKv(T$jWIuG87! z_up|nFRN~T|JL1mB5pCe)zuR`{nm#zEm&h-TJ`$arUT}?js`D1t$lY-G#>D_3>8F0+By>z1eXSb})ayDjCYKHeR>kZ2I|U^UJwcY(6sR^`A9e_me*?y);7I zp&_{80t&Bdx$=k7pTmGO8b+sc(w6A!%kXf2X zOP zU*P=kao+~*vXAZvt2k|kz3cY4Bll_}d_@oJzZ4g4H(mK%>tnUrgZLWO+=-XMK6}r1 zKRl#q|5*KXmL(MSUtM|mu&vtrX>V&IUK|Sh*Mh5Ek7zd?Y-wI}05>qXUx}5Ck7=V4 z-|KvT1^m~(;~N}ZuPsY`BKp>EAZL7iV${a%+MxyWFW1_Tz9#QKFTLa`?an3ZLaIK- zo%I>7R*hfZpndaj)|=aQ<94O0&wpFm_Ze-|bq|ht`;}n`Z^muQ^PkmL6x9xC?=uqq zkI%m7oks13l-c_}6_6iy)aVBJdCk0NiOKi11^&0DJ#*&^+H13yMg4Z*1XXDJJb2s} zJG8xf<8GL+|4T)vE!fpCIs>{^?Ov^{pHW`! zxaU8)V4t?~#RYF(vX{!Q;L!bd?9)oNeYRohGXqtj`r^zV2fwLZbl2l|yl)zz3gQ2J z^vX?dYNZA5?ilksq%ULDJay<>+VS;qC-d%?kpAGKG55Zu-Td|H>VJF*`|1tL(nr0m z3Dv{C`0|Mh5&!$6s_uDP%f0L5ch{BT=J=L=Nmuo6(XJmmf6P_+DDUdWu0odaCn=-@RhLcF*G2D=JT-{ikmeS3JF6TearrEZ5s8k4DEO z?|1CijtvYO6PG?-6_TgS8945M_Wh_W(c!BuL3o4zoRxJz8!|jBZbbbMRcK9Uy0+$k zR%v};Tb>=aj8$Ew-vj0cHa5)l z&li4nv>#z3o6fc>F6(R>#buqfFTKay>#Vw(%Q{p0a9O9}FRjeI&b9?y)*1ctyUbo^ z#uHrDS#u4Sb+!!Rvd*ek-eLZA)~(>O&K8NwI(;V&Gxs{fw{lr$w3o{|-D9|{v*q|9 z=3i&VpSi3vH=oNoJ7c)4v*I5InSY&C&vRL)a3hy>cFyLq&Wd4v|9<*DIl%MdXWNrp z*4es>%Q};1b6IEOWn9)-i}p$FMCaO9xUAE67ngOW=W$tQqsC>OwL`e9Q~11vg|D;q zWiIQq-NR*_;iX*G>6^}FolWDotg}Yovd*>!j0bphRuywur(q(Obv7M;i@DdCv5Ct% zh2L;lXZ59A)+xU8CiAbe>25CTOudrJI@?BYS!c#4`79b34p(^tr4ox)@;>#X{2 zFY~WcXyS4gg*Gh$c^R02)9#laB)F%s&RCvs@EMXO9Xv983i1 ztUCpa1k*q|!(9y0*{ug04Hkf7Kp#kJ?=o;KSOJa$t3WK9=-5HPvWc-QlgpXVkU7x^ z((;OyR%D#*WnaA#ateysrI9(AS!~T!SnSCmKLsAXl)NUJTU?V{=_|%+EC&wAKBvTQ zUnvULR7y}q!Zldb(RtN1Mc#_C%pBa9NG|oKMXO{HAetoiJOBK_HGr z994m!g|u+ozf5uP`laqB)ApO8SmU*3ug!9q0#h&X@Vs-<8d z6)zd%viNrw$zSh>ewBjE=*NqRB;OO|79NArWnyc9{XfRLh0tg>88i39K>K~FTj=9* zlW~`QOMrhe-<{+poYj8fv~%0P(aZi&ukeRX@9Dp{{o^ywZ9i$&x$Ql3&TYSF!MW`Z zFY0L@SbqDTaSI^OSM;>s-7Eh; zNImU)=YN>k)4q57`|anp|Ipdfen+qPuXpvd?;XBbIk$aDQcwHd=?_lsX&+cW`zzvw zzd_NXxBo!<=^OFx8j8kk{dpO`4M6kxnV$dq?SV7@_P}F(7Zl}Y7I_N1o}`Lwe6b(5 zPvD{rwni-Mi>olsYCS9%S63vImz3awZ2d~Db$#_qEWEmra8sY@rGBBfWU80$EP$oA z6yAhcA#=;UC6%e(5?r;68;`TS3B~0_6nW$?L!a&uMh2Lsv3rhTD11()^D9enDM4CZ zp*OyiZVDltklm;I?vD8>d8K8^xEfiw9w|!nW|c2l;w{lr(!#`?+Pr}x*skfPho#}7>4rkOER!{j!#IFG6pM#5>HmZH+) z0xy~lO2NlUBmo!R!w4~a5#S;r74NKqrlR?j1~#E zqV1v{^E?R%J{7mB3r|vr@f6nGl)^blvq-;-#gj@+S@^2YEZn-EH>I)+m(VQA^LP_- zGfRY@`s&)W;x2o^N?{}w;THVjBD(sXUujc{lt04S$C<1ms3Za`7G{>@(Qgeb5@wK1 zK>fZ;q4OZ=&T)j=Kqmg-foe?`p1q$?=w;?d=s3aH%k72tWK#K zuuo_Dd0t-I;XEatIXUDVx3BT`)K&cb(5tek;CPjtX`=W)vwvF&%uY&An=|j4#Cg*f zCe1@E1F&xzYr>6Jv9X3l@$+U+pFPcCD9iO4meJ3;7>aY4kX2k zG(%pgL5wp@C;QB@@ui04fT6Ou94^YdMIJ9MmC3=_;4~B?w36i*qYSuvo-VY{&h=*J z2gHF<#86gJX~PMm0%UW7#C;U^1NQs{>OC}ERr2HZAoANhrE=-EXSexN@qXt zW|kU?P<-Sa=R&x5AHTv-;4NBGmK$eC(ha zx&|)=6yL zA)ssn$^r9ENv6Na1!nC`fu07GPSJkKEe8ozi|Zi8t#VT3b54UDMjzZs_m?9FuYKgk255)){Z1B!EJ0S2@MUTf+I{J3~42iY^Pk@RDypn>$Z?;dK(w&!Q9O%r_VfrQRj9 zm^*9D@VU5m{qzn;`W4|&|C%)uGd&f=GAT~97-9{xGV^IPr&TOQp?q&ik+*<4$AJD* zDh)G>i}1rcSkK289uO~PN zj^cL`{~EWt8#-yB^L;vZKiAVc-&I2Y{=CG_HT-bde&wT&SU&#{p%+Gt`z-8!u=oK9D;)B zh9i8|qYu85bwlM1SNIF@&&Rmt!G}3lZ)!VDI`^t7#yYs)_0W-r4BYw`|5yLSjof}d z{VUza``teS_it}LzIlZ3>E`y$^bNb7PgnS>9%Me|_7#M=M}B+6AY5}~=@Iryxrc|< z2U|aE`yQX)Ud4ST<2QNNIM1)H_dh9czZUM#rfAJdN`Eh+N8Wqh=xtwKqr3bM5xq46 ziHs0G75^rl7B7$nNta8}k|epM8PYr{Q_7dhq#LDm(o52K;|ybnX`<xBg@uVvDqmx4CTTHlJ;??RncPwga|y+i6>{eXxCkJ;|PJFR?#kKVbjD z{*67@agk$`W1Pd`a69HWN*y;j>Kq?AesWys9O{g5YR*jOz0PLmJI;%gC?!r&m1HGb zDN(j6JC(1MQEHr;r53Ae)O*xA^mk`Dyuid8gbae=47pV@!R` z1I@$D2D95d)tq9UXHGZ&*6cMGm`lwo%&X07&3`oCZQf+wYJSSR!@SG<8p`N>^Oxoy z%@>%E#Fv%TcfQ`>on^kYp!*bb-lID`h@jq>uV@8yKSni&{l4{-S(#K zsO?kRNn5CWihZX28oSqCZ-36d(|*6>MaOH7zdFV{W1Z#BRn8locR3$%KH+@X`H}M{ zr(2n=-E+{*1uZ&+Ag;3vUl2lwud-E9bt}eM~>rB zN4=xL(dgLWC|3Wbrn#25e(zfE65RM~7SbOtR-hKwh-<}l$j4{mBuSJ^l1);iJLM)YV>)8`jajk$+4896NlUBcdyB(59(AzZ zcCW3;_K_{d`Mgr44$$b!-iS`HiTUDf;#}!Z#&3Ub9%`SAT(;4*ovoGs_e@5vv@pPBw{GMJ;$18=qb(X!rhx8**|Cd)&Xtw{G1 zme(v#Sf8>!Ykk4G)A|Zp(_ZV_)`M1|ipTjo@k8+wv0dyVg-QdYLQ9ctne8!KgKdyf zuQsY*so&yL+4QAb129)wfd0S1bf4)_YnFYf{Z9Kv`zZw$wcP$=#~9~$=OpK3r|h&k zo#>ef&S_5A*WT4*h?-fG=web5?ii?toJeQ3Mg zwNkrDTd(cWI;pR<;PaJ0KQTf~6qkra;%afbcwGEWRHX!|SSpupmTIK?rOncl(zDVI zX`i%TdPn+9`Vy(T#3&gx<4ofsW4>{V>XBE_@q76WUla7M6;Kr3;N?jS0s6#vSHY%vYnw@3hRb z=2&mBzH1$6dk5p(<@QN-hy5=5k9Nf|({YPqqod97Pe+xr#<|zo?wp_;R63N+YJ_W& zYdLz-vl!FAb46+~+H5UdyGwgg`+>?Ag}V|+6K@u`if@UxqcmTZE;icH9`7}NVw@sZ z$#)|E5$0*;T#VVP%>ym*mJGDVm6lq|E=wHh@H*=Q*5NkImTSA&mS8Wn|Iz-k{h0kH z`me_%v#60Q&6jO-9QK^vw4y z^$bg%V{W_D8V?vhGJa|7GzQB<I@vXz-+>J5|R>GB$O042krYZwfk87!`!gVwH>Yvb0 zKhVC^1Tl!+mk=t3i+0g1E)ok-e~*hD=ox}EQBtL8QU?0PBhq`)r_wNEtTESEY}{!) zXdH&Q$tlm0uaU2nZF;Bg5#KD5JoRAX43nd&p3BE|AzI&P$eHLi%O*mBYB(hsq%&Ll@g@B ztnO7OxQwnD7}qztHfe%8h}|QxUvik9G#xXYFpV;s%t`1^FPJYxyQ;E|wk@>PImRl_ zC?B~_U=7kw8?PC)+qA!6E(v0Hj0_UTBfr;U9M~&P5ftC_A~YWF_g_Cmy!qDA^qiZ(7lJ$_)EC^yR&npRp4 zTgTaAY`5C(usvY=i|sk|wk&&@{U-Z;&S#yUJ42NS~^6~ykC2^B9E4Wdz8A+8sPNimWc?PsBMQW|HPWU9nia|_0rdrZ%o zcABm*$6^&Q%Y3D|(%fYJ!hF&^$TAAEzQZyLEwjn`oi)N1ZIf+Pwtn^$`zrfq_8hdB zq0Vs_Q&uYLl>3#3m8X?GN~~&AUFtM-wOXxiR3BAeQa?~bU1MAYu5!$+H@lv69ddQL z3aA{agV=o+{lul>tD=mR?TymA#=)i-(-gFW4AUO#Tef4iJs43waQ^5Vq+FtG)?Oli zwfytGIpSuCKF8Dvqe#hs-05qGWGO{TMH}=;xl)1Tld6nsjBAbSjMc^s#v0>Btd_PI z>x|os^~MJDo*l*}<8EWKaUWJthm5VpqsBJlam*?wj2*^P=vAkUf*c};%3*T293e-_ zBV~geB}dCKvM8Hmo24t|YqB-Pnu_r--MZN7!8*0T>a&(%Oj(JUV4ZaXX1QAH z7OY&iStIQu?FM_4J=z{)7wsmy&92zp_C$L!YBklKW>2>-wrAKq_8M)YR;z8%>aYT@ zN1JNYc4$r7ZhQ}IALfcfn6Zy)ZD?uj+6k=BPhnI&O?A@}Bpk;&T@XXWP%#W6L0vnwTyw7BfVTm@5{DKCuj|!j)oG*Sc_nSR-x}YsD>M zow!Y`7aPPzafjF>?iQQHePWAvNNg34ifx#a+r<+Ye@=;=V!C6oBg5fwY;kPE`g4b4 zw_~59$DJpfr<|vqAxao};7IIgVic32D2Yl6X4A!rM=8KcexsEKNdnx-yRJy;o) zsVlJ~TBmM6&)K4GQybJB>TY$PdPqHrettqdg}xr*3UfucM!KRfJD6OGE76tWN^>oC zdCCx_1=Iw-;Me{gt|VCdOpSLxGhLni#iTL{YIc}qfoCV z)M+B>G!6CXL0y)i9@k)PzXA2P1$EbedfSaUJB0c=j=DO9eQk&oCPhdir6}}V6IT9- z=(TCmV)WVq?CMrxU$;)$AZ?VkNZX_a%+gKRO}02&oo!fQbT~Vmf)a|EDpD~h(Tb?p z6gPI5sY<$%q2ww)r2@0TTBTa4QEHVsrCw=Nnv`axMQOzh(T>$gry{7KYPcGy8q{c2 z#Hi&~lhsr;UCmH)u@9?ItJJj^!)mZ2t5a#!-Gnu33)T^BYP;H@cB;4_8hh4Am%$b7 z5?wZz+m-A}b)~y9T)8eE=FBSBT35BJ##QU8bJe>VT}`fLSBtCF)#hr)4!6@KXrUU- z8wM>}6E&OW){?bUtdBCZT+OFdXjR%;ty-%=FRVikY((#CM$c8^qEe~*`ZRn zL?dW4Mo=408Im!2replf#n@RPRY_~5YOKv_r8=ozYLuF!W~oJLmD<=kyi*d4p~i4y zq|soEHi|}@(QQmNrebxHfqCC&tT0w#?5)PQTZ=Kb9^-8j#@ZH)v;Eb9>JSy*&lG~$ zTos0W$4E<*CB|a1D3(N=Ris%KV{KbtDZ`3yjb)u>gJq*-3w9w5mK~PeSl1lFy8gK3 zgeA-tj&qAJXE^$_i2j_4okq2@9<8Or8IHD*iuSM$ZJ{3Z-=Tz~=ZUCkA8NNAHQJ$u zqyAD+XVs{u7Sv5R>LV3(P>phLq0Mcu}GTi$*jWP~w0lm^YNbgusLp16VPR;~Nd<09FEt zXGU{!Jk?*XSo^zrTZ&$>?Y*VF1<@MJ5Ss*F0lgN5)}U1PI8>w3FhI=wzH9F@lR>Tb z^E{vD`Fx%~9yDj4vtQO;d+oK?T6^u6srmjRQko=54*bRAlC&Ek{VV0q?|vLY@|dYF zjFJ8@>h<$?+ZMcj{u2M~YxCDM-*a2@&3EPBa`WAH-=pOJ;MV+R_3r%J@6In@RF{9( zJ*#iMEIT`^zyjT|u<`OYE-&7g_#3xBw()iTedWehgzcLSZu~nBk8gaRhi`5C9m4LG zw>G}X!@u)z@$I+x2}S~AZ-pc+usNh()Xl9+#Pv&d+i06hk}_HrvHP{N{vlmE?ldZ#UY3roM-IJWC}0mrMvb$Uy`M`_E@P>4G5ctul^jE2 z#gLb0*kfg=h#7z5paHLTH?hSXeG-bvdmLF>>~gi_d5Q}kO~&=*%X?~E+P-{GSe^0$ zB_8+ySjc-^Ztc`H>Zsm|A&QJ<;sqhq$ZH^c=jQ8W7y)@(DfF^e#&E=X(|I)VYI6&C zhKWWtz0|Vpi5xth=a_Eg$fcLX?14lM9?x@J%5&sxrO?Z6O=RHFJVTKMBAZ@n+4YGW zJRUjxONj2HCv)rs3G*fCYaM|0>~2Lg`x1|>Yu1-Z#eYH%^oF*-PvTmVdP7en-(F0< z{UQ0bBl-4J^6k;&+e7rWrc5$I^yX!q0vkOP#HU%)r<=dQi{Fhb>}JvbT8q=sBD3zV z;_-mQ9vY6v!4xl$hzWmyZg3ecw{8+nJdS!zL=kemp)Nd0-$Z3&3%zT5Z90E3c#;QQ zY`%~5z-q&!bYrQ@aCCUt%cxF!*%|6mCZ#55U1@rV8XI|<3f+~O=4B5j3r$E(;Dv}T z(Y1kFQxm+b@jFTo{i0=o*=Lt1{EiYt=cvpcAL69Cndfvw(&A`JC+`F02GgXDto7$m zCv2g}#q1eAl3Z<_ypKyIX=CEO74H-LdDI(k<#E0V*w`om*S~@H;}ZbkWksCXoZE=y zt?{6qXYg*R^>3u||H8{VQGOrLLl*`l|1fB1 zielTLU9^|o0SUuBo66L({bPBV1c*N(H6aCA6h>Ql$=s?D>$QZrY%BtpDS=9;t-IR4zGV5arn0$1pcY${MuN$FV zA195=qF7PDX7FKD%M@sQ&`b~Q1}<7BJ&TkH{wD}ydlLF=0i9FU>Wy^*Vx$ZN@&5tH z7$K_K%c@|`U|eh?v7^o9!iPGV5^MdgX2AW`c%B0d>_5%>!^ovy=AP~=}l1%Jp3x=`>LkyD5|WJtE>Db8kRwMRnrTd4ZQ{+R@&Fj@W00!mW)Zz0hl z6hK^^uL*8fFH35IWIB&IaMZ9OTv_3x&a|-3MIcuVckE3w7o=Ol%A$fYG11OfoJ0Ue zZ+cQRcXClE2akaJ{9VA(2vLleoyro_BoVF6<$`*InlDpxZsH1!hRsh-S=6L#i`iQ- z{yCS7txZ$>6!`PjqQoW1601astyI9va|CRr*@v2I+4r-l=5JDx@LKFYPE{YxNp$1{ z0m#A-ijG5MM>DO4a>UU#i;?BvAT=}x*cc{_f?DRb8cOO+o6D6N^&2HF_OBwe*CuOw zRaK!zD4OhADxeV>uk zTgExrZE)4&HB3@SwTZ-?!j6FW2We>xY^Ms}9G9R-dZNOBWZ_vZD)XP z#L2-9ba#Rbsfbe#)_x7~qns1I8*w4mzZ3CtLj1ZU;_4vh5`lOEtxf1SA=HRIi`iCA zGnb&2pL78q58#Gcc0(#!ZCp}P22jfCt_@V-8(iTKr5vI{bibu%yb0sZBWf{nDM8p8 zqDD4d5HQpwhd$($lO`k7YFS325XUruTZlN-%fdqQiGFPBq~5e}vwHD2gxi%#-2DIG z#4vI>Fk$F;*)Ms|I0Y00DNI%nwNf){SHm4|NKKm7SCfZ=&Ie*r_Ab1MDOLPxDdZijG6y*%DCyCL&Swn^1ff zLHCPD3y}aRJ}$EtvmYlE9}!D5wg`P0BChxPr>JP9owt(ua`p*MFPIw1Hm$QD3lg$N zVFI8{R<*0d7y2=HCvPOTo8;iM3i~brHJDgmDRUfBXeUS4$|=KY>PM3we?((aCj^%fdaO z^tO=FTg*13)+GiK>CF+waIZsk5uS^vGgVYaHJlmgjPF}jh>l295uz%*Ecc&QVU5*g zRK)|yDqj4Ywq-2Cc~@8NDl4G+_L&Xi+twX@!x_CU^V8j3jQ)$fR;tZ@IMSB6%XgTI%|DdeY zL`=U?K@K~CnS<53J5WJ!S7WzP>eBk%962u`cM)nV{ubPxA1PWy8oe(b`A<~lW9L&P zddm=Dss7N%YLMDs?AK1mm5JKvVI{|SC44Gf>z^9#&q#Batq{`D^xbRjE0YFG3pT44 zr)0#;AYJ=lYWRbUw49L0_yW&3ub@>K&#oFl;XlY;;Uo;j)yeUNjtyBxhP-Qbsh$xX zu0EzeL zBh;`Z$e-*{*9fPLssHcv=;{#^4wC_r=+O(QN5>c$ za748`s8~nHs*eXa5Uy231^~@rMXwVtnnmTWfKX#|yrUI$ynBGo)9< zl*vY8PUx_b6WXUvWT%b$w!IP@nb7)75G`;-fc54K_I8Q;8a%x(%!e$InvhS7cUbECU(Z&c_k8Rt5V?U8mI6CeTVO05YPZk3QC~VV zU$2RwrPRd3a_C$jVN~Qqen&ngBAS~Mjk<8D;B@8(m-R{)pr%NWaxHY_7oI6TX!L^C zk$XjqJ9-?Q7*}&JCcN4b>uojQY8Eu&;T z6+Dc}Ff!Pu;0~+9Z$+;Zcd>PV(CuSBA_PPkSk0=DitYT022{>jLlGt}#7VRV^>BtW zsANK!7?rN=n(Af`Bl@Gz z2<8d#auzi#!9;o?DVXl1VnmVM)A7bWgH=A_1FeUM)jN;FB!~FUV~r!2ybV~uBvPJ+ z7W(R09N)!n;JahV*aG{({imOG(m3TX+P9oRg6b@+azw%e>uO^&@H|GP zhYNW)$jhebore%92k%1J*3&jQMC&j{C)H*+I!SdIJV(h*wjw#0#%rMF9{8+enL`~d zs*5yI9b2eSo#EI*rQ(Y1Qv6Mi^VYHxXrUpnA24`ZNGCYBZuB6V93o5Dv&43(9QrNZ z>dY;K>|#DqG`9@VdwixXo-5^-Nn~br5GE$ktFG3nNfhKE_qj%yr*>s6nk1<8T$2r z8KT041E%AO2>Beog+7DjHb<+V2E0BT`DkYAHCd{yYM$qv=6`hX9)azWZ}dhk0}Mg` zR`oa|wi4_c`2)t0NU+I4ngJLgA~umaTL3rCL_VhYCyCgFYn*9o;50QHPZG_Sb0p*- zN!ozD&LYc)-$QmzDToZLWL#%#A(+NIXIhWZS9pWdGtW7>>*W3m;msoUT9=C?(N{zf zTV?6>kj*Df&T~omFaVY$>D>Xq0Le{847r;GuFunu_I$p6>|m+Osf<2Z>Y~AJe6FM! zYw|?bTZ|xjpKx|4wn{-Du%K!`@Tq8PVUPIyEUg!cjI7<2Y&i@=(rGYu21q27LSB7~ zNTAVYiG&+z8V&rW!OVnv$Fevtg~Rz<)$dFIOpg5)DnMhuw$`X2wF^~o9;6>s?gT^4 zfpIjE-9A!PKcs0=>tc;UQjVf#DBaIJht|JiocibLbcodHThy^WSK9|Pkd>>rLXAP8 zUMjbDAt|9yV^DU^_*E?TVq~v~p$jY}YO8QY8_`!QLI;&|eC!|)Yrtp-JxFkChKz1t zpH0}19)mT zgE_+kFf<#u7M&iiaNfw3=1^$g=8WQfWw1|3ea_(O(;Z=7Q;e?2JBUFix>uqT?<1)V zxehHSDX>l4n10cW0t8OXDAF+hu{!ien1@5v87Kr*cL!n4XAwfRlA^njYWteaiEO0k z`T&(Hx?fVcZX=s7XLV`&Y$e$t^;o`3Ac3y_g_QB*3J6*(+8gn|U>&i~+O4<>mVOcZr1gvw;*%d)U8OQ9kz0Rn!N0 ziHQ)nm+bu~flD_KXX@8$BK9;Z+}?l$wT9OFmo}G5Ben%nwd48Pt^J@GCWx+jv*lPI zv*F8MgL!k=ZvftE%!O8CJS7!w5t?$Dr`c zihf~Xc;ic*p!mua+}>PJ;5ZqE-a}`0*s!D$>{1qr2=y~EdL;8Hn4HPLu)Po;9^RC; zUmJ)Q@72PNXC<4hO<_ja5K3MdJf;*pi=82oG7bSWi#_@}>;eO|6o$Lavfy57?*ZJ_}GL{s$jhhN`PIjYB;P1j$PVVJ6=E=JpS=ZRrYK)cgL-Vw#ZQably=f{l z9a+=j;Ig?xc&vZdaAbMx>On2)SeIk&0LH`GUI*l6&$F%gryMBmTCu#_TwNed?$Y{f zcqh40SA5u4(&$vjvoi2SVEhWbh&>Olo6!@|(HL|H%nvveTt$~z-@am=yd|qpP z62s1Yys-@2Gto~Wdty1tqgh!TJViCIel*r!0HpjbJlN}i+kiak_5Lq3uz#o#eC;T3 zQU(WQSceSS+=re4*oFpWvY+1A^%h{vf@nKIJeOk0mjE2d(MZTYLj`FT>Z1$}w9Ods zu_&tdvE9&YK6aeHODpO93I3jbGnL6(5&8L2NdhcBWy55>_;6tl7JkFbUV?!*Iezlb z7sl4PjSRHS9^bF^IIj1+-#ma>Thg6_zLn7`w=o8?+a5oFJRa56e4LD8C;RWkXbrtw zwS>P+@q0;bT}qthWY1A5Nk(n%Y)Cd(6#LMY-t<-Ufwztd_b+e4J4szR^aNt!vmONj zj9E^!GX9QnNN;=_nofz&dIZski0O^T^p<|T<%sr~15eMH=K2IxN-~vC@Ld(Z8W{%? zv3h3wowK3p6^D}WY7Uju98=RvD*BcGgj_M+MTL4rzY&W*;h#-iH=VlfkC5gK4gOM! zm_rf2;t>e}nGeKCWvCbTrt@~<8?C>v4y~sSyoqK#q*9!S&8FCHwg@A@>SWHLd%40u zCwsU)Q0-rKM}E`oUc#*eY9({~GdYJC7n&hh@xIq5DJm95hWTL z8oSvCKt6IGD#eIvJ3bwSB%OQF``8GXw?x$zxYj`$2v?ay^^EeNl?BhX*HjXqs z^mG>w{^LaiPdpqNKwwlj^bo^~NiQex(#xx~VSpN?Lwe{K&jfS`FQWp>UxY9(b{sG9 z+)GIy#Y~Pa7DkD^Auq;Z)*@4zMUy`VWg094dJ;ht{$dz%+Z6O2mp1WP^cv5lv5)Rf zYmE0p!Jp+nfMqPbMoJ0)*gn(_XF_*i0(x{D7!zX5JZ-DTIp`Q~Cr+o{;SWl~G# zRss-Z(AnKA8)Ce5E{Q@39QN9sBnT;)eSqqYJGZZvP`Bw!T2O6d#7HK@+v%VRZtlhhWn4SP((41gR-Seu)R{@^%fOXV&VUmPu>x zGyWPrlWq)aA5RT`oMFvI?rh94jh7_tViI5>*kj@IxFBQH%otKkD5 zQycGAnk~aMq>dVF4WgV)9Zf!>DTAfuHf1~*_X1?a!r=g$NM#y4J<61NmQC;InK^uf zs9D0CG6tgd;=y`$J0D|j5(!SF6BS&1g`lUr!~t?Ca5%xGj;3R}V5d1E1Xk8+8aHaj z?$vNLpz~ZDS#}Hqf;KMdPL@wafCd@OdJ&a*=N7BXDpAJCS*pfa+~sloiCA0tUa1zF z(fqkt_IE8dc71vvds$<**;WpqfiVppXt4{!T9*@?=J?YP@^en%bJZD;j?mk))@&g; zP%2uP=VR@J&p^U>H1XA-X9!-Vp}<#_^6_*klj7@~>_3p9t;ux~V!5~rIrU1XUg;Rg zk9h|cHi(NFqL=&FrSwA5gD5i<-ejp1!!XCk-T(kEdj@1Zd8nabau<O2(UGv<pNxoX` z)%Z$dq0{KrnjDfohKw)L+=Ny))cFn?7w_SV&jinJIfBH-`A9s!WvF=2XmnyuiAiZvD;zw~4>Pet0~%4!xpcsQ6D_{ZprWuQMqoTW?;3RO|K0r#kxanVjC}no_0JBUSpT9zNaEC8TUEOweI4%H1+PS zI6*WqGPT&Sl5H$Dq;$@QW#ZEW06aIucq$`=U}O$Ne;b<0(u1_by$I^FVn9d zGOl+48^Dl*e@Ck6C^btR#)1bOrsF{)kJcsjDfb!gu(c3jzq7U1a4+j78KSp|N6Z6dPv;SfQIq+A|yB2R8=6Q9DIn%!o43P1u|IWx?ioWXGgKgh_ioD zJ^OF*KCBeLZQh3uW1v1foX$FFBU1m=2EP2dlSFvK3TpwjqtsDw|D5~P%(g|`OWC%W zuPmtJ0pF>(Phy86bUaoZs`AKEH{|#thrG*HrpwWslZP;0?{`BTkE(KMw>ik8vl233 zwf_(e{r53+1EX00c6tM;#-TuIAb({&n+@i`0$!h9a|DZTlT(*Kr(k}M_5x01IpoMT zLRFtjnlfDi?cr{|qN%scA!TW!;(CL#_2z=sj4f32;=xK? z-CvSTIJD#kO6%FZ3scaSLyw{_44zE$urqqg+kxTbM#UjxX}{-`Z2pOouhfR)%5u+_ zN_~ffm7Ln`PIZhgo?8u^kPV|`j?oJf$T+EeG&THDM%qm7-G_m1*!2v+>X6ziX@~DG zWDL+smzRyJh14hAh6Oj zn4&FoC+3X|b6@z^SO7az;mIcwjK7}91DRI~hup#QmkwFJP-AWo^Gb4s+bUbH%~wu$ zWX!o)nK7qXxnRzEWdbvyb}Y&0z^V zBO?eh(SG3G3K#bY>=TP-@}4d&RwqB)0o0Ur8q1f1NAaq$(aPd#<$8_fDKj*drJSoV zhuU6JF(ilnh;++h&|Y;%evi+#S6lInkV|T?8&dgkylAhMMjk`hTMc6GD% zA?)!X?Nxi*o2`h8Dq72sr23N}^P@k|*b>F7u`!CLS}7!4CTc804yA*~PIgOOV1$yk zSEW)EzB+VJoiVTNOM&R>F${CRC}@|1I}oHBBvo@h2SV(1Y39Q&g7(T4;@LjQn5 z!%_wD(36CVMeRVE&%cH|I@6kX*CRdDj;w)vttV|6a?Q?A&a_@TR}M8JmVX7({R&E8 zx6W-=5!miM>8KnMK6-t?>EFnc?WxI5O14YUf$Q>` z`U>+1e=Depl?C|j>tG*y*-f`ny*Y&H-;s{J0rB(=5b(wO^lFFh)T{CT6j%rP2A5t9 zhdAGXan^CB*I-p~XLNZ%4jj{YOBZ`h#^V@*AalMm$;J5Y}(#HvW zM0c!yIGw=4M+pSG$ya`|%#nc@zT*&Uq^R1cb{6-s=yCF=`19gxT=6yT_?jGcEw}^2 zw2|k5PhGd~#&DpC)&dl|IR3*a@gL^Je>k1xS{e5`q@}+4I^&b#uHwVR2a5-bv3$Io zW7@#?Xbe3_1Q6N5EjoRj22NLw>$%ii_yBN z)>Y~mP)FCZN5OjJgvrDb+|77ROizAf_?*U=!dLVfmpRV{l~|cqjhRts-=+z*i|bhj z{7-0(aVT1aBWI{L>esMNF7;3x)pS%i+ilVDaPWKe3YUo^boK1~L`9xPmomyC3pUtbiECFE?-xN%THbWP z0ezQn+KgkHvGY)@V4VCrIKL-a2NROES>(W--7Nd+y{rv06Ep&)uA*%&aI0O;`OF0k zI*MJ(0YqKMzIGfdqOS{RL1eoCmlhbmjI+g(0vGWlmN7TWyTFR_3)3EgoVKmaMzpKm z*jV8F@>kJD3;1A?N*Ud7;cpn$cv^KBc<&S1+Zz^ zIUob+Qtdb`1=D2QT^|^3fN533Xmvn6gk1&`*trB?HoGASAhIZvd>3+i5kgNo*`l&m zfOn(MI7B-uKb#u=Fa!Ip^u{Ab4)>mPluvSO$HK)hWK$c4JGO;QU@w2l0e_A_=;p}h zNCwe^Zz0@nmqV{2ENO9p;~qz*^Jhm70#JdyYk#c0VjNU)wKBdMdsli+?uQ+FSo>%g zItz0|90C(jeFr|(h8=6u0*)0v_EXpnNTd-xnQi2ig2^Q|m%qZEmm=#>pIF5r2eX6b zZ8aw_3N0UyUOo|&8qk+aycF?P)9?n{aS#oxmV+Tc=~yx;z4dgKvJnQ(hIV&x-1OS2 z46)C2VJi-W=u40Fl;@>qDc`qZJIeE>&B;=3M1d-7UQ5Yq3)qo+C9+S;QVU12Uxe&a zkUcMumQrA4Agck{+ZW_rMEJk`1L`KsDjSp^8bZ_zmQQrFDz{*{*BhUSb;M=d@+F&p z0Why1DIDX($FG^w0*)eNpPkd%xJohGU62p~jty$(_us6Wz0*XX-+d(SK;a%8K zcsx2ArLB@?4Hn>P2^5Es*!8o=L8Lt%+9$XF7hXMY$PfOSqL!XWJ7vt=LWX=t`FRc) zVR}746K>ergg2O+E=+)1OR`jl%MrB~oM}fspa3JaqTh7Q#4uNd=Av-eX zOp^Hq$7{mMsP>G?stB!+85PH>J+ZY@%qqTJC_9j~OzX9`XGDID#P%^ptTMWR)1nGn z0nCcHH?bXxC?Q&ra2$f4Hfk-$VGaU)E8Adso}*g15Ksfzvnw#^K*iCEdNQ&r4VP$L zMZCRyVtVu(k2;`EL_W$j7P)}5r{$P@Kl%BhH-Z`CVvpf^uqNPx8AWF09pr2uQyD#g zSnIVX0UW)&y;OC&?5M*LP4CDAV4~4*VGN|i=CE{-hjyxbh1M=4V|PPFW#qT`faWMZ zIInd#ZJLtQbB)FU$luN9c)n~Nvv8igE5k}rB1Yp8d|KP9Kms?rI7;LA5&(&O1cR#7 zvsZPbeSz&nV1^Oyt5&Y=$f%^YBVIdg-#FGv6tUBIY??aetk{bRzrg(dJ!5ac_Or#b zYlit@_t3z^%(i8q@Z6esy4Ryfi{TXPt*LdSV%*?6soL;*$klkD1 zo`klpl%KOTLC7n`O`cw5bd#Q;^no6*L5iVTsN|D3!N^=j6 zEhooG>w-Lo-RdIk-$Y5W6{gs!tsYV$M+M*uM`|_p=HG6=Q0T| zId~Bgnml189W_V4XH@iSUBh7g=^SpoodAykhFY%!86tl}o0{}7)QDbt_Q5^a2h^vm~8rV(-{ji0fcz$rlC+r_vUCPujqHZ9N)x^?(K>>jS12$}t3P|~e#5r=I={;(D&jCyPrKK(aNPN3&HJGvN>SPH_YyKQ9$0D;?6T`s(+8Pfh8g&>{L$W_U z0;4xX-}PM`PW zo12STo-^0ExOPU`!kD=(X3nQNz8f~sOMy*aDX{4?3ELU<5#S+n-H;LgAK_x*CIv2i zrNE`nBwUAf%Dr*im-0QJm)l&2mTd;T+)*aKaP*tBJ^F35g~i)mUn<4>MK`IrnBrlg zr=4;(U-ISC@q#Us`iRl{0(Bg^su?rLFfq|iWQiTQ#!&a6#fQrhwwLqzY7m^ zWVB~?RNC6BY#o($z-_Ox!&{~Ga_Fxmp@Y`RygZjp=tjcf-;=o>5qY#88)1kkDpK2% zserK=2;7Ok)%d#!e@pPU0DtB9n}a{2{Kv=i@`sNhWC$6;;|Px<96&gL@C3pW2xACi z2!{|3nGO?8m(m8(Viq}!I5qkg`1=k1x;X3t*NT|>a@hpmf9ErT9 za>bCjv1G{Vgo2Sy$o}ffr-x8)K?7P4Klv^w{r0j_39u4fXw zmEv)?7mszT@Yu8l3AZ6`^F4^$ydH6zH?J{wwW1dDC3@bVZiBVD$T$%GguFcy%zs6s zgrcZ#b0)?<#{CWIXWCI&xx@&gORz*dUY`KT3b{I8{nF?o|Bg%ySXnh+Jt@jB1Jhc# zN7JAZUci!{RJgzJm0Dx3C^4#IeES4m0(&u2VOFbOHbhRt(*Sd711awQ{;!);6@TT1 zNizbWI{)vQQ$v4Anp6L%PN;5il0)o@`Bro4G)h@2`;P*^cbikCwD!`?9!6dmfiI4f zE`Cp#Q`e(~q^oxiOoCU#{byX0lf2?dd%7ID8na$n@AefB>Y>^Au7|6~EW(SvvlPz~ z)vab?X(SuI5G;jGWf!87^NX05*G0Ax>wTBk75Rj`J^SH%JDoV!v}HOV)EPN^cB`8O z`0BU`=a~-gKht^!8~$3cJ)#gR{p6}qr?9>w9P~dBSnD!(0(7LE;Bwps%g4eUD${me z@;+{$HRG4v@tuS>J6#J}fX{@WD7~|!eLI?9 zhVqcxD+^0%+(zVQ_S~aZ-Xe0?s3x zUeGzBR^zNWYlsSzY_!c*rgW6sX0~Jc$fMeq{v%*NAMs|z32*fK@}9k3_B2^{u#n4* z5aDTXoC^1*RluiglOH&YDg*Y#W{42>vX&)ePP+JdemW;A;anOI5z5hvux(-|MI^E> zOv(NZC}K5npH-l?Hju9KRue*Spom&A0!&n*D?bdEWZcnbhvlF7+fD@fp_a%Z)j zcgkw3Qx*VugY&Fm5@V-*F6dCgSx0_oK6P3rb+mG$0BG_Qa1wcQPV`iq$o>xSwDUyk zq+Yej51m9^@etKgY4F~SJb+}dGx4-tEta2i79VW#nAEGH`{hUXYF&1H3ui3e=h|Mo zActUqWZ@fY*%ay~0T`2XRfTa;!udkEfZPQ-ryLuE*`1PWQKi7h;Lru}Jxks4{m*`d zK~zE1d6EW2Wry9^LPODT@q=aUT{$w4Ic_q?4W-#|!wz-UNd3{bk5w@YV_D!UQ|?4=@xtljuBWAbq*# z4AyM%%4Qu(3h_Y*Ts<$+gJ|OwaE2WE1muNGl^@uMxRGJ6Jxz=$nNM>1gag@dEN!8v z6>!(A1wWO5d*C%{@^lhUscwyPpS?*h*1GLrr6%2jC*Ipm4-+~1M6**RS>YiJC{7k{ z-FFhj8b!RhG#0-A0|^3II^jtoll;)<^C$Nm+^ZA!zhFfczR7GLPUBh6FHAc=KUmBdk?m&TF3Aa?>*a=>>e10I#QTVyhLq|4O7QeoN zJ@W?Y5nImrM$?OEt(JCr!Y)&=!Sv#H_>R#y7F1}*Xk{MXG&-_l)W`N7AZ6pZ0n&`? zZxW^TEN~DN(h4kap*s%0&%bFEwy8K?C6?t;4d0=*M4QuzT~;_*{70%*omR*8T#SVs zoN-1hE$)mnE3t}7yHzum5e}7(=sAXqC+iEH`WSsh9@c=duiK7&@K{h?p4i9BS4%&~ zj@=$K2?kJ8JN z`po;0n2RM_kzTe2PRKSao&pcrom#eLyImbmE6`(H|WzZ6GnS;`MRy5KgI~{vy zh0GYS-(a|z<|F9YI-ee*a|-Zz;RK@FXvx8ea(u&fID~WIc+*3_q4WX$Nji^!OP%>ipZ_6b#33hJ%u|Sf>2odO*S4^_exLU>40JLdHSsv#2O& z%&BWpo#+~wgQBPzyM&ZVjio6i8gnX_S69>SpfrIlE~Y>x?Nz7fu87RP9M;zvSmN5N zw&;M^Fcf9j1r+_T_4Fm`<=9Z#>qzuC)sOztU*-87Cl94|eq<+N?=UG(7GV?KPxl?t zXJiXfh|JWe$dB_NUc#VP4mCelBQZ${hxjnY@k!Czs1G3RzU_)7}!k%Rx6 zLRAj_gu)HbTNEyngZCpO!Vnh_yXYb6P&4!ho?dwu%xhP*kYUPfoHe4@I6prW-?yzxpE5_AH20hvBCTPJr zcwey>CBvBYhmF`V&S^@h8a;3x$i)ZeHj<40i`BJfv7|&lAo)>xmWBG1A(d4P~=A_U~4gf#uO4$qN%+hl73WmbX-T( zP`hzWUZHO9RYc8QeyK^gyyU2*w)jxslHy$VEC4zH+aHO zl#ngNN^`d%YSY!`?nb25vq={~q;sJy1UMA6k_9EzNlX~c5>Tj!5Wz%t+-BI0L{YC% zg+p`?;nNy}@tvf_Fht@zsWyy00%Y6DUbCq1OQi4(|=>+OgO{s$|G7RSiYQ5bsBw6p;mj{S5nYPGcwkq9J3L;-+|pH|K41 zc-~lh&dGPj4WE2pATMx7e?NjwwHw1?D2EQ-n~t3T(H!l=ll=Ie$mZF<3HL}C;nBTn zhQ5W-W$Y8%23zl3`)bkY0j^-Bv;FF=Y!M2Mf#ILWXBbicp9g*Qze@+(#+q` z2bUe~V-^}*Bt>@^T#1?$kO7s#1^{+wzj770CcX9AB4x(HIIo~5qbPd55Ggduu$3)y ze(P*WNiT&6`A1=oD2)p$Q4Pe|1E4!mViw@xRT(AdJR>@3u-lgSDvY`YyY0$Ykp_uM ztwe6HCMnIrP7)Iak1dQ1cDvN`&XVNyfqZ5MvLXlfS#3uFliM)xfb7QyWD@l+uE9q} zY(gFEb}Hu%b~}jSQj|%3pol$(ngK-XB!L2;RJqa;>e_U#@kX^ECUziT{^Sj0z_X#7 zL}bAK1&6=6ikF5}d|e5TQm&5g?_=2KriNm&b3Q%iruBbopD{F7FD{ z)(z)k>_GFf`83m_BQLn(5WY1h9e}NH$HjR(njnP+H=T$5l{sXuFQhFAPe6THmOW7fct(X}l z6;5?Nst?$`hU}@yQ486*m=5Zh{B$nuAH594dTHF?(g`|Gd^KDC0dGlEu4S(vFRI4? z{ck<SAYRaY^Wv&*Ro;DBFN=3-qX!Ih(*&R(W!^-q^G$6&t5K}SD+{y zvJ|^zHh(VR&nfhLaut8i!IQ*2yR|3DE=QoR!7h*sNZZlIxq(AiMF#U|B({lE)Yr)Z*2ZR^@Y1IoQTD9l($+$41+Z zOzgYf*Zw5kN2l*x!=J0^X%^v0w&e*ddSe@xmz7k)L5O%z$Zz)Fzeh9M$lR zjCTTfjAJ(3E66h(Zs%kYa3XIYr@*H7Vm{3~5Bu-nWKE}n9KON3-Pl513PyI4bKq^-nSSaX`QbmLlYRO+EG=Ll z2gi~W*0?P)`1nj@(IiWQ( zHIonrLqqzt%>zRlJOV8V7~%PP;-gX21@AX%rJu1n{w$Bup}dbenPN|nm0|7%TO$U)PY zogiJ&mcaEnM4#3498|~EmZ^0TQNbs-V0de1ZpAr?GZk`ZDGhc`{}gQG;I$OZ$=&0~ zxb=T%XBdZKt$wIWLFN*UOp>2xs3ij8|J<=_MgZCYP%vK6H_%j_=ZA=|qPfZTqo8rf zVn9ysai#x{(EG1^)s@qG4IER6`l@(+DXjL?bqRVe(mD6*ovVQ%MlN*D@T|d@ppejV@enC8tOJrn@}eK$2nmsVuf@5{S+SI97@3h=!gqv78w#0EqLRL< zB5NTBFbc=c>*Z1eT?;#a2-m@7TCi&qL>j3f`~nG$ZDS|Zh+#<|x|wJ|PND%H&Y=ca zdAYpMI!P-@xI&P_<fI$Yc>! z4qePYsDWVr(fFVaYkx8y5v+X{+5$N=%?J^00#Ue5IilQHU_XG7-OwI7AIT;cA-$m~ zct=l5SPUVV5?`ZWjR`N1O_bzi^8nW1>J)v`WboJ~oz|=@CHolWJ4RSzYvf=iFrvwD z@Gcak+3{CM;}Mf+sKQ-(1xx}DgQqb6B6P^_8$Daqdff`u zS=Ga7gyV>2#Sz*~a0|>!7^|(>%jt@ExT=VwYi#lGGcYSfmUU^px8ztWef0Bki*$M#=+K7{h93t_`gVCw-u0G>Hdx$KhvrBde>nU>%5L*ihlRY;GwIy(f)S-<+ z+mMdJ?3FAkn-CNeF$X8+lS9-B^zG&yHlfXp&N~sWohgz-$3WW3`m^-!kMIKtNrr4a z0|Vq|DBpSpPB%CNEJfVQbrTIC?bHTkL4xte#JLPrGlsd@5V)s7*aeaMkyTXtwc1>~ zHcM1R{Al9BRBT9M$n|w>eTf)rHv#cL(Q+Y8BbR;?`xn1N%fv8DNT)x z1REY&5-4tnEJLNj&}+{F%hRC82~{z!BNx+B8XpFjT#t-~vn1JjSQLUF;3Yi+a&Rdu zk0f6PU=j!shA}M%m*cawlMh0{5lU9^z9!unsYXH%43JU^xqP$zv!0!8^(?MR?ou2( zY|$BFyq;}G{T{28NfHS2se|{5)>(iiLI!LE`N$Zai;%kUHtp0JDx&4AfN*(F;{}~BT@R`6!->1ju$ZM*wL$~xlN(aLU|9Ym6hb|96Y_Ih^)% zGTaEw1n_WwTD0U2{+bmn;w3d=MDWC#@Y9sTQO6#_;lc#nL@{fq3A$-r`_sCUgrYJ@ zLaq8XLahL}uM_H88b1F6p>~sc86gx$+9HwSB$`mw+Gmv~-=7@6kXvYSkSLTKMFp@h z#3&M@MzqD^WMzsNdlp~dj^iZ&hf~{;FQHsJOfnXN`-B0ZWa_ra5kxm3d>i34VKoC2 zS6t`(Z4JH)haAb0%&f8uI8V3Q#A)rjOwc-C6l2#TX9MO!Rh~X|`qxC5I=c0`X=)jk zsqR)i9ho%d?f@mDmy5YKo#~}1_fKXLl}NOV_u)#3RAXtqNb01CfDO07?xZOIo4kv6 zM-krPneZHfZ)u2guU(=$W;0j| zmg+IWc-``@S8G{1u{f-z{uM?y+%vxVJ^3rjq?hOs9i4K)rRQYx=POrG`gBUC$G4>m zx0X|z^N-zd&r0ezANwIVnrd(c# z^gU2en@bmCVFiHwD+G7oJoY&PaRuS2Ujd&69FZtKTr%Y=!a}_%fZO0N~qK|1XORWjjyjPGykZj4WB2QAS#TaP7Ek)}8(HJreSu<3N+f`#f!d>P%&sf|Q8eAd&yo(sySMPURKuv!f5RF-R^o;rQ5mg_5M}YBP zN?+TEBFU(kJc`JWj4I_()bwQ30v<)pO-A{76tyoIwSh;SNR4`kN5xX3p5jqMsZlTT zCGqAOyFclr7#!@Nv0wPO6 zoH^@eiHK(r5lHhNM>*3~@dRo$!ZRrAfmq>yua^CiLm_WQXa_+#k-%^dVd!I9FXt#y z`XflM=h*vLMb*RI9?y$wnxTw1!xLeOyV^?l1?q&2GlJCEtN}s{*=0!M1=V)Gsi;cm*`0;@%M}uczZI!qfZeXn)zc14`goBYi z&Dq{M79%uBO5~W8Zp2-SxMNnFaz!|9_nK37r!;E)8a?z28@*PoU`^vaU`cS zh5gyPK;gNyBXL%4BK71^=({JzMo$;+)r2X9l|+oZFux% zFLuE81ndokVdVn+Iq|omFsxRy_hC8H4`m!euV5E!Jn{n!zTS#sRMl2`L|4Su-{fPp zd`#kgTRJK&MSVEg#$@FxTx+IWSgoAHUfiBsD=mH+Q>#A!1|hkX9??noBD}ZKBkIBz z;l7m~_&El>5x1Z4`>}Og!-~T&!NV9J7&4jAY_I$r6VJoAV;;Xi3*VBscYoN4U!WQu zjk|4!9oS@8wMwseTf1$QqzyaqGdxwR^@{zyRjVHY6pEQ)WET}-{2b7izP5EH-qOOJ z{VfG|yy7ydZqimeozgs{h)mJHlH#Xsq?-m45|KgQa!~p4^{ajHrAHcYL>>DJ8v6}U zPGC10o;1uCC=r#W;5XK&cw4VpMVR0&sQr4?YTPe)5!43n)}{FQ%;~_1lzmCFL&?4) z?9%qS(kfh@{mq}=vCoxOI|^y4!`Mp_Kx|JShPV_2#O>5`ABT95)N=w~u^JlG zz3CKz9)py$cxT2_NWiinb10KEmaUAb7UFp8GAK{n4!%SLUJ)$d0k{soj)$ZCp#2)! z0zR!8^^qLHeX!~|z3KExwZwCO1A;{_)nZ?r9lf2RbG6tIT?#NTQoty6wBph{B@@4e zL$l(M>dV%lH>Ox)75HV-!t%*X6fzYm&2zYo8I;?n;(#ZH&5A%}UN>({^j^-J#7 zGO6%PhvRBosX_-8jfqHmfzax3l(gH*ZctBJ7o1@ecRuvj$hHMO?>0jW;-cOgU+0MD z?f|~UhhL)7usZl9twwiyFr8+IrJmmA6CI&Xk=r!s*%PAZeDWUGVimS4n(gUbo82RF z=i|DSb)R7yPzQdbMg2=1z~jfRP>K%4P&piYs$***pRFW#lIxRc_3>TQ&N`L@*`mE% ziX!lXQqGY)d`o2_-*Ije6&SC|&jo9!8r;7$rgg!XiSCYI_7Gr4-MD2omtyiM2GH7r zV~AAI%=RbvOPS}*=5Vwj@N@GqiZ@j5iV9c+`UP@)tSEkcIs5!cVLw58&nCh3&cD+( zM(AmF4OWP7CL^0~8W(cK|iSH&qw#Mo$#79 z7!VNfNh9+4c0f1qGaPID#+fglMw^T2>O)56IqV%sVft0kP$p3yxvKrzE7XdyYA)W} zPVt6h)v~9z5!8x)eVJcij~l4_2TRxBgwtoJU@)D?hdYHnzz3Q!3N9s1r0X5qiZEbt zS>d*s6l%m`+sf(n4Z7p@RC){6h{|ttHR+C;*@!NSGM>_QipE<@c1QWdy!JNdCY}P? zwGGoiX#tC!M;z1sfO~TpZqNQ3Co=Y@0e7c5j(^P+z2IexENlH->IMt>vq*mhd_BPV zCBnHodLdmra$egRQMiu%nhLX8JjJ#g2*Wsj!s$KBj>FF}r4DY87Q4OJRdDDF%ViAi z9K#2G*C+BU@Wp9c<4vO%O)q(THt>;y3=}KVx{44rcL49rAGMt!w~-vg%7D~%hORQg zEu?stpX-LodJ5u#tMxF9nt^KgCN{W~DWaM2-d@H?#UA;Mo@ z(#X~=YHj%xB|lZp@2Ixn=ITlEt^@KeXEcKbn4`?|%DO@9zQzVh^?kE)((}Ur+Uj(c z&R0)C6tD|uM853MA0T+RuN6N#wh6OLa}x>1$cxBaGM7X&{R+UpAuqqOf^__^&PMKU zza==XJ1UM9(Vbnb)ig#bj-gtkPnp$G1_`DV%DcvrjGNGQnmT>$xQ+*lkj+^>ej=`+ zDzka^ulpOMU2BP?zJa^Es)VJW#U0JN>(KDtN+(K5>>j>hz(N^pYc6zQo8%*N0BU8E zVK*1!FrCeuZ(pQ-E;d%6vsOZKaKW+rXF_n0X~ln^BVgNhCtQatK+F9YNEH~d+FXjl zc!I>RF)vaY{G;%*8EhO4XKS8a0A(1Mz{>CA3v=l(j9$NZoA+PP?Cb^f%&n&9x#jen zRZ7pfbMS0>DA&(}?3;LS?ra{U&*Z_hA|A}R6u}b@r>{a_R7l&F@X)bs8A99>xotIl z^ItycP5%XY$A3O<%%OVUDG*vfcuYWp{K*|A)PI509$67XNoL zlVl))86;p3lxTvbMrt&u#DFHigi8qoLlO|fMMw;ho5^f0Eg^|RG{bf*wYCRadWuzh z^jq6 ziz4$E6hjW$&Mj^l*eJT&IDinKBQw)8$QwxTKd_BbV$$c6h^xxZCsg`!A83n9V$4-S zL@_wMU&QDM-lYzi7&?Tk;KgR4L;7n6FGyS#7>kzpa+i2F+8roWz^@{8v60ITF3!QV zgM_+}WVY$gb(xQFN;Nhw*ArTDmwWM3H-zgl`P`@vz^@L!pk9~x!-&Tg@mOA$`J;$O zy?7MVW%?r?4~WO)y38L$JRTH}8|yM3jd*MokL0?{KSqahA+8p5)@42~9@u1EPO-Gm zy5$v)(2)hc&C7!WLigLHzVfgDg5Pv-xFTDCm{3@7(%S^=A+i@c=bBo^jfbI)$2slW4&gp*KD)YdY!6XrvZ)x-JB+`b(`uM0ff6(_p%+u)iUiXq(eR^%HDmKi zPLCiw>t*Qmn13KR_F@S)t^5_438Ks< zCI`Im^JH)XK?0h;mQ>}qmQ+Cz#*p>`%soBN1n-?~4_Ri!M@Yf2QW6^G!GE!2N89a` zwhMs^ir12>Q0XnBUx%joHYfTvudSGZlC=k4AVt8dAf_d^T-G@6uaw4LYB%pg(v|b3 zky~!OAq!~)A-5BYDrZOlY#}l%e7P$*D>$;SI5% z{#a;EO#E}_Mov31rf3d_OrZ#uuWcY)#);yBhATG-C4bl}L^p00yIj6W`KYg?W$hEL z;yy*UD9saFd<7T?E}<+?YY-b#cCYWKa?6S2e5h)YKk@Ob!y6YPJf;We3jG7ox#xhN`GP*}9k=!=Aq#!$?-{;(| z?vbq4BOo`!iu~7!$sYT}0s6BHs+ATdfnR!XNgUlyP9N-yGZr3T<{V!9cN+His zL5!+zZpfx!Fb*#pZy{T5#~S*Fm8eFd9ZI0SFaeB{kj;AyjY5h0&c!k2I}C4Vd}5o8 zT^|Gga#>b>LR}|L@ znEmprEL$OzX%4Dy_6+E5ds226!7|YZ5*pSj!wf1kH(j8Xs@V~nHlbnr@W+AjS^_mn zpuA27T}Iy74D1cJX1$@uy*P)ogRc5RI;!Lb4Vk8CXpW9=^(jk%-G_Z@7h|cPlY!41 zdr;EpVR(c*dXdpxhG|3>`Z>xnWA&ae>?{C3Y2EpUFXo~)o4iwrql|lcZp}ASgS4nn zF+JA_B2hoc{1FL7GYu#(r~QOki-{yOtW9!j3JwT6Ga45zS}fZr@0eEbsL9E&RVMo3 z+d02NYZH42JJ9(f28=3fi+ar$RTqRUFNo=)smh!KwjYLUBBacIcCkz3y_mS^+mT>i zj5b(IbLE5iA@g5z9$`K+&{Y%(rMzv0_URyyyyKZg-Ts?xAoS`M`ec zn+%A+Q(xrJZ-mwT;d?|8mO1akEOxoFBl0>)(SNa>5y|d4nI1%AV#Fd@y{HDp!j`Rt zB98}S%<<+7t27Rh{)-?)v^AQ7svyW!+8R%LOHXQ;*ElCRgZQ}k=8o0$eY_Tkmn?mv zZ1cGHuh~v!7jm7bG^Pj_jQ*(ks@ubgQ!J|`Jx=cqyt}3$bFffd(-}|hgCs4=PJB&y z!o9c5q)fw1%2~=L)tly!?36-vY&lVyEBt)6sv`+{uD0GMP(5!;cF+rbz$ih{Z97>c zstQ{1-ft$f*BLUp)5fdP1}?@TA=(~e6E=j<*K4M9d@F=-7N%~@Ick3)W@OsgPL=vB zl`vkVzdQMo%C%MvD~p(9kqx6VVACGN5J}*}7*aNxX%XX)WzjyYa;X^=F;PY4xi2jQ z$69EQv}2eRvXgEltPs#XOHdUi7GjROal;ZzlX%s9C^DUaP>f}KMie*D;$2e*gO^F( ziGxF)TO;hx(HZ-pE4$Wyyx=n=faGalZ_=V=Nk{JU=bDl1%(J#bct0S*&y`Zwn70L1BzOlisj4{ zu7xc?50oAUg+H-8UB>cnn5q?_i~%irPF-ehZ^9jW=;92HhF<_9`b{~`SfiC={nz!I z+U%m=w6fT26QYQa(FkQ%1G;Of4HS-LFD`pH3UZu+Fffo0Nsxw=?kr?B^M~75@zTv# z0agVs?Pi?5;kX5_mKjJtU2G=M_eEz~Z*Vi#uNuP~PTi#US;|FkQvl20!h@{gl<;ovVESZc*ciFz-ORjE9jtkfnx}!YR(!bEAY9aslIpn|=Up_a$>E z37`HgV{844kD6^%kGmmi^%t&TguNzoP(;Qfy8=4Bi(Qi_qZ28r0unsYZ&*xMsL>bRdJHr|Arc7Hbo>+HoV(*^ z8-<-lU+gbM8JKoUzr$Ud?VC2)Y8N z#KJ~deCrhFp8dpi?jAi&l4`18qEgAAo1dWX1QWN$&1U=gm%s;BjN{Xsdrp*Py{%tX z#vDA9qkw3ax}QP?V@DqGz8^iawz@}Kyihn5=M<-6Z!a?cCc2XRd8R^B*Zk#l$Y zoRGVRVe8!O23w91cFzhhe3f&z%~xo7IO~THbgQk*_ze7Xv`cHad$uBUtj7>0cxT{4 z3k{v5dc<{?Vb0QZF{oS~e1I4!u! zvT{_;IV$HIS8xJ8msQ@xZ{qsv%WOHrgV&aEnb*0ejXqN7>Y6%mgzGMpvP({pB0$5I zl$xbUyJ%7n3Q_&v=;)CqT~vz#YO75iHw9l_%PZcW{Eao zvq8VyvP(4e4-RvNG_*Jt<3Oo8#SWX03>zlOXk2a#;+s~t(Jp0xJvTSOxHCceW{fgb z)KoC{<#dkY!T7L)L=t@8b@-;(efK34&dr~{pk%>9s4<~7wP~=H>p|x8TO%t$a02UU zYIt28_4Q>M4ciV@pllZDn%+oe*Mm&jjU`RYa;Pf(q%k<8%(=R;%(;YTDbLzQtzfS4 zw)X=kq6iy|cf9Y{1cGrMl%&=~@#MJVCs}^PD<@liL`Q1Q68Tx{_tjGC@9J%w6mK=& z2?XsPXV8YqS-wJdc70dx^1kmxp!uD^nP|_zGUsM|?KAQHz~+gCo%mh-i}?$ix=(nU zTxmz|G>)SDSozP?zX$~TVvx>V9gCPo=u+M>4RT)ao*jiPq$vZg6mvRk99x!KOvYIZ z9G0moB~V7A^Ou}cB}B2G#o`buLVSzuzBvwGG3W5p9HM;gb9JAtSY0{;nVg$fdrDVA zpeA^HtKl|po>sbAk8kaMyCUj}{qrvdDzpX8U-nNS@2oGc$HRa-J*M-HkaJRFY?S6n znY1J}TJwyWv{t~dN%^rhq<8TI#NlZ}wTLlE>;z$!&8HlQ+*=;i=i)ZqToH$MLH+c6 z@`^?HMU}@l-;TvDh$+5&3T{3tl70XSn4!t zg--0;W1l`otA(NR4UA}63LPesH|uS94Ri^&SZw4ap;(UvZHOG^(E}hGlNfb{guR~1 z*;*Vs%}FZLPVWoC9@1dq2~7sgAiHDXaX^Yw7UhuLLVrb#9e^XW-cwXDAhaG%b+T;3syi7b@dT^-5``B%S zUqjdxN7`KrLj4obU^IJTY?;mDNwsaP&7G+#-22ddenkqoN*|3?lzCKQl?6XFOPIeY>2u zq4{PK^HpfKgg1|mgmkmO$lXNP@YgR`6vAJ3gD9w>>o%DG+2{F=+R+&gsyaa&AkA#! zL6KV-cafib^F;y}4?c$bwOW4CTJp_bDX;C}x9uu1iEsLGvS%|Ml-f<2FZdXlxm{{0 z1^qeshjz;+b2$MQEU1W`@BinWyu-KlZyr@wW1;X$Lnv*DTxHR*ken&WXP7ss7&M=^ z2AmE@mknVOBn;XKhRH|y)@1j#xTcew{`(>`v<2S?W@&D@DlQC=f+CIxD8^RJK68VN z2=x+WY^~*UzxSD&`n_ybDC!MNv(Kd2H%6MBa)#51^KMklzR_xS$tTVmP|dzoYF`%! zxBHE=WmQL^1#$>$<-9PPrc_dde}EWmbcV$cX0P>JMj25cA>#k@L{H8um%^Mbi?~=J$Uq(`IKzSLUu~ zD7JnNBRKIzhPc?TS(n8u=p_C4;-Uic2|3s9OE8}&C2LkOpT%jUUpl!oFIueTNTS9P zb#Vi-3o?VgZIQ%-hy56M)Dz}n)=;L8L@ZUwyd^|Dqm}O9!or>YQ!CEXK1c8g>p&`Z z5VrI$&Sl}^jFE~dQ+Pk$3X3BhKs z`$OB|%E4KLTkoiJW)XJXfZ1t$7&$LBG2;X-2d;$fce;;z-$7liaTGcP`7GM&l3O8a z=_zKu#u$9IzNW~Gr!uHKd0AARWWDjX^*=@%N0r8tF@1sh$R!cIkI}~KO5w@nW_NAx zX=8OYjn|^aF9*1+_dK7GH#eX7t@V7!Z?xX--HbLII-#)L7Z|Zwxek2*cVslZIolT- z8Z3o1Vm$*UBzfZS2<~b~!s25nmrdU%V&ghDfs0(h9kN5}U8n~98cu4+{nhn+iquG zQfdANoinlt`R1UIxvZdediPg?4(*@n7%4?0@VCQ(`wN^)Czh@s-zvL(eE{$F?o;%^ zg6>n{VL+F*Sp(vf?dU?Qdvc%=$tBKOd0c>F5iWFL$o7hiMwHx{PtsK_Qp?Ei(-O_f z4rO1@L^+oBnR5@KANJuQ0m6J>o1uR!Y%sk|(pW5MToZhWuEHh^b~srn z9u=nNTm%{+S;d+Ydb8Ta+|1}HX)4A{*m`M3g~%8I+lqprcSJm_f;}vbcDc^9||<8@u3#7Og~; zDaw3`ab#70RHRG=#@odRWq*OdZQ8reJ?sYU8UA&uY-8r=9|x1uKBW&_Rpzt#7b@S_ zIUd_gJxCS^4&z-9?a)~dHbasKWGd#Viu^L)yqt^kga52bVO}r!UK4y!jjq%_u_)?@ z_8vm1)KvfS~6-n|bp#dS&=thA37nD(}n?w(3rqi8)d0 z*G6XEVrP9t6al^(0`-!3mpjJG9i3rGY7gk#atD6-p`+!A;{Bv#Vto_8ROR>BC4Li> z-}e4~PwwPR_9*4^`qC!;lRNM?s!dBahyWuw=K$i^g0_==rhXQyQ}+4F6qLNU5c5|F zJNQ~*LvT%{aHYJ$?wXT1NpkW`Bkj=5;si0^i9?jzr0H)U?X=Kgey{N7ot#^tj9y_3 zD^zIW7u$v1Xw=qJyRhf1C2PU-C!}Vin@V~FxDrK(azka<6H+_;VL6C@Op$ybUbuAP zC%T2(vDwHcS?PO4DSzdmpIetmMFBMA^6_+wFu~~8>**ju=VoeRg1A{Y>7ik#shrv< z$Vl>DY+t{ofV(7$$*x~%j(DAJbCtOUVBKI^4=qf6hVTdn-8dAqVUK$*N*hAMOp>zt zLPf&D%$Vl|S%Zqq=)+7yoHCvb#+gsk>9LOS&kC@fEDR2zRJm^O) zGVhUHC+*V)oeb=}5`5lr#99S60zyNNHh;us30l2}(1dbS3^yN@h+Q$YEK<>)tC63x z&r`>wn2I>$=PIJgp?YT{vj6W@suH*ct?lJflg4GJTdte%AOFE>$Fbqv4Wy=eA{4QV z(90jNIQi{a=x;ST4_~Y(1oP76%WYWA;<+7!*Cl9!6~11lJ-fWfU6 zJIqISs?ZC@3eA%dl?aE#Z~wnc(po-uj}(;w24xSCg!q3yA2t_TJ^oX~3@X2C+waeD za2U7)I;-FAW~I<3X?9IpKh*p!;#kH>`uJ5X7z^Um!zpwNtR{;AKcK}XJ;B=~L?V=; z=JjwD@r386a|@&x!l_8L^6wSI*LzeU5t){@F|!y>aQt8)`jJ#25B!0Dnj4GBMk}PB`dIuHyY6p>NS9%BHl-lO+*8R1U zL*;rfIkFd%CH*n^6IU3M2m3I&@;voYnB3D3lSVg~{FUE6Qlzc!u((R9dr%1JA)_Ka zgr!_h%2)iSVdvDURAkoE)fDzRd$G5E)i+@8C%+KvB`fS*GWzq)ld7YP`X;<_z>oz< z&|gRb?4q{jB|3L^8t!vjW~GnNN5c~2c=<=DZMedRJ?Z;j;F<1FU`T@P@(W6ee41gZVNOcHgFVYgB{XnFFhZt>fpi z+l_A+ZVs2g*8~rBdIdz2*|bU`*k zhC3PK-Ap-ftVH&m2551sds0@HrwXCNLAJ-E;@!!zUHHnpI;=-hk96e;kj7iwtqJs? zE_Y&WG50GPN-p|J4tfUoO4^#;As0HS-EA^2HI#%D+x14e5wp9q-X=FP@)BRrY8lS0 z`Vff5*>NaU&2+bW?6rBJS|cDL`;Ay4Ol$I>wEQ|OL7Q)}vGFC*ZfJ-#FY;0`d?7oP zbuz%3I(|q_=xR>x3OGDY64c_Lg&SY^3VVX+8fTdc#t5kORrjETwWz|is3Q6LQNQm`KCg5{o zDAoK=CSADs;RJ3noPUc;AGW&wOW7uwf0D76)Nwz}$H19R*Jgt?`R_#LhO@a$qKh^5 zVG|`%m;StYKVB`GAS?JUtVwz-eKhvUdBx7^al5r&Uz7q#A=7{_i$jk0$6sh#{)}mV(R=>(+}fW zHVVg54)_YsG9e)!tB){$!bqu`;3cG|fKY#yekCHmV$ka(hHmrmyrD*rDFTqA%DmMl zuh55u^s^!T7@uB2HiSo8wHe7$?X>UlZ@%h5m6bVT#mZ^ zS~eJpj%Rz4XatlmR~9JE)Jf7qJ>TXHa1C#;wd4&TZ+2m8Y1z=Ju55N+j0#>(>?lUn zB>6#!oBLvP(8laTo(v`DmL1ZiOU`!f%|;IaZdUdesdZyYfW)+H=axSM#98ZEhz+6o zm4p$A{pCPzmSlbEd{AyWa8-5PVDH5k=ay*RIz*;zuB!JqwdZ%m?{#kZPg1dvk%VUi z85BYAYE#0Lx0>%%E2M%Y=N34_py@1=Pu5;8cJ`plzJWCA&VTaqYgS#*wj>_(b@9H) zuYNhmzI~;1+gKV+&3hetC=S-V;5z6t3kvQe#7|%m^_AcXG7`*m2n}CqC-)yz?bh8w z&72Qi!(g)NQzE>jebmP@!m7)xektj5JKkW364Uvr`=asrbWg%`eNqbtYqAaws<0uh zcUB7T%R6oa(wdRfK5J{1zSQLJtF{;(F!GMuIs11E(%j6TID9ouGL>cvW7ojJ7V(Jjaj^2fL48h(=wpsHCF_n6FMki7xylz#YTvI}MEGle}>{*?jBWazN zY}ppGD_W@NCTuq%%u3PLd{NPcWa8yWn4eEWp{|5VWS5^~GZa!=lqZGPDQ7N=^61=h zh5*p9vto7#Z&3JO)C9JlD=TJa*vDr1Bxc1t754dbg$k3D74uBk=RM13R94J$VV{4q ze3G+bc7=UjwtP~vVxABCJZt$($ckwV`}~vTGchaXVA!YL^2yGMX$$*QSw2&SbT*&g=! zqFhxwJu9X$>|pZ?i6x2$F&mJ5zA^C`5>Vg5nE1oPJly38jPOf-L{ zV3PSGfw!0stJh?6i-M`g72II%S8$UV07?;d*V5a}KZvizWPV0DWsWz0uAIUwHf2PIc5f5sL&_-} zV{?;o3a8k-Upa-2VwNfAPH`?&&Zoqgubj__)2*Dc!!vJF&R4{FgK{>CGgUeFiF1T< zwu*BwPE}-%`kJY!56_G9FJ)4=W8yrcoX5rao^s0CWFAw_c5&`k&eP(2RXI&@{y{n0 z#QBVJo)zcMm9tZvk1FRmaXzG+J>uM?oEOA-zjDgv)GSj@QFdf5#Horbms8C=^&vr= zla*6eZSz*;Ocdw!%9$k2tCe$?uP z&ST0c)<4bt$~jS-uPP^780xQ_Q^olVPF3XT^7d2pK_rOGA1G(OIJYS0JaKMR&iUe8 zt(#g!*}KHypAx0cAM4>Vn7x8C^HCk%gpgyP#{sv0 zuDXr%@JWWTP+K|jIx3>?s~HR~)w81K<89p!!u|h-WIs zyXQJM>xsXkG{TJMz8YW5?INYW;7M^u81b@(nZF>eFz;vY;(OCv|EyF;8m6zEw!p~! z@qq;$ca^ZKiTK7ve5c}T9iK&*5AB3q6;VaF-u3A{=AzAD?f@);lz=Z!ZI{{3E~tnm zfH_&dwX$-uvBGx>^lfObX`hbVi@c<>VLwHxQMWzia9J*ADrmXtCLE^k2l}OWt~gBuZISdu!rd^HvgR>Al9Ov zV|x%OXf_26!fLBoy~$qRRaG9@IZ*%V{(H(C#znE|Yyerejy?L8g;f#>$eX%JeJt)g`Zu!eaHkIs9I9-^<<~y7E=kqq-AWsRP)!^ho z(imnAR7nmO6xJ=0ZSZ_H2QT~t97l!e!%7~=cvr3id^kGrVQg{u4$9V9x7x8eGX_-C zAdan5Z%vKHj!GNEgu`E0XOIPxq#-;rI2LdQxembLBL%>zBfoZkZ39V!Z2)hbdShy8 zT|!g?FgX4jzCDl-9els`RE@+54vhq`?3vdtPfx9t9UkqE_?2W@($xLV$Rl;{YmID_ z9*`4}l5G_}FSSQjgB@7>eor3kAI{x-a{h4F?qmcYw_ZE&^wv1fw+1$PQoPMk-j=A_ zKB|np?Su8v(I4K{f~yHv^KI>VytgAtKb*1uwsy~e7iqyzWpwx329)W=`(>NtJsS~! zhD0mE^(79aPbKTUswGCAsW|(ILNJmGa}Bbq#S^t{gN(Xuni9*K&$R^Rk*j3H8+DI~ z=k5e#2*PuM5$HIA-zD<_Ti{pmV|MXwKyqN**Jh`W-;(j)Z+5!SQ1T_`8D^(prnW>b z3glQ~D-9(Vn%!SYQvSjoHCI*G?wl*~Y{elZ1tVoQH=U7jlgd~e#(d@6@_q0SE}s%I zL5q<-REmgjb`M(Jt!XPb%DKC+2e0#i_Z{(VmsVk~B^e_q4DCr23lXRq&L1u*ma^Nv~4B240nN(X)JwE6q3sA6#+Ln5%4Kdvp9oU1zX z%{9y*#&NkLpg5&a;Y}a(g|q5oJ2T{h1zk-xeXwXe94fSkArPIg#ucS^i%Bk9g>7+d zb-S9EPkJq5Pa-rTT3+JkgOLb%Z){%~Rq6bB$2lfoE!AOOu8MX%;{^9{xslsjv}0UR zq5_npIN$t08kc!Off%swLAwp5Sy)?rT9u|fQko{KG}Xnu zrHRZ&g2P2Pj{%)5WwsSli-_2#C(bO?RPa36fUV)TNP!!{<)gCso0 zN_4unwLLqnm7GcUDAhoM>c_CIT5V8zj%Ojkd)#=vBDAv{c5>fiDTV@!u(|k=JGv?vpZJO?3a{sI2DdAt1##_9t6P05OO8`SyCXW$JWwlm2BPcXJ@7PUG$~xfu!3c;|X@w^dhxQe= zNm_fKejLh#O(+yk``r6b0QPkMilV7Z@@RqJZB(}zZwS6Bl6~&u^V3=?Y*c=cG4JP{ z=&9Lz^h|tVdkU4$YXvKKa>t@Q>)lQ78SZ^dRe|>Cj1v{nX(~DQz6DvWo8paV-&8+~ z`o5sucelUOd&WLv<3~o`!5rFC3S~9tu}hk>V)Xp90HqQsgEsJQHRhw=)R=LqF@x)j z>Vrm0#puUXThfqqA6YFq$NNV6G--~sHxPF|`VlL7^+_8|(w+s?ygl58C#yuFz-qv; zG~m@%1BP3#J<@u;fi|9qG~KaC(@~DzhWn?q1CfRslt?>8>M9KYS}&=qFYlz$bo3+e zUDDqDmQiwYK^mKmgW^4}zSDSJkPf<1TEM(-9+=EKDIKz%{+dm=tmaK`8TxUM&jrl( zXhD9)i3M4QHaRTB_rv;`4zY5XHON7UoDcs}u&GK%56Ng`5E_BHyiR;;dpis1Us6^o z?aOPeNIv?Jw2zdR+Ni!kAyo+>h#hUGcU;mp^n?FU@r;{CQL>B^wwtAdQ#yVuB~*TO zrEJYZHMUQ!0$V-Dr?;ve{Z)i2Od6ll)NjvEYXXl_N|5=-FfyeFw^&%jFBepLFWTtA z)e4E+jc@6P$2YzSk4AN)^w1b-S|lXhuN?hQHjQHhck!K1B;g&ecY1rWG1JGL^!0Y^ ztioDI)}wv5!a_B|>%pqIz3YMZ?Eh~w?pR9uzccQCHRGmAGc)4~rv7)v)&IxOxYyH8 z|FdS?WJ(m7aiw(sb7tJ}ltyM;DPd&B6~BHnt`zux%8aYZ^7R=vog)4tGwxr%+dJdd zovmfM?zhdAYp=DOo_+4^8I4E+WFwLKm~2{oCEK_M*X}EM-dD2ISMrpvWQVWhxlDH| z42_w0_Hrr$v(*9LA%XyfE{HFAyS5IjJ)i8sV$=W+u7RGI+Vg{S+vMO!TL(^V$osXo zC*Jwc_t~q3QtK1gr~7l>nCMs^TVb0&Gx#5dI~D1uuz|kYxDi$XQ zAQ&uWvFaZoI$PA>Zz`f+lzsVpU*5Lh&Wh;ylsZU7*dpvy>8^X`t0~$!wmesRKFyO> zdw!hf+S>E!o2j zAq0DW{W;@vAHgm~f^*9Zm2{eOiou`=+vpCWmV#Fvv0*WKLDZ5=pW z67_WZ+|ThzN-!pzJxXCmR5`-g&kkq)VI*@<_pzHt=;I!59bZpv$DN|$QNBY0LgI>cOf zMI2&tH05I*N7%7d#C3?Yn5y88pv@|$r>C~##@h1^=R*elIQW08Mt+j&1)t9>N%mah zpNtIku5d1|U`wt3eiHHKJw|%-JH99B4xB&J+cVHvzlxXObT-?cQ}`Xh(b6;-_Z=GO zd{zIox4F&sY2C&AM5uy;tbR)#)hC0OZO!}jt8?)VIwZU!jK0rjO7rGz_i>kCr%1rP z1s}!RleBKcR(JQrm`yR*;&XQ!dC$$MNXns#&joF~hEs1yARUKYDfWXQq`^8;P6)O)AV?ezjq(%NK^rl@z3qf zaYO~lZttKRObehNXv`F?$$e|#=db94nR2B-nG!^mUW zYjEz-oWJ7${FH6xg{+wuIQ-^4RV8}FX+w8|Z>C(xvz3LSy{mRabFE@deW>P7M&2%? zdb{C%7<+%&bF7^3f7H+)GYU`EHAgps?doH`!d={y-<(x{WW!BzxPB{eX0*|2YYcRZ zj^AsOS%huA?FbxWp*~bHA z@!=D^J6MsHLpDjE|E+nrXs?h3BkikOFWo0yF zXj)l(3m82{NrQGSpdEWjCR-7r9bEU37=lNapFmrQ^R!f_^4+d`|?Kk7~og~De{BQ|8odZoVdwqm zLZiAi-o35NHw{UEGN02|9PL{l+j~X8JJniuulp!l+r;xGPn?;pmGcC7>>U_g=b6Ft zEYCmlRPjKI5=z-65|KhOi=iwqj1ZL3SuQ25hti-;SQ$vlU$8_xQfhzmw&^DHoK&2=`Hb|y&fuAMf!Y7 zYqYkwdqT`IC~L_$0Ws9vqf`It#QM<2XydQe4Q`P^fCVtXjGM_!JUr;~Pm6E3DywyU zqWKqAxr%ERbMbOjE{oe~1~GS6jcDU8B;C%U%gIa}6QZ<}|Qwky@t24YBl+i>;~c_6-fW zQU2WMic-uW`_138m{p`ND6=8z-stVgTo-L? zLXaNZqt=~n=6tS|21q2GK!@FH+UJm*Xd9_--1sa%8;bu%x_6OonYYKW?v{#le{N{u zRu;@M*$n3DF%3!6gP)*PCJTmRqI}5I<7%63!@~3ctaPJI`C>L&1~MT#R>5zEhL^k$9&w>Io`zt6-&O2|7R zZ)<$+oiI+1ZMKc`S4Gty**t7(Zj|aM2wQIvbkO=->8 zRw&<5lB3b6zdWKEl`YIV|Lo|@>O_yNIo53yCK;0xYA2+7#?f16Zj9}IM;fYP`NFKD z5T*7$-u+jNu{yB-t4%Aicf~ZqKa5)BNvzFGhd05L5S2gIETsd`b1sodlDklXW8udX zo36=WsjaVZb53)AC{dWq2?%)?!G}6FS8hb7n@;$+YI=cLe+Qdzv~axyLluE7k97fY zpg9(AVg*mLqs{u%Gn`%KA#e3D!KhHTQA_^|9PowmVe{wD<@%8N7zlr|y@3ug^9FW* zut?Zm#5BjL$#@hoEP-yOUGp!jVyp+f>&?*Ht@TFnG8nL;CrV`YM{(T*p27w5+O-5w zmpHACl4#blL|M|;J=t`H$7w*(!cgs+P?Ci0*t`p9i{!#*BHiIO)g1z5E%x+uW);*F zL}t`%I}B%T1r(VtFnAU)mU0&aqivmx;F;q4OMKxT(SQ2&5Sdyi7qiHarhdV8|fM~Ua1^rrWfx;$> z0owO`}WC#2cfcQ7UKlTR(dTJ zn4${W@h>!6xDG?j-&mi< zxixljZi9sALLJowZL#pTd(<6vi)q@QO=<19!pc|X3Xjs7l073tgvNZFWmFbRw1Gv* zN}FR34nfm=zB%}V@CS!4iV3LSobFIsnER^AG%mMiOdn#w3{K~(Xr!q`W|-|=Fdysj&fdXWTTxa_1wUUj!F}PY)q_?2_Qxla z-fQpLm-D?#>>V zE_OFQI5~yqV1Tmy4qz0`c7%f^!_qipRQK4r;yXDKaUj|of1Z!VA=?pKmmHEheP|gw zZ41Sp_f^?3mGXUb+n~)XYp<{+aYKt%d3(^DjX3$Yme9QjtCwRL$*J2hK~lBjZlQ1Ty22}sKMs^)|L zU)=-q-=7dIDIOrj*4`6ir!SsVQz_693PjkxGI7;|G9B??a+mlN%bhSCpAba4?{hE( z$tCpsZ`uW}d# zj_$o$EgR_ZMwU@!H(D^*4z?`>6VG-e{&0*O+icKLE?8kbZ~L;Oas`gXi^_ac2C9j- zKl2=SagpIc9mg!xZfrs&N5D9Y8Mce-931Q)C}$>jzBESESVdLEeg0I(<#^Pcrxcp= zfkV;>S~8lS6&V11FyTa}R+RIBcbE~vu{5XmUkKLSLOjh`FIv*Nn=SW0;dZ|CQFPTH zBi7qt_pgKNLb&Qa!k)9J5qbhC~k8??;%(uX#u_xHHVoNH#E z^RGJxT;%e0pt)>KZZbcs)BWqxz31iqXqodi=i3RWDI3jOyS(j{w`ne3|4m-c%IlhB ze@%Mz9{;)oW$c4*vwQsOdX$2*zmqn_>zB5?^-Eh`d((CVizML-{&g3O5U&5a%=Syt zmA8KB%4=`B*wu4w8v40&4ft~T*HNy3d~urT$pHZZle5l7^$HDigRBW^08CJn>7SrD8&y@4#1h-8PG#4Lmz| zQVxqAa@l82i`tqSO}Y)!i<~hk@Onv0EZ|V;!fK&jHT?dw@N_ z3&0D0yPv9SwoY457#&7PDxJ+Ui)RTBdOs2tEpFN-HSX`WY9ICynX&#D0UeRBe$R~; z{F^c_gc~8XuMq})`T5fq$ai0eTteM%gJ};=(u%YRrWK`4(xgpVDGMPa@V4W)FYu)D zvNhM1a=2ld&HJ&!-X{uszwei{lr0>ludP0g_I{#Tp`l;MZT-Sg18Nv*dn#2r0cyCs?U+(= z)*s=`IP5)D6F3v+DfL^Qw=uR+!nkI(%rQkWAuUR0Ovdrdk-=GvSIuI))<92Vw#w&c z-4cE_ujRwN_|>ezuVy`dH8pGfyKBkC|C;>H)SqP8n`0afoRPKWa{tfp)QC!cHF1o6 z#{EqF6C`mx*RiT}M5D-UxbJdiR_4_i`sWCPow9kH(gAa)iP<+5e?FZyT=pPW&JVuC z8A(fPOFJ-^byLL{uyuIDFAYwOn| z!L|(~byx;F%x0zgQ0N5f&}r#{ zK32bfv)w?0COaOX4-7ExlNi?o4|0$z@Gpuonh0^l*2}jXL4)F}N2Z}tA^olfSN4qh z{WTrr*37N6{TnW;z2oLhgMzkZEq!|JgiKHOMQmN%sKc?Q*RIaDU+pUMZEytV`|F|zlyL$Y7e^4|)4<2W0`JGi ze-=0u9}mwh0s4t-apLQ{He8F=^`W*d<3L@DY=mT+`KjN2na{S-^dSi-*Nzhi8{bpL zuB?w<<2`%HDNYQJxL~H9^1ZDyhiSIRRKgufwJIO^bb12^s&kXrVd!JG3ds7P&;l zpP6%`HI9ml3Nu0(e`bK&7xw?;czvDfw`SA4d%EwWBOq|BIq`q&X_?8q_ z#m4-Jmb8c}Hdn7Iwj@!JhLW`;rHbu1`@SR+VU|sG9S$CTTd86@fhsmsw-E~3Fkg~- zRk0<8Rk67&RcuKpU>l`Wu_>i&c^l)trj2cm9`P$#v>4S_2W!t~SHYA_u8MX3rtRpN zCSz~Lk=j$EkD6d2HegJ`pI3H&vcBFK;G(|nm&A5gxg85 zUT)`Zi`#i_k*{6^8GQOKpS}~8W2Ikj_uF&*_d9&`8`OtJL#I5A&OH;5V|M@X2Dp1BYMtw(`bb!8sUg`A!Tj2 z8*Pm~y)!w`?iw z#P|@3<;6w_oYBU^s~QKm8%bL@qaPm*#(x^h+a+y=B%|J`zafh88|$UC3q8&f4;5#W<75IHP%AObc^H zzfhdfE>X-QoYBv~tC~^ZkXK2}&*H0}BI9-v;jIQ&1x> zVVIi2(ZnQ0~U2Qaim z+VdT(|D2~QTg$R^=;~KqlYX3n0Ci8w8$S0I;UM*>(t_o(tX7MqZ@9OhUulQan;~6Q z^>dM|!4>Z3!s!>afB$7aAEE+r|BAtIJTe#(puTE4wCpy`^GCS0dFLvSk>52RTFV=H~$HKyy1QZ4N;S)3me}340P`wNe9-$9hg4nd}Ign7`!cC$#ymq*Gnfp z`n67MJE3|h_>BLQeyOYOiGPZ|0l`A zE&a(^{~P5FcQ0qX$PY^w3p3y8VgY@VN@p4!=ZoMb%ro>GB9F`X2#=0uXg8y}q08Ng z+`u#gwJ6QT>x>T>6G5Z}j>jK9{BbDn8EO5(PW>&!1(;EKWKcM_~kA(Y|T0L^o9j79nZ1zB1*-u`B^=ik@_bo zGw_M4?vsm*g^b1uhp&1EWjkY(n2XU4+pK7lLX12C(d_N`HW^qY<{bS4qZ$FZSFAxs z6EgeU+Wj7j1kJ&%sFGKV1BX9mw!zj+I~z)NNWu8FIYcD^%6p2qEQ;0;)ul>|{^$Ig z?PPDTCehWLkF=5&^R{uoU%ihaJS{|0q_Pp+hJ+W2Z)0Hl$8(&I{}d1700!HR$nLd` z&8&MLo7jX23}y^M3psKmmoALgg-|LNG(^O|e!tPieBg=7HQcQ-JiZ`cPgPW|O+N@h zukZ!q4bn45`wAOtJD@dojP~1aq15pKgKptA17;FvEeWEoA0f2ql$%;G7~`2; zScyAsml>bxRqxoE6JoWPc=INAa6oNlrtWBtN}rMSM%Cv$_MEa%>_rIb4`0_>+hJ>% zZgal6zv1pE4m#PwKv1`w#-xxGJ73}V#YoI9o`ZCUzuWS0=^fD*>8vN@+Eal!_*#ox z%?>G}Q8eVlyig0GIg-4lG3$s%is<;3u7KSWGf1;5H7(*|OC!1`aB7L>O2L=F z&Bo!Ep^oS6{4|t8guN#*W3C{f=iG0_@MY z1VlfREFg*tTCwPCp=R!Ic(0~ zG8wwhW$fS5xKYq;8C4LBKdXu$NPkupLhueE1n(w$_0(z}eqb?*zq%acH0LhG^dEvP=CFp@F~jjRcP z`=O5VUH5R`{ef?BM6xJXn-($#p2_yi^iE1bVT|U`6=Ab$BG?Whs^o~(6yrquUBz*Yhd~l$*{Wb1AiRE^LWa6Ht{s@{DkKzp5OB9w;%Vf0hvy8>MV`SJ%}V7-=b6Yeljkm;l|0|$`RZT7E!o z>E5uylV7=JS!q?3rY&1mr4`Q09XEk*0&l!!mRr&)oIPX8oT+YY>}q}G%5Q7hSZ%eY zt2B7w4_e!T!;##(JWkKmO&x$px-5azim8DBPrS5g5t3B=w znEkfi3rbflU0c4UvQ+tz(7bZOEidpaU3T9zeQD)VtQVDr!&;x#u358k-ilSFm6WG9 zd_T|Pr7JwSYbw7Ic*@e1EAJuADs9TjHC3fw`6_j@%G38j(h>hl@(6o=B@N}9yHc+z z54UnLwJ)8lmz9-P(&FF^q|I7!Pvz3ejm71qt0RTEv(%$kt|kP?oT67&f|_swYbs~! ztL{;CU$~?8SY^lD|Gj-+4 zsVgdJgf*2bN>y3htMyd{8>>8}t7fes(b6hun>DM}F0Cvr@Kml?eJ}6iIhDo&jpSmz zTY)8K>s^|l|M$YG(#mk2R?yi?SCvZLXH?NoRxH27bJmo+rE7b0yQKcK(b9WMXDpX8 z%v-VSzA0<;)t+0%t1!7MR+jdw`{a$&m#$vE(&{===fClt&c+{`6>aC399b|m?b;k| z0AM~4YN@sh$Ob~|0U}td<$o(jyG;CnL&YDMB>rP_v=P8Y;1xjEw{x_Sz*^uaU?)(- zktbf4qm34SU@~xeT8?%#a2N0z;LdS5+6JKGJ2~1$;8@`IfK!1NfJ=aK94iOjsokQb z^M4cC9tUdUNUw}hx<*^7d9)Rb*?aL>%e%NexT}~o)+(P$^}d>K;%~)S&KO^=QX+Zv z7fF9YZ~BoKrKGrq)b2%wM$%nNp38_YC6IY8nfFS*>e?!NCHJa+DM!-H{BNWysjZ_% zmE^O!H+8AM7RJYoU?hT%rP@8JJRauEZ&Rvr%2frthf+yO$&`Ajno0ZD-74RWU^kM^ zKVEMSdB{A!6kI0rNLwro*FBQ%t-a~$l%bUNUd!(?LP{x;sg=y`(uS9&ChfG089AA7 zl?nru;gtKg*Ns|Vdwp~I<-}h~o_{Z$zV?xH1eYs`nM|qH@ViEp+QOlF6R%+OnTckhVr1kZe ze;i-ZSJwYG^SiYFL@*m^_pg^;@EPe-k@8!(%IG&1r!YR}5i(MTZ%XHz=AR7h#@_bJ z0gEz9R?+vYc9)*`O({ufrA*0MB;QqF#A$Z8O&nbk`ocp9hhBzJyFJGTU`tT_|=e=;-Mr8SsEsC!g-D%CDd)9$_j_4qs< zo?4y?QW&SrROhqrG1A5{Pt7Ld`^agW_FYocSQo^9o+i80{6}-Nojmd<^cKY2)t}H@ zpzx?a^lHovxkt@hY&O~@~<<-EzEG(W$AsL5k% z8)}KAEh%48US95S#BEr+cKzD5mz+ln^wnA(hnsnvFN;f;YxBx=&QL3~f~6jfZ_Agm zY393vgsBn-;Z|ENO~O|yPx2w23P)VMQn`>UTe@1yExkv}TUx2*tgQrYMA~dM&q^&v zzn8PbT5ZlUk2ZVFI_Mh9Bs^!)jS{C)IY^hd%gTYoUm@pw;;ZuxX~>pd($T9pL6R0{ zE$b{tnrp;Gx)Co)zt^3UM<3wH%e!Iu@*6g)be8jXeR3Xu$>P|^pEiB^ZL3z@Ce#Gd zSG|%r^eK*m^dz0J1?`aE&hhPs+j8iYI$ll}$K)-@BDg6=_%@tn_4e z*5@aysjQBDK9PJPu_F0Ns6M}$q$y?1CAE8iGV95CK1Ypb>s?AUGh8=;g5wmCIUFEuTmkFZIg-1M-(2hIzmnz}IqqH-__V0JFZf5q^#)jC+ovFt&lQ9XX4k*%wy4crZRKSQepC-PI2;{ zyawV7XYU;7HtR}@SFB#XX1%=6T3QwM%U`or2l@EPnSahb6;K!Yoyuh%<6DFhq7s0d zV-YL(7R9q`GS;DhF92meX#~pr)(T|$(2fJ4cWLcFC|T$)wa)FGKsmSf0M!gW1-&A? zJAes57jO_T2{;&-3=}cQu|O9v9VqAf3Bb#M*}$Q|>A*x_K5!UtK2Vf?E&z!|^|z?r~W;CF!yz}diUz&XI}zcp!ADfz`KAi0A++V0&9S+z$iMvL0~lSIM4<>4YUJgEsX(o@*WGk0E`1V-1G}z zB5(lkbO!wan9O?u@Ot1N-~`}c;8dU!m=AOT?*p?r%1WI5l zD1#lK0(OHcco=km+%)W{1qOj`Fa*@WFfa<_!Dvter+{%_444YWg4y6yuo#>MmVxnL z1$Ys-8JrH*fC=Dka3VC4>GT>1cH0I~DGsU^W;C7K1@x85j&!fWyJf;0Uk=JQLgvjshFObHH{m0_*~v z;4#n*2E?OXz!BhbFaq?$M5TfLU>tZdm<$dDQ^7zm8w>)A!BJot=ma-|%fTAZ4-;BF z=npo5CxflvP_P3G1iQf?@Gv+Ey06V}(z;3V#JPbnrhk_H$y$%F{ zZ-XJ=n_w7tKgfemf*RNa#(^DRGDvGcD%b*MgZsc@uo>h~K3bE?;HD2MHiOGSTFYpS z+YR>;kk)oT@`oEuz_ox^f$iWEEOp?*+@i z*T4#}7TgTJ4Ay|Rg1f<|z(()|um#)=wuA40U0^HN15O8zfsJ6mtZ42nkV88S1xCRA z2514_2P43DK?QsTi~)@|Bfw|jUI?~|of**kE!P~%1U?*4&(pL&~;C`?H z{19vg-visggJ384H}DYnB1k&O81M+(9xwpyN4kf9BIZ<(bdd|dV7N0W9PU6c6z&8t z9PuX-;VuM&5&joYgu4=q0`CJ8z=y#Ua0ZwGJ`U!C4PXt@Azh^e?sD>nn{=9TxJhRS zLApU;CETQY@CYXzs0!{Puo&T(dbnD+cY*aF=^hsN4+ERvo&}OF6%Mw-eHmB>_jzCk z+-YDq+^2xuaAU|CI^?O~VYqJxx!KX&Y(PQ0U@!>oIiLmQi3CI7E&!w87QisLi@|cZ z9Uu?)S_;Scr-7s+>7WMx8^HuH358U@N!+>;UJ2ame>{up90> zz{6lN$jyo7?gSDMJ{$~!djpt>bR{qZ?yJERgpUBj;GPGj!hHtF!#y9=z)fHrxE@Ra z?*TKx8Y1GK2^Pbh0_MYg7FY)N#USaT8dw4Mb>L=jCs+fn1b2g*!BU(z5^RL~60jNW z^T8IlGr)FmFW3z}4;}&Qz<{J^<3HVnfUm+G4!#7IOT4SO+cw6HyNv*Z}txAnDLiU^Cn|fyHnuU_0EUU@6=x*ai0* za1+uE1$*GW6g&pzf>rQ82MoY}Gg=I$;ygPz0`3y99^n?y0(UxC1NXUL1l*}$3gU~P z0{2!h5xf%YLA-HbCfr$I5ts*-f`h>d@FTDatN?4lZD2k4DA)u(0Jeft!45DVWOoWU zl!c_8!&*b5)Vz;21#1M27VcuS2^a>l)J@~7ttj3n(G zLRmbz*G&iA+oOZ-<609w3jiv z5?MUDgF;7^A&q!7(0d-;YoMdBw_Ys2Y(u)S&Uwqb)LUM9W=BV+_r5}!Ax+c{tXw(X zbkmGkgzCrYNlzr$dF*_8--V9l-uTPC=@lBY1eK4Zl*-S_Lr;(Cpy$PO(9=9dR(`ry zOGi#`yRh&aum3V{{iwZ{BVHl$qZXlOIIP8(Y(%2}qv22T5eZFd8tfz^k70KwlAlP_oYE;oi;zFnh2)6tFUJ{nIyc!km*k1^rE^K9sGKpdlU&igBG!gf$H~S# zO7cZ%QagBza>g3zlbl5&*LmI<)3cI70Ei;DSeW6YPW%PA^A7^F5M_U%a_K3 zSq2&trk%z`pPk7Vm6OJY>7Qftg;{>;M`kbdIhV!_m7mUCVzl`*nmqdjCms)IZ=J7 zY;2sc{+?{Kmv3MC#y9I9Yg{3j^G&QF3+y>goFS*I&P)$tb!NH}t23L2Se>UBvRr7? zpVh%PKUO|g2Q%+Pqm|6O6O5i>c_$g=V0kAPa|O$r<-ziv<{g{VW~`0bd@|WvjvTCO z<_IwJh%x$<erI{mvv{*lSvk^;zNS0|_7TgE^?;clJ%u!7CElnl zOE=N*XYDq_=mFMlznw0PA|@?ny2(c0vNmBd%hIJMpCk)R2C0nw`+%Opn^Iz?MbApj zGG64hlRVEe%3Fw8gwgrt9HqI_G z%Fp5?8~w}Tu6tijGrGG-KJkMs5m#hHm&gW8qsiH008xg%MnRfY8vkjS!7zKaq4S#d)xBwwOql7@n-r$~ zavy)1jZJ^jR!lovhVr#C@Ne|it2&)ye5!^fXJlVs_z zc4ziwMw>EwrqO52o@3k}V0L=9#!R1S(9ECSCG7L>%QxSU2^NP|Kr_w?AAfp-hx};` zr8gwWPWlI(W$JD8?j_ktPhwX_On+im0c;LtS02pH`pdM_*kgA3HSO6(Uo-z4$QxY? zkS@aVWjYX(U8Y;J=dnyzGyQ3fCYd(%V0INnPoX2x(ev8RvuG-VlFy|bj;;Oo#}dr>~xjN^kQ}; z#`I-&b;fiiCa+A-rC-uXsa;sAY*k=aL3C}@=g;Jl#yVSVa*RG^`YipL*BR`Jl<88e z&zPNlDGtr|W*kbBjR&TmvNEu16m~_+u2JZ{7xQ|BeEM`ldKZ@tQ(s}y-{)qMYhK^5 zt73M2!>){(4$Jao`VW&oW@qJOcKW6DfOK_-p3&~NmZYl&SP;ijr^IN-v2ZG z3yrbH{ELivoLv{PeAxFL^of8K8qF+2H=GNdB8)Qm^WZGM`U}T>arXD?uwVPc;qLeE z{gvUa^1#3T@z>x!rTOQ_o!Fmm3Tts6-TWJbXG7!zP~|!C-!Ha|LgkvSA7D0SN_d>j?WXUus2#T*FXM=)wVBIFxO{i zHa|Za1f^@%UR!qE^*5B?c+-~Vvr$DfWK`}v>0 zaDIaZ`wuzkFfM%jgbO1g zCr;u8t4*{^vZ6Yin#-+6rKK;)@GM=HnRVIn?3~=Z{L2dpi&m^$RlNF&OBOD=baCqO z!>=s4>gsF$)Aj#P=l?IafAr)jF|kvp#l>GVJz>VoS&6gfBqh(CH$Ua#1+4v#AO1h0 z{r^?*JAU;}Nc@cZCG`Aq!h2Di=RzJ^*kkXmF-bF{XA?C*!)al!A0-#X#(?UQcpA5Q-mio-$e^^q-#`yR%06I*@4 z$vsJlA{g*Ysg_D0j{QCIc4?k&6|M2Dk z`Bx|P4y95Dzdnjv2t$V%f1n(my`g`&Z~F6ZiQ+DSp~F1C zVL<+iHueu6n7(p*|L}qJd+d(>;lBAJTkf6BQN4M8uv_}vhNt)E&pj{jt%Cm?Y_vev!`KtjFE)2cUWO+zFAMuE6mb8fuTp&6 ziG#df0K^s)^QNaz+;AuMJ-Xg0b5gW-1flnkBE!_i#h}Vm#TNqF*Jrmz|YXP_!bS zKA4!#)%wpV%AT9M3Li;uU$Oe-7UpGp(3t3z8AcCH$uqp>T=Wp6b==@U3Z*YTy!{ALz1#R_;zY2)wKVP7Tn??$)19otX%9X;q4&Y6C9GM`% zRiubqC@HFO*)aB^m_nkR zw#>s-Q;S7YTU}3S%!-{s_Q#BNOr$R2PVuP;+ZzO1Q*hhK*INsc3OsH3bs3^Lyo*13 zg{NS3qNl*vup@Vg$7m;XK%h^$-h`0wJLJnY=b-&Hq6-a~f{hzTA+fnDvkLNZb0Fw! z^Nd2&bBiA}%x?u*s26>t^j1G(j}l6=cW;t|On!QW?5DxARutv0!1f^+S1c3cp%}8C zgneD0hZuIYC5&X)=XjXwj=>3i`+DH47mV5%dy3GwfX{Q@T~??F^SRGSo?~+}W-TQ* z$4!r&Gcz{9W}TRk&2FFiPT7Cj|4l70Gd3l8)||yLbK>X4&Osi-0y%E1Sj9vEX-w#{wC)6lHoWlN1Yfi@_+vOcG(q!B>u!bdM#?lIbZ<%kV78%1O(%q_Iig zl9g+mf_;3Jc`PEXW+LUOQ|Z!$E5JiN%414e?zkdLUcM*SlAczGTp$Y$%h*CHM_)K? z3S^{&?Sk?>1r}PJEK3XWatzPj6LAuqlZ;aK`dKp53N5*LMMg|daXvm*^JG}EJ-N$@ zGACMMO%G2N>Q-PGn>F1MPBra2e-%RVRuow>3h+f-!FUS--LBqvR9*{3F~cWP$ywQ> zy?#cejB=!VP|re?A!})t2cL7MBVB6KzTBvOX$6IrqCA|ilG>H!Ye~zdMp#YBn{78U z&kQt5K^6Vu3^MXOtUZk6S>irr_UVs)ZSB)7f7mYr<5GVNOzgM2r4VzBC46j_B^^3J zVFb0c>9AxiwPY0;r;)5d)C$J?w1rQ(J;g-@XSJ94EB$Fhp17i8sk)#(nQY>#l|M(nZZ0BP=w(ypWw4$`WaXm1jf#vZ% z>5udA)&WIJPs?3y!9G~{7Mp}^{P8L_Fh5@zKGFR0(~6d48gr*I-5dm2=00i0XR*i2 z9k0-Py93jqh4m6-Y{e4VNNy>1iCc}X^yx=dzuze1fb7z<^Oh{PKoFIjp%@*f^E zE6HND6nd7C3Ub_5V{6F3wi}p^a02PjJUU}KRw!zSmBK{cZi%$aNLx;`;!Grn*!vZblamgf)Lo@2s8(DE^=wd^*3UL9jq{v(a z-HT`<@E$Wije7c#k^5pw?}UPggUIf@dm{vU>4QPA|MrzEi$vjM{yhF{ffH>3lBY9a zOxYRiwflo1FhgL5!JGs$6y{`@AeaCz$&cJ5*%bB{7&DC0rE`g=!cZP0*5r2@%;{c3 z{-a^Y-ws1=8WrT8;&tPK%s9u;O<_-hp>SMI80lXOQr@&kl79}21qK&o#`i9`*fq*e z^`P>U!cdvlc)1p&x?BrG;bkzC&PJH=F!W6exwpYk`KnrEe~szvh2W{{KT#IsWryR>0#wAp9Rv zfqz#qjw>Esjpx^LVfy^LO7#CW-Txhe;Wx-XAh;CYphICuUAubiXm2C#_<&iq-N(4* zp3Y-ri@LhhU=89wd+&jJEiCv~zia-`aXYUlL(UnlM0g!Qv_2AvmT}brV^$KW;cvkhep_&VOn9@VLD;D zVR~SWzyw&4H%vH;29pSr3R47A0#gRF9;OmzGfXv1EzEA12AC$87MM1eE|?=Q{x%jr z7z~98hf!b>U>3sU!<50ShpB|AfoX-Iy?z?Y`pWLxCj;%t*P<zXN`tQF*Ml{8{IR*ldvqdxE#e=~P?}Vxz!b<3 z%!*BTR~V-M(Q^$4#ozDPFTao;PWo#U%r6*IrQjNrkFE(wzqi0#1Jip{4T|cuHxKEv z{}j+`kJ=p6YfpUs)Lwho;nPif=^dNSH0_p#y(5|3f8Wbz-z<`S+m|i-&wlQ$nNgOW zt$Xq>ta<2#Em={mi+&#a$*7xWjr`);sLSto_x35L4B0S#*Vd>X_f^Gwx#sj+)~tOp zYM=J@j@N&QKd<|FnO>C4lex~(R<;kxB>$Eh2B$nPwf-0=R*2Y=jh^oy$> zm_23Nrz<~h`F8xIvNadPga@DXz>$Z8KYpRG&kYpyYIBzG-yt0(^&e9fqSjx zHTnmPIF9O#1YPrky>l z_Jy5a=}|i#&&u94%`r_UcEH zN=|=zvHtE?lQx{R_txvqI2xme>GyrE-Z$>=*VIhVud3bF)sRs#we|hE?j={A)G{V{ z)wREDT;tmKlVju+OU6zS8f&%DH@=~)opxtE_w&2Xj`Ea%vmfdH`1&1#oiCQfPCohZ zzpjwqo9M7z9{T2(_pD#VS1eF>+_1NC{(<|}?%2M^`cdYir|q0`Pt3(n1V@aG?~0Vf zSxFD?Uq1Ghi~Xw`4?cI*(e4+|-TGPig83V@eTmneA2M^gC;jJZZ`pNH@RsC;uxCXkWpotUv!Y|2}_+|DOMaKSc-;Mhm>) z5GD(=g-e7Cp-?Ch9u@{$FR+%|cH3UHePH{y0*F= zay7WVb#d-V?gj2F_g42a?iRP7exANtM-N-@9t<#>f1H1Y|A7CLzes2n##qa(w^$#s z)?5AUVbY_LRlZAZm5<61${os6N{srWDm#ujuhPo3+q7A(Vfr{-)Km4#^xO2i^=kbg z{dJvWstf53=g;OR@+$A}M4VY~3G@UHNo@R{(f zaE5ghTKz)nMb-`0{npQ{-&&7Y18pO0=h!^9%WOrqhi#A9p2EM94HFlL_$Oud8|)kG z!=!PNC{2-ONQOA6Hhq^tWHEV$`yW8#FHgGxu08?v zyiwn)|4pYwqY`yImk;AFa4k(8eUHx7?6aD&)<6NicyvVu4c_qs5sPk>-L1(w~RPB5% zUi(1n*1pwFa*cD9xn6aB;`+`N>Q>#e-0R#mZdvcvztN9UeoTwX6%$d&R>kX(y0PKi)>MO5Z0*C>xbejAiVrAcX4T9j6$ zO*vN$Q^VB=l~?aXyLLNHac*=Dfpk8vwP=6W7P`i}Q`~9pC)|zhEqaaqG|5b=QG9MA ze;2<)*d^R;{lxl}^-Np7ZKo|o%oMK{w}{>1*J#00?X&I2?1QE85|0w^kvgOaj;O9K#@m)SvK+MF*JD0-+jhYA zo$V)EsHlp%7%wgs3&e79BXX<}Ul%!hh<&Pkx;-DGe4YJv``z{j?T^`?#Atuh-fsWQ z{*C4XyEg{vjQe zIQb;`6nVHjQXVZ|fVLK8Ro3Nca)LZZULY@)J#vm*AQ#J}kl%IkZSp30E9Q^~Uu zRw*UQTID9?7Ugzji?Us*QRI31OH`tX9=J+nQ><%(}|D#=6nk1*sBj+r)aY2hud$9%`S4dHV!iD+X7thoIaMx{2P?92sdB&4p?s`-uS~=o?Ldo6RTI=Cb%C0uW~zDWO7$xB zI&}kPlx^w*>MqRR`_z}!zp0;N&K%^J?PzdnS{7#L`!TNsyHr=QE8A7Yd+kT;QPMmq3w6I$Iw*ZBMPl8Wg>~ynxn6!&eg$LyEXA%| zq$ERLepDV(HP<$*Fk{`iJI;Nb`>*bD{SK@E_4;Qz6}A@TP2lHZCR)YcfpNHp-_N)6 zpYUJv?+K?_FSce{Z?GP+PPQGx{P?jr-mcq=?FZ~HOP@#|%E#o<$`17r^$oQ{J*J-Q z2-HSunl?jA(iUrZ+6t{qTc_QPw%n=h()MUiV`h0-dtG~1>(oBezSfSQh0k||y9Af) zigqQqZgK5&HM&l5k8qDiNf*0w-JiI>aR1<*s86Mtvyr|7MBDPi_<4LI|2coUU=c3B zD%BxGTc5So*~W_LDB*Wvq-2#8Ntd=r4kbywR4rC3)VtM()T8Qf$M>4WHN#ctx(BlT zf$L}28Tti~zf{lH*Xot}4z$cGdWZfM$#5&nljBdv3L>GEmhr3kb^I3oL-7mo z8)Kz-338b)t&$#sCSjG6mdDH#?tjPSg@zDK1XGRo|*}ootSc;6;p_S^RtaxBPgaN_futinT!W zw+Gv|+IQF=wLfd0A!SHgr3>Wi9h)3M?qIZAh&$A6afi9X-4SlyExHw&V|(cPMvgn% zR$$v>%d_*+aHrE5@BB_1?qVZ7$`#{^b6xJb)3pbBNTaLC)$D3%)zULk z3+B_YSfk(x1&^-Z_6pzGI5Ak93~eo6gog$He~p4MLxc#S=-&uveWGwkJPa+)-yUQi zfteu89$^>lnmxvzU{AI$v}f3}?M2Wu%IxdymG;f{1U*qtM%mWu6;ux1kE8!nUL=-? zWf)DB;%2d0tQB{Q4PuknBDRSgVwd<|%c0s{3r(`Y-ehmFx7j=FUG_uv!&vY9r66g9 z6p9%t0_%*1l_o(-hL)KjWlKd;iByL5rV{H-wN#7Mra@{#o3vqV?1Bz@SUM*8%R%x8 ztmr_RjqzO~mtl3UlsC)Oa;>}@x)QA|ZE^=zmP7Jkj7EPY2>NQM z5{7kOR5T?XD@r!>*Ak^nS+7(oo0V#%R@n`0pb45l8)nNc<&d$C_^Uzc2sIRX zK?LSbO^w0KnXE2UGt_LgNG(yz)b(nmx>>D;-n(0EfacqxwqfjdsfX0Vm;wA9L5>lQ zP)C>}!XY{|M~ou@>&`+)h9lci4m*xH z{GCD05zbI&m@@)emgbDX=t*`ibY?iSF>XpQYSud|FlMTpHO@L`y|dBT>}++mJ3FC+ z^*|%!v;Zww3(+iExW;RW7Nx~$iCT)5s%2{VTCr9NeYir~q*ZA((7@}pMre<%T07>W zZmkFN5$6iPoFC${U{>N?iYp4^f<|VlE7O&aRiM;W?y7KYa#gu%usYUbtTbbsw7WW8 z-L4+j5oquM7>6MkgW(u|iaQGPSR%BjRClI3-(Bo3b(gy~ruG_^x- z?RNLLkGMIkBf)xzZqdVaURN+L#X*)+Fvc=5zKZoyy&N*VNw0!FR)=}2QE$drYu7um z;`ZoApzrz_dw+6#03XbU@D@HCued3gN8bJ7@BZ7U%_v}YFxwDK`UazfWsS2YT2rvTXIk^E#nw`+eihbD)+%d_ zl}p6`Lc}oL|2h0{%9(VAjgXiK$a*fMR|&~l4x#kLY#sjbXbZd-4wuvOYN**4p%Y}K|JTP;@Z z-L`sL1Fn6VY|XY7tl@38c3X$7)7E9{wjHwd;0pB!)=^Fj!kjlk3=u;`ix?(`ixDC( zilQQFVw4yo#)%1HqL?hEhzrG3=m42wHfF~nu^2O0Ddw?|s|+b|YY$7;W?8T;ND$juff{l#Y*<@& zG3NcxIqzM*M~ilV4H#iQ{dn#<=bn4+x%WPrZfpuH;_)dr8VvkHXm1k*}8Dh3cA{c z?@;OwZ}QhUTW6VL){1z-QSJ6C^=Y|MtL_sC#bBu3XAQ%s@9N&VY5%T$yLN2uSdPn< zo_))`!ri;Np4`;ay?41$3hRHzJB;@u%6Atz>*_f8Bsxo`4jzdltYk8lJ{TWKm}9AA zye>HqRUK;mT?(nYLwyn2Ree7FwZSV*c=On%}^vBj2Xc&W-pyKA_+E01rtN2(HsZ_9$U9{>sA_5YCv%x zTY`y|mXRDa6UIO=jb0E{hf$lRI4A~bPnp3mdx{4~N6nNGN`|3|@v~4H!ia44AxbSX zhJ$G%k+fLT92-SZnPDSlCWfrxI-}bWm=TOEWzzU$ zZrq^tC|-k9oc213Tw>p3%Xm;6$AF1(rV&GAFk*(+8Uyf4InDP*;|r$JhLwcDValuY zYXoDIgrnr%$=#Dlr;($ef!@A@aMF}~uzPXtirFNk^VD zja9V~W8kP|rq@!goexH2(1=)UMzw}gORaY0!WB1`N-AiVh&z;p;$A>EUz-$nfr1gC zsYx0Gks;K6a4Ztf#4$Coys;rQJ({CWEu4O*dL-aFfNI*TBZz+_-&eJ;pzQp}Zd#*gjLkXb^F zWkMnBtb>_Y>?o%4rkpGgV?lQVv1Dk(KrPTLIbAqg?oIw&^}niX_g^k}!4cXO%v8dR(J-niHXk*1CKJIp zPN2kEqq)8@(9m2}QB|=&jpFL4s&LLsV?AxRv;;RA>l5Y?p=avD9qVNUvfz;MOntm# zz2s9QRTVhQ<@HRx*|DC-q?Ow`)?` z3kqibv!xZ|*XlFvZ;@>7l9pXC{AYVA$N$!Nd@i%>N7VSP&UarY z;rtx{{G}eb2a0zC36yo;EA&UleSR^0q?eWH#gC55>krb!gGhfN^v`AmJRe9b%s)qj?+Br|f zSLQ2TR#Vg$^|=G6jw&p7&pN8~x+tB@p2V=&eD30scK(#9JfHmrq!izLSnS8=d~=tU zv`>-tF}vMI?Okj;KI?<|pPjf&^;7cp+_j2c$EQc=j;=C4yzv<-6J;$QpW%+JrEbO2 zyyE<7TQy_Ys+nRbAD`jXm5C#Fzxe7+x#RG9qk*U|$IHmsXsRc(XAsNy3|#|OG4GsN z?`&MzgoJS1xh!>EbfT%T*hJqnJ;ym1x;DM=K(r|uaA(GqLVG+-w;Yc`olR5seQqzV zI@7!VG;J+%0Nlvz7?*0#)ajEzx3lEEOF3ImSuuC1yku^Yw?IA`M&2%&+O^o;tn$0N zCwK1MeTKI}{{($+x3fu-|BGyHP}m7yST;<5iX=eN$Qn`K)YJv^ykKQ;CMm9BnRG^4 z{0x$s_fPy*4|IxFfzw@i!TvB!jm3JCuzv+lbf2&xg-U!LTMGLtGEyuH1vPKMRf?nB z)C5I>3`}46xBRYGo#UgYH#bEG(jISPCANR07A}i+7**olj#b5nHq6dg4+e!fv> zXES5=W;d*=ao`k2FDu&_A+7J5M>v^12YHUKkMmAoA&(qkkzrjqd;{BseOt5Cn@&$% z^A_iyIE6X#q@ncxHE^d2U%?nUhE`uV#`vcI=cj7qj@|rLsvVtTh5|AZ*rsKcqtbz`K>1FiQnB!BUmgdVjXiiR4QB!W3%;x^99CsLKO_WKa@#WY4PP&oR(oeF_0EKA^n6cZjhy)i|3f@D znf((E-~YoYf<0acRUr$B&du8v z2737Hrpd5J=5&#zE}T{7S*vyzw_d9YjaPr$X`0RTTyOdr&jfwzq%S{Bc$cX!;M$3I zjaq{%7A1(Tw0GC2C$y|z%RT^=<6Wjc)M_6(?!^}?E>S}(0-$3V@jcLLN2s!>y*E~dW( z?PU56XcwqVl`K+phJyT{&D{D3h<;lrQ)@t-ENcgKGj)QtGrbPl#`Li!KfV`;Y?G!i zNNh(yVtW!qKS-3R)1Xc4{S&BzTR#EGy!}$se}ZT` zC{w=&b+TRwibK5I4HAo`AgPGuAlkMuUftTFWgVdP>}8v7?E#7H0WCWSqF*m+R1_rs z{z%ieG@aG-KIk6q_n$$XYHR?1-`gjE-US0!|{*BiA3?x~*r%b73Z1Dg{ENVew@fb+@*a(v74}!kT7D13$jDW=AA3jgm4TL(yb+oJV$fVM)fMjZkfY%u^5ix@~O zERghZ5+oz~7U&_i_-l|@d>~97n{?3E8bL;yc@%Jwv@plRI2wVIbBxCyxNcP>&G*v*blJ)!`@w^nYojpGUf+|+e zN>Cfinzd{@NFqG|!awN6@CP>o$jjG2t5|j#)XB1!K;rogka+&SroREn9G%m$4?!}v ziy(>M*IMR7lSJSLL5v7$K@!1s&}x?TfFy!H07(RgL1J+XBw3r#vTuOI^IM=t*~?jw zc)0))FaH3NJ?tZp_`3`efAhNax4QK@NXBs&mYrDK3la-M%bGzlj{TrD9Kq8di69J; z2;v~|@*D^^Gsyj)gVwUet01xX4oED11`><+LDKI>T6P)K&R(jqh-7SE28qSPAhBrF zvNkQ-re!@^c0kL9Kr*5%=rNA(6iDJb4U+g?0ZDJKfuy(ZYS|A!65m-ZI|q`S1`x2= zwt~cViOu63Mww~`Ndy}~62a3TiQrj~c!_A)^C0o^5-7l4z6la9-v)`7 z8IX8+2P9tJ)v}8q@#4d?7!B;D3?yEvLE_~>P$Rdl(5-d4bpz-LwAQH35FV1Ki-fEC zE-L!sS)w`z@l$DCAnTX*+SM_y zq@h{;qCm1vJ%zNp{4_T3H%hmpMZM^?YFww@^jb9qR3)ayW!2QAo-L5HsAjLExmC>; zNZQpoucW0x-G?N*JhwEds|7mks>Z9++Nho_kTk1_0?9h{dV!=((VelYuXPRTT7jfh zErWtf2Q%2^m9z)cSb?NPy-^@pr!IOV&4G5c40n1EqN-??n;Y6xuUFF8sOX;3rPJ7| zs>{5RHuY42q+Pw}wQ6cmFMD-b18Sd^xS!2}AyyMTokdS%ef@*K`d0|>>K_cnl4(;u zD1%nhpqU)BKhs?uNrp@-TlVNlLaz*8<+4bf1oYF7 z^0b+$e)$z%Sbl#O=HJ@|NqI9KrI{W+6 dW+;QlSB@eMGc?j4N+w4lW@oeNcQ>(6{STN0zi0pe