Mapper Support Routines ASCII, 01-09-94 5. MAPPER SUPPORT ROUTINES ============================ MSX-DOS 2 contains routines to provide support for the memory mapper. This allows MSX application programs or MSX-DOS transient programs to utilize more than the basic 64k of memory, without conflicting with the RAM disk or any other system software. 5.1 MAPPER INITIALIZATION When the DOS kernel is initialized it checks that there is the memory mapper in the system, and that there is at least 128k of RAM available. If the kernel has found at least one slot which contains 128k of the mapper RAM, it selects the slot which contains the largest amount of RAM (or the slot with the smallest slot number, if there are two or more mapper slots which have the same amount of RAM) and makes that slot usable as the system RAM. When there is not enough memory on the memory mapper, MSX-DOS 2 won't start. Next the kernel builds up a table of all the 16k RAM segments available to this slot (primary mapper slot). The first four segments (64k) for the user and the two highest numbered segments are allocated to the system, one for the DOS kernel code and one for the DOS kernel workspace. All other segments (at least two) are marked as free initially. Then the kernel builds up the similar tables for other RAM slots, if any. All of these segments are marked as free initially. 5.2 MAPPER VARIABLES AND ROUTINES The mapper support routines use some variables in the DOS system area. These tables may be referred and used by the user programs for the various purposes, but must not be altered. The contents of the tables are as follows: address function +0 Slot address of the mapper slot. +1 Total number of 16k RAM segments. 1...255 (8...255 for the primary) +2 Number of free 16k RAM segments. +3 Number of 16k RAM segments allocated to the system (at least 6 for the primay) +4 Number of 16k RAM segments allocated to the user. +5...+7 Unused. Always zero. +8... Entries for other mapper slots. If there is none, +8 will be zero. A program uses the mapper support code by calling various subroutines. These are accessed through a jump table which is located in the MSX-DOS system area. The contents of the jump table are as follows: address entry name function +0H ALL_SEG Allocate a 16k segment. +3H FRE_SEG Free a 16k segment. +6H RD_SEG Read byte from address A:HL to A. +9H WR_SEG Write byte from E to address A:HL. +CH CAL_SEG Inter-segment call. Address in IYh:IX +FH CALLS Inter-segment call. Address in line after the call instruction. +12H PUT_PH Put segment into page (HL). +15H GET_PH Get current segment for page (HL) +18H PUT_P0 Put segment into page 0. +1BH GET_P0 Get current segment for page 0. +1EH PUT_P1 Put segment into page 1. +21H GET_P1 Get current segment for page 1. +24H PUT_P2 Put segment into page 2. +27H GET_P2 Get current segment for page 2. +2AH PUT_P3 Not supported since page-3 must never be changed. Acts like a "NOP" if called. +2DH GET_P3 Get current segment for page 3. A program can use the extended BIOS calls for the mapper support to obtain these addresses. The calls are provided because these addresses may be changed in the future version, or to use mapper routines other than MSX-DOS mapper support routines. To use the extended BIOS, the program should test "HOKVLD" flag at FB20h in page-3. If bit-0 (LSB) is 0, there is no extended BIOS nor the mapper support. Otherwise, "EXTBIO" entry (see below) has been set up and it can be called with various parameters. Note that this test is unnecessary for the applications which are based on MSX-DOS (such as the program which is loaded from the disk), and the program may proceed to the next step. Next, the program sets the device number of the extended BIOS in register D, the function number in register E, and required parameters in other registers, and then calls "EXTBIO" at FFCAh in page-3. In this case, the stack pointer must be in page-3. If there is the extended BIOS for the specified device number, the contents of the registers AF, BC and HL are modified according to the function; otherwise, they are preserved. Register DE is always preserved. Note that in any cases the contents of the alternative registers (AF', BC', DE' and HL') and the index registers (IX and IY) are corrupted. The functions available in the mapper support extended BIOS are: * Get mapper variable table Parameter: A = 0 D = 4 (device number of mapper support) E = 1 Result: A = slot address of primary mapper DE = reserved HL = start address of mapper variable table * Get mapper support routine address Parameter: A = 0 D = 4 E = 2 Result: A = total number of memory mapper segments B = slot number of primary mapper C = number of free segments of primary mapper DE = reserved HL = start address of jump table In these mapper support extended BIOS, register A is not required to be zero. Note that, however, if there is no mapper support routine, the contents of registers will not be modified, and the value which is not zero will be returned in A otherwise. Thus, the existence of the mapper support routine can be determined by setting zero in A at the calling and examining the returned value of A. The slot address of the primary mapper returned by the extended BIOS is the same as the current RAM slot address in page-3, and, in the ordinary environment (DISK-BASIC and MSX-DOS), the same RAM slot is also selected in page-2. In MSX-DOS, this is also true in page-0 and page-1. 5.3 USING MAPPER ROUTINES A program can request a 16k RAM segment at any time by calling the "ALL_SEG" routine. This either returns an error if there are no free segments, or the segment number of a new segment which the program can use. A program must not use any segment which it has not explicitly allocated, except for the four segments which make up the basic 64k of RAM. A segment can be allocated either as a user segment or as a system segment. User segments will be automatically freed when the program terminates, whereas system segments are never freed unless the program frees them explicitly. Normally, programs should allocate user segments. RAM segments can be accessed by the "RD_SEG" and "WR_SEG" routines which read and write bytes to specified segments. The routines "CAL_SEG" and "CALLS" allow inter-segment calls to be done in much the same way as inter-slot calls in the current MSX system. Routines are provided to explicitly page a segment in, or to find out which segment is in a particular page. There are routines in which the page (0...3) is specified by the top two bits of an address in HL ("PUT_PH" and "GET_PH"). And there are also specific routines for accessing each page ("GET_Pn" and "PUT_Pn"). These routines are very fast so a program should not suffer in performance by using them. Note that page-3 should never be altered since this contains the mapper support routines and all the other system variables. Also great care must be taken if page-0 is altered since this contains the interrupt and the slot switching entry points. Pages 1 and 2 can be altered in any way. None of the mapper support routines will disturb the slot selection mechanism at all. For example when "PUT_P1" is called, the specified RAM segment will only appear at address 4000h...7FFFh if the mapper slot is selected in page-1. The "RD_SEG" and "WR_SEG" routines will always access the RAM segment regardless of the current slot selection in the specified page, but the mapper RAM slot must be selected in page-2. 5.4 ALLOCATING and FREEING SEGMENTS The following two routines can be called to allocate or free segments. All registers apart from AF and BC are preserved. An error is indicated by the carry flag being set on return. The slot selection and RAM paging may be in any state when these routines are called and both will be preserved. The stack must not be in page-0 or page-2 when either of these routines are called. A program must not use any segment (apart from the four which make up the basic 64k) unless it has specifically allocated it, and must not continue to use a segment after it has been freed. A segment may be allocated either as a user or a system segment. The only difference is that user segments will be automatically freed when the program terminates whereas system segments will not be. In general a program should allocate a user segment unless it needs the data in the segment to outlast the program itself. User segments are always allocated from the lowest numbered free segment and system segments from the highest numbered one. An error from "allocate segment" usually indicates that there are no free segments, although it can also mean that an invalid parameter was passed in register A and B. An error from "free segment" indicates that the specified segment number does not exist or is already free. ALL_SEG - Parameters: A=0 => allocate user segment A=1 => allocate system segment B=0 => allocate primary mapper B!=0 => allocate FxxxSSPP slot address (primary mapper, if 0) xxx=000 allocate specified slot only xxx=001 allocate other slots than specified xxx=010 try to allocate specified slot and, if it failed, try another slot (if any) xxx=011 try to allocate other slots than specified and, if it failed, try specified slot Results: Carry set => no free segments Carry clear => segment allocated A=new segment number B=slot address of mapper slot (0 if called as B=0) FRE_SEG - Parameters: A=segment number to free B=0 primary mapper B!=0 mapper other than primary Returns: Carry set => error Carry clear => segment freed OK 5.5 INTER-SEGMENT READ AND WRITE The following two routines can be called to read or write a single byte from any mapper RAM segment. The calling sequence is very similar to the inter-slot read and write routines provided by the MSX system ROM. All registers apart from AF are preserved and no checking is done to ensure that the segment number is valid. The top two bits of the address are ignored and the data will be always read or written via page-2, since the segment number specifies a 16k segment which could appear in any of the four pages. The data will be read or written from the correct segment regardless of the current paging or slot selection in page-0 or page-1, but note that the mapper RAM slot must be selected in page-2 when either of these routines are called. This is so that the routines do not have to do any slot switching and so can be fast. Also the stack must not be in page-2. These routines will return disabling interrupts. RD_SEG - Parameters: A = segment number to read from HL = address within this segment Results: A = value of byte at that address All other registers preserved WR_SEG - Parameters: A = segment number to write to HL = address within this segment E = value to write Returns: A = corrupted All other registers preserved 5.6 INTER-SEGMENT CALLS Two routines are provided for doing inter-segment calls. These are modelled very closely on the two inter-slot call routines provided by the MSX system ROM, and the specification of their usage is very similar. No check is done that the called segment actually exists so it is the user's responsibility to ensure this. The called segment will be paged into the specified address page, but it is the user's responsibility to ensure that the mapper slot is enabled in this page, since neither of these routines will alter the slot selection at all. This is to ensure that they can be fast. The routine cannot be used to do an inter-segment call into page-3. If this is attempted then the specified address in page-3 will simply be called without any paging, since page-3 must never be altered. Calling into page-0 must be done with some care because of the interrupt and other entry point. Also care must be taken that the stack is not paged out by these calls. These routines, unlike inter-slot calls, do not disable interrupts before passing control to the called routine. So they return to the caller in the same state as before, unless the interrupt flag was modified by the called routine. Parameters cannot be passed in registers IX, IY, AF', BC', DE' or HL' since these are used internally in the routine. These registers will be corrupted by the inter-segment call and may also be corrupted by the called routine. All other registers (AF, BC, DE and HL) will be passed intact to the called routine and returned from it to the caller. CAL_SEG - Parameters: IY = segment number to be called IX = address to call AF, BC, DE, HL passed to called routine Other registers corrupted Results: AF, BC, DE, HL, IX and IY returned from called routine. All others corrupted. CALLS - Parameters: AF, BC, DE, HL passed to called routine Other registers corrupted Calling sequence: CALL CALLS DB SEGMENT DW ADDRESS Results: AF, BC, DE, HL, IX and IY returned from called routine. All others corrupted. 5.7 DIRECT PAGING ROUTINES The following routines are provided to allow programs to directly manipulate the current paging state without having to access the hardware. Using these routines ensures compatibility with any changes to the details of the hardware. The routines are very fast and so using them will not compromise the performance of programs. Routines are provided to directly read or write to any of the four page registers. No checking of the validity of the segment number is done so this is the user's responsibility. Note that the value written in the register is also written in memory and, if the register value is requested, the value stored in memory will be returned and the one in the register will never be read directly. This is done to avoid errors from hardware conflicts when there are two or more mapper registers in the system. The user should always manipulate the memory mapper through these routines. The "GET" routines return values from internal images of the registers without actually reading the registers themselves. This ensures that if a segment is enabled by, for example, "PUT_P1" then a subsequent "GET_P1" call will return the actual value. Reading the mapper register may produce a different value because the top bits of the segment numbers are generally not recorded. Although a "PUT_P3" routine is provided, it is in fact a dummy routine and will not alter the page-3 register. This is because the contents of the page-3 register should never be altered. The "GET_P3" routine does behave as expected to allow the user to determine what segment is in page-3. Another pair of routines ("GET_PH" and "PUT_PH") is provided which are identical in function except that the page is specified by the top two bits of register H. This is useful when register HL contains an address, and these routines do not corrupt register HL. "PUT_PH" will never alter the page-3 register. PUT_Pn - Parameters: n = 0,1,2 or 3 to select page A = segment number Results: None All registers preserved GET_Pn - Parameters: n = 0,1,2 or 3 to select page Results: A = segment number All other registers preserved PUT_PH - Parameters: H = high byte of address A = segment number Results: None All registers preserved GET_PH - Parameters: H = high byte of address Results: A = segment number All other registers preserved Before using these direct paging routines to alter the paging state, a program should first use the "GET_Pn" routines to determine the initial four segments for when it needs to restore these. No program should assume fixed values for these initial segments since they are likely to change in future versions of the system. |