|
52 | 52 |
|
53 | 53 | [3.13. Enable or disable the Z80 access mode for a driver (_Z80MODE, 7Dh)](#313-enable-or-disable-the-z80-access-mode-for-a-driver-_z80mode-7dh)
|
54 | 54 |
|
| 55 | +[3.14. Get information for a cluster on a FAT drive (_GETCLUS, 7Eh)](#314-get-information-for-a-cluster-on-a-fat-drive-_getclus-7eh) |
| 56 | + |
55 | 57 | [4. New error codes](#4-new-error-codes)
|
56 | 58 |
|
57 | 59 | [5. Extended mapper support routines](#5-extended-mapper-support-routines)
|
58 | 60 |
|
59 |
| -[5.1. BLK_ALLOC: Allocate a memory block](#51-blk_alloc-allocate-a-memory-block) |
| 61 | +[5.1: CALL_MAP: Call a routine in a mapped RAM segment](#51-call_map-call-a-routine-in-a-mapped-ram-segment) |
| 62 | + |
| 63 | +[5.2: RD_MAP: Read a byte from a RAM segment](#52-rd_map-read-a-byte-from-a-ram-segment) |
| 64 | + |
| 65 | +[5.3: CALL_MAPI: Call a routine in a mapped RAM segment, with inline routine identification](#53-call_mapi-call-a-routine-in-a-mapped-ram-segment-with-inline-routine-identification) |
| 66 | + |
| 67 | +[5.4: WR_MAP: Write a byte to a RAM segment](#54-wr_map-write-a-byte-to-a-ram-segment) |
60 | 68 |
|
61 |
| -[5.2. BLK_FREE: Free a memory block](#52-blk_free-free-a-memory-block) |
| 69 | +[5.5. The UNAPI RAM Helper discovery procedure](#55-the-unapi-ram-helper-discovery-procedure) |
| 70 | + |
| 71 | +[5.6. Breaking change notice](#56-breaking-change-notice) |
62 | 72 |
|
63 | 73 | [6. Other features](#6-other-features)
|
64 | 74 |
|
@@ -629,6 +639,91 @@ Note that the Z80 access mode is enabled or disabled for a whole driver, affecti
|
629 | 639 |
|
630 | 640 | The Z80 access mode applies to MSX-DOS drivers only. Nextor will never change the CPU when accessing drive-based and device-based drivers.
|
631 | 641 |
|
| 642 | + |
| 643 | +### 3.14. Get information for a cluster on a FAT drive (_GETCLUS, 7Eh) |
| 644 | + |
| 645 | +``` |
| 646 | +Parameters: C = 7EH (_GETCLUS) |
| 647 | + A = Drive number (0=default, 1=A: etc.) |
| 648 | + DE = Cluster number |
| 649 | + HL = Pointer to a 16 byte buffer |
| 650 | +Results: A = Error code |
| 651 | +``` |
| 652 | + |
| 653 | +This function fills a user buffer with information related to a given cluster number for a given drive, |
| 654 | +provided that the drive is mapped to a FAT12 or FAT16 filesystem. This function, in combination with |
| 655 | +[RDDRV](#33-read-absolute-sectors-from-drive-_rddrv-73h) and [WRDRV](#34-write-absolute-sectors-to-drive-_wrdrv-74h), |
| 656 | +can be useful for tools that perform low-level disk manipulation such as defragmenters. |
| 657 | + |
| 658 | +The information returned in the buffer is as follows: |
| 659 | + |
| 660 | +* +0: FAT sector number that contains the entry for the cluster (2 bytes) |
| 661 | +* +2: Offset in the FAT sector where the entry for the cluster is located (0-511) (2 bytes) |
| 662 | +* +4: First data sector number the cluster refers to (4 bytes) |
| 663 | +* +8: Value of the FAT entry for the cluster (2 bytes) |
| 664 | +* +10: Size of a cluster in sectors for the drive (1 byte) |
| 665 | +* +11: Flags (1 byte) |
| 666 | + * bit 0: set if the drive is FAT12 |
| 667 | + * bit 1: set if the drive is FAT16 |
| 668 | + * bit 2: set if the FAT entry for the cluster is an odd entry (FAT12 only) |
| 669 | + * bit 3: set if the cluster is the last one of a file |
| 670 | + * bit 4: set if the cluster is free |
| 671 | + * bits 5-7: unused, always zero |
| 672 | +* +12-+15: Unused, always zero |
| 673 | + |
| 674 | +If the drive is neither FAT12 nor FAT16, this function will return a .NDOS error; this means that either |
| 675 | +the FAT12 flag or the FAT16 flag will always be set if the function returns no error. Note however that this might not |
| 676 | +be true in future versions of Nextor (in case that support for other FAT variants is added), therefore |
| 677 | +you should always check both flags and not assume that one being clear means that the other one is set. |
| 678 | + |
| 679 | +If the supplied cluster number doesn't exist in the specified drive, an .ICLUS error will be returned. |
| 680 | +Note that 0 and 1 are always invalid cluster numbers (the bytes for these entries in the first FAT sector are unused). |
| 681 | + |
| 682 | +The value of the FAT entry for the cluster has the usual meaning in a FAT filesystem: |
| 683 | + |
| 684 | +* 0 means that the cluster is free |
| 685 | +* 0FF8h-0FFFh for FAT 12 and FFF8h-FFFFh for FAT16 mean that the cluster is the last one of a file |
| 686 | +* Other value is the number of the next cluster where the data for a file continues |
| 687 | + |
| 688 | +For convenience, the "cluster is free" and "cluster is the last one of a file" flags are provided so that |
| 689 | +the first two cases can be easily detected without checking the value of the FAT entry itself. |
| 690 | + |
| 691 | +FAT entries for FAT12 can be even or odd, as indicated by the "entry is odd" flag. The value is stored differently in each case; |
| 692 | +if "X" is the value of "offset in the FAT sector" and "peek(X)" is the byte value stored in X, then the value is: |
| 693 | + |
| 694 | +* For even entries: `peek(X) + ((peek(X+1) and &HF) * 256)` |
| 695 | +* For odd entries: `((peek(X) \ 16) and &HF) + (peek(X+1) * 16)` |
| 696 | + |
| 697 | +For convenience here's a diagram showing an example of FAT12 even and odd entries, based on the one present at |
| 698 | +[MSX2 Technical Handbook, chapter 3](https://github.com/Konamiman/MSX2-Technical-Handbook/blob/master/md/Chapter3.md): |
| 699 | + |
| 700 | +``` |
| 701 | + |4 bits |4 bits | |
| 702 | + FAT ----------------- |
| 703 | +start address ->| F 0 | Media ID |
| 704 | + |---------------| |
| 705 | + +1 | F F | dummy entry |
| 706 | + |---------------| |
| 707 | + +2 | F F | dummy entry |
| 708 | + |---------------| |
| 709 | + +3 | 1 2 | Entry for cluster 2 : offset = 3, value = 412h (even entry) |
| 710 | + |---------------| |
| 711 | + +4 | 3 | 4 | Entry for cluster 3 : offset = 4, value = 563h (odd entry) |
| 712 | + |---------------| |
| 713 | + +5 | 5 6 | |
| 714 | + |---------------| |
| 715 | + +6 | 7 | 8 | Entry for cluster 4 : offset = 6, value = 978h (even entry) |
| 716 | + |---------------| |
| 717 | + +7 | | 9 | |
| 718 | + --------- |
| 719 | +``` |
| 720 | + |
| 721 | +For FAT16 entries it's much simpler: these are stored in the byte at the specified offset and the next one in little endian, so `peek(X) + (256 * peek(X+1))`. |
| 722 | + |
| 723 | +Note that if the offset in the FAT sector is 511, then the entry is split between the last byte in "FAT sector number that contains the entry" and the first byte of the next sector. |
| 724 | +This can happen on FAT12 only. |
| 725 | + |
| 726 | + |
632 | 727 | ## 4. New error codes
|
633 | 728 |
|
634 | 729 | New error codes are defined to handle error conditions when managing the new features of Nextor. These errors are returned in MSX-DOS 1 mode as well by the new functions supported in this mode.
|
@@ -659,46 +754,126 @@ An attempt to open or alter a mounted file, or to perform any other disallowed o
|
659 | 754 |
|
660 | 755 | Attempt to mount a file that is smaller than 512 bytes or larger than 32 MBytes.
|
661 | 756 |
|
| 757 | +* Invalid cluster number (.ICLUS, 0B0h) |
| 758 | + |
| 759 | +The cluster number supplied to the [_GETCLUS](#314-get-information-for-a-cluster-on-a-fat-drive-_getclus-7eh) function doesn't exist in the drive. |
| 760 | + |
662 | 761 |
|
663 | 762 | ## 5. Extended mapper support routines
|
664 | 763 |
|
665 |
| -The original MSX-DOS 2 mapper support routines have been extended with two new functions that allow the allocation of small blocks of memory (from 1 to 16378 bytes) within an allocated or TPA segment. Entries for these functions are available as an extension of the mapper support routines jump table whose address can be obtained by using extended BIOS. The names and locations in the jump table of these new routines are: |
| 764 | +The original MSX-DOS 2 mapper support routines (see "5. Mapper support routines" in [MSX-DOS 2 Program Interface Specification](https://github.com/Konamiman/Nextor/blob/v2.1/docs/DOS2-PIS.TXT)) |
| 765 | +have been extended with four new routines that allow reading data, writing data and calling routines placed in another RAM segment; they work |
| 766 | +much like the existing routines RD_SEG, WR_SEG, CAL_SEG and CALLS but they accept a pair of slot number + RAM segment number as input instead of only the RAM segment number. |
| 767 | +These routines are compatible with the [UNAPI RAM helper specification](https://github.com/Konamiman/MSX-UNAPI-specification/blob/master/docs/MSX%20UNAPI%20specification%201.1.md#4-the-ram-helper), |
| 768 | +including the extended BIOS based discovery mechanism; this means that any application program that relies on the presence of the UNAPI RAM helper will work out of the box |
| 769 | +with Nextor, without needing to first install a standalone helper. |
| 770 | + |
| 771 | +The names and locations of these routines in the mapper support routines jump table is as follows: |
666 | 772 |
|
667 | 773 | ```
|
668 |
| -+30h: BLK_ALLOC |
669 |
| -+33h: BLK_FREE |
| 774 | ++30h: CALL_MAP |
| 775 | ++33h: RD_MAP |
| 776 | ++36h: CALL_MAPI |
| 777 | ++39h: WR_MAP |
670 | 778 | ```
|
671 | 779 |
|
672 |
| -Both routines work on the memory that is switched on page 2 at the moment of calling them. It may be an explicitly allocated segment, a TPA segment, or even non-mapped RAM: they will work on any writable memory that is visible on page 2. However a segment will be assumed to be switched on page 2 for documentation purposes. |
673 | 780 |
|
674 |
| -Following is the description of these routines. |
| 781 | +### 5.1: CALL_MAP: Call a routine in a mapped RAM segment |
675 | 782 |
|
676 |
| -### 5.1. BLK_ALLOC: Allocate a memory block |
| 783 | +* Input: |
| 784 | + * IYh = Slot number |
| 785 | + * IYl = Segment number |
| 786 | + * IX = Target routine address (must be a page 1 address) |
| 787 | + * AF, BC, DE, HL = Parameters for the target routine |
| 788 | +* Output: |
| 789 | + * AF, BC, DE, HL, IX, IY = Parameters returned from the target routine |
677 | 790 |
|
678 |
| -``` |
679 |
| -Entry: HL = Required size (1 to 16378 bytes) |
680 |
| -Returns: On success: |
681 |
| - HL = Address of the allocated block (always a page 2 address) |
682 |
| - A = 0 and Z set |
683 |
| - On error (not enough free space on segment): |
684 |
| - HL = 0 |
685 |
| - A = .NORAM and Z reset |
686 |
| -``` |
| 791 | +The routine will be called by switching the specified slot and segment in page 1, therefore the routine address must be in page 1 as well. |
687 | 792 |
|
688 |
| -This routine tries to allocate a memory block of the specified size on the segment currently switched on page 2, and returns the address of the allocated block if it succeeds, or a "Not enough memory" error if not. The segment must have been previously initialized by calling the BLK_FREE routine with HL=0, otherwise the result is unpredictable. |
689 | 793 |
|
690 |
| -### 5.2. BLK_FREE: Free a memory block |
| 794 | +### 5.2: RD_MAP: Read a byte from a RAM segment |
691 | 795 |
|
692 |
| -``` |
693 |
| -Entry: HL = Address of the allocated block as returned by BLK_ALLOC, |
694 |
| - or 0 to initialize the segment |
695 |
| -``` |
| 796 | +* Input: |
| 797 | + * A = Slot number |
| 798 | + * B = Segment number |
| 799 | + * HL = Address to be read from (higher two bits will be ignored) |
| 800 | +* Output: |
| 801 | + * A = Data read from the specified address |
| 802 | + * F, BC, DE, HL, IX, IY preserved |
| 803 | + |
| 804 | + |
| 805 | +### 5.3: CALL_MAPI: Call a routine in a mapped RAM segment, with inline routine identification |
| 806 | + |
| 807 | +* Input: |
| 808 | + * AF, BC, DE, HL = Parameters for the target routine |
| 809 | +* Output: |
| 810 | + * AF, BC, DE, HL, IX, IY = Parameters returned from the target routine |
| 811 | + |
| 812 | +The routine is to be called as follows: |
| 813 | + |
| 814 | + CALL CALLSEG |
| 815 | + |
| 816 | + CALLSEG: |
| 817 | + CALL <address of CALL_MAPI> |
| 818 | + DB &Bmmeeeeee |
| 819 | + DB <segment number> |
| 820 | + ;no RET is needed here |
| 821 | + |
| 822 | + where |
| 823 | + |
| 824 | +* `mm` is the mapper slot, as an index (0 to 3) in the mapper variables table provided by the standard mapper support routines |
| 825 | +(see "5.2 Mapper variables and routines" in [MSX-DOS 2 Program Interface Specification](https://github.com/Konamiman/Nextor/blob/v2.1/docs/DOS2-PIS.TXT)). |
| 826 | + |
| 827 | +* `eeeeee` is the routine to be called, as an index (0 to 63) of a jump table that starts at address 4000h of the segment. That is, 0 means 4000h, 1 means 4003h, 2 means 4006h, etc. |
| 828 | + |
| 829 | +The way to specify the mapper slot and the segment number is weird, but it allows to pack the entire call in five bytes. This allows to use this routine with hooks in the same way |
| 830 | +it's usually done with the BIOS routine CALLF. |
| 831 | + |
| 832 | + |
| 833 | +### 5.4: WR_MAP: Write a byte to a RAM segment |
| 834 | + |
| 835 | +* Input: |
| 836 | + * A = Slot number |
| 837 | + * B = Segment number |
| 838 | + * E = Byte to write |
| 839 | + * HL = Address to be written to (higher two bits will be ignored) |
| 840 | +* Output: |
| 841 | + * A = Data readed from the specified address |
| 842 | + * F, BC, DE, HL, IX, IY preserved |
| 843 | + |
| 844 | + |
| 845 | +### 5.5. The UNAPI RAM Helper discovery procedure |
| 846 | + |
| 847 | +Nextor implements the UNAPI RAM Helper discovery procedure in order to make these new mapper support routines compatible with the already existing |
| 848 | +[UNAPI RAM Helper specification](https://github.com/Konamiman/MSX-UNAPI-specification/blob/master/docs/MSX%20UNAPI%20specification%201.1.md#4-the-ram-helper). |
| 849 | +For reference, the discovery procedure is repeated here: |
| 850 | + |
| 851 | +> To check for the presence of a RAM helper, and to obtain the address of its routines, EXTBIO (0FFCAh) must be called with DE=2222h, HL=0, and A=FFh. If the RAM helper is not installed, then HL=0 |
| 852 | +> at output; otherwise the following register values will be returned: |
| 853 | +> |
| 854 | +> * HL = Address of a jump table in page 3 |
| 855 | +> * BC = Address of the reduced mappers table in page 3 (zero if not provided) |
| 856 | +> * A = Number of entries in the jump table |
| 857 | +
|
| 858 | +In the case of Nextor the following applies: |
| 859 | + |
| 860 | +* HL will point to the location of CALL_MAP (offset +30h from the start of the mapper support routines jump table). |
| 861 | +* BC will always be returned as zero (the reduced mappers table is mandatory for UNAPI RAM Helpers only when the mapper support routines are not present). |
| 862 | +* A will always be 4 (in the MSX UNAPI specification it's 3 since the WR_MAP routines is not defined - this is a non-breaking change). |
| 863 | + |
| 864 | + |
| 865 | +### 5.6. Breaking change notice |
| 866 | + |
| 867 | +In versions of Nextor older than 2.1.0, including the alphas and betas of 2.1.0, the mapper support routines jump table area that is now used for the RD_MAP, WR_MAP, CALL_MAP and CALL_MAPI |
| 868 | +entry points was used for two different routines that are not available anymore, BLK_ALLOC and BLK_FREE; this represents a breaking change and existing applications making use of them |
| 869 | +will need changes. |
696 | 870 |
|
697 |
| -This routine frees a memory block on the segment currently switched on page 2. The specified address must be a block address previously returned by the BLK_ALLOC routine on the same segment, otherwise the result is unpredictable. The freed space will become available for new allocations. |
| 871 | +Although not used by Nextor anymore, the source code of these removed routines is kept as part of the Nextor code base |
| 872 | +(at [source/kernel/bank4/bkalloc.mac](https://github.com/Konamiman/Nextor/blob/v2.1/source/kernel/bank4/bkalloc.mac)). |
| 873 | +This way, if you have an application that makes use of these routines you can simply incorporate the code from that file to your application and call the routines directly. |
698 | 874 |
|
699 |
| -All the state information about allocated and free blocks is stored on the segment itself, Nextor does not store any internal information about block memory allocation. This means that when all the allocated blocks on a given segment are no longer needed, it is not needed to explicitly free all blocks one by one; instead, the segment may be overwritten with any other data, the segment itself may be freed, or (in case of TPA segments) application may terminate directly. |
| 875 | +You can read the documentation for the removed routines in [the Programmers Reference for Nextor 2.0](https://github.com/Konamiman/Nextor/blob/v2.0/docs/Nextor%202.0%20Programmers%20Reference.md#5-extended-mapper-support-routines). |
700 | 876 |
|
701 |
| -When called with HL=0, this routine initializes the segment currently switched on page 2 for block memory allocation. It is necessary to do this once before performing any block allocation on the segment. Also, this is useful on segments that already have allocated blocks, as a fast way to free all blocks at once. |
702 | 877 |
|
703 | 878 | ## 6. Other features
|
704 | 879 |
|
|
0 commit comments