Add support for DOS Upper Memory Blocks (UMBs). (#38)
* Import unmodified USE!UMBS source. From https://forum.vcfed.org/index.php?threads/loading-dos-high-on-a-xt.32320/ * Customize the UMB Driver prompts. * Refactor memory management. Allow activation of EMS/UMB on demand. * Update the XTEMM and XTUMBS drivers to map their ranges. * Add instructions for all the drivers.
This commit is contained in:
parent
553ca58dff
commit
0fbbc0070c
@ -49,6 +49,9 @@
|
||||
// Revision 10 02/17/2025
|
||||
// - Use a lookup table for the memory map
|
||||
//
|
||||
// Revision 11 03/01/2025
|
||||
// - Refactor lookup table and add support for UMBs
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// Copyright (c) 2024 Ted Fried
|
||||
@ -170,12 +173,10 @@
|
||||
#define PSRAM_RESET_VALUE 0x01400000
|
||||
#define PSRAM_CLK_HIGH 0x02000000
|
||||
|
||||
#define EMS_BASE_IO 0x260 // Must be a multiple of 8.
|
||||
#define EMS_BASE_MEM 0xD0000
|
||||
#define MMAN_BASE 0x260 // Must be a multiple of 16.
|
||||
#define EMS_MAX_SIZE (16*1024*1024)
|
||||
|
||||
#define EMS_TOTAL_SIZE (16*1024*1024)
|
||||
|
||||
#define SD_BASE 0x280 // Must be a multiple of 8.
|
||||
#define SD_BASE 0x280 // Must be a multiple of 8.
|
||||
#define SD_CONFIG_BYTE 0
|
||||
|
||||
|
||||
@ -196,7 +197,9 @@ uint8_t isa_data_out = 0;
|
||||
uint8_t nibble_in =0;
|
||||
uint8_t nibble_out =0;
|
||||
uint8_t read_byte =0;
|
||||
uint16_t ems_frame_pointer[4] = {0, 0, 0, 0};
|
||||
uint32_t umb_base_segment =0;
|
||||
uint16_t ems_frame_pointer[4] = {0xffff, 0xffff, 0xffff, 0xffff};
|
||||
uint32_t ems_base_segment =0;
|
||||
uint8_t spi_shift_out =0;
|
||||
uint8_t sd_spi_datain =0;
|
||||
uint32_t sd_spi_cs_n = 0x0;
|
||||
@ -205,10 +208,36 @@ uint8_t sd_scratch_register[6] = {0, 0, 0, 0, 0, 0};
|
||||
uint16_t sd_requested_timeout = 0;
|
||||
elapsedMillis sd_timeout;
|
||||
|
||||
uint8_t XTMax_MEM_Response_Array[16];
|
||||
enum MemResponse {
|
||||
AutoDetect,
|
||||
DontRespond,
|
||||
Respond,
|
||||
};
|
||||
|
||||
DMAMEM uint8_t internal_RAM1[0x60000];
|
||||
uint8_t internal_RAM2[0x40000];
|
||||
MemResponse XTMax_MEM_Response_Array[16] = {
|
||||
/* 640KB conventional memory */
|
||||
/* 00000 - 0FFFF */ AutoDetect,
|
||||
/* 10000 - 1FFFF */ AutoDetect,
|
||||
/* 20000 - 2FFFF */ AutoDetect,
|
||||
/* 30000 - 3FFFF */ AutoDetect,
|
||||
/* 40000 - 4FFFF */ AutoDetect,
|
||||
/* 50000 - 5FFFF */ AutoDetect,
|
||||
/* 60000 - 6FFFF */ AutoDetect,
|
||||
/* 70000 - 7FFFF */ AutoDetect,
|
||||
/* 80000 - 8FFFF */ AutoDetect,
|
||||
/* 90000 - 9FFFF */ AutoDetect,
|
||||
/* TBD - can be used for UMB */
|
||||
/* A0000 - AFFFF */ Respond,
|
||||
/* B0000 - BFFFF */ Respond,
|
||||
/* C0000 - CFFFF */ Respond,
|
||||
/* D0000 - DFFFF */ Respond,
|
||||
/* E0000 - EFFFF */ Respond,
|
||||
/* Reserved (BIOS) */
|
||||
/* F0000 - FFFFF */ DontRespond,
|
||||
};
|
||||
|
||||
DMAMEM uint8_t internal_RAM1[0x7A000]; /* 0 - 488KB */
|
||||
uint8_t internal_RAM2[0x76000]; /* 488 - 640KB + 320KB UMB */
|
||||
|
||||
uint8_t psram_cs =0;
|
||||
|
||||
@ -220,7 +249,38 @@ enum Region {
|
||||
SdCard
|
||||
};
|
||||
|
||||
Region memmap[512];
|
||||
#define RAM_64K \
|
||||
Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, \
|
||||
Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram, Ram
|
||||
|
||||
#define UNUSED_64K \
|
||||
Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, \
|
||||
Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused, Unused
|
||||
|
||||
// Uncomment to disable conventional memory
|
||||
//#define RAM_64K UNUSED_64K
|
||||
|
||||
Region memmap[512] = {
|
||||
/* 640KB conventional memory */
|
||||
/* 00000 - 0FFFF */ RAM_64K,
|
||||
/* 10000 - 1FFFF */ RAM_64K,
|
||||
/* 20000 - 2FFFF */ RAM_64K,
|
||||
/* 30000 - 3FFFF */ RAM_64K,
|
||||
/* 40000 - 4FFFF */ RAM_64K,
|
||||
/* 50000 - 5FFFF */ RAM_64K,
|
||||
/* 60000 - 6FFFF */ RAM_64K,
|
||||
/* 70000 - 7FFFF */ RAM_64K,
|
||||
/* 80000 - 8FFFF */ RAM_64K,
|
||||
/* 90000 - 9FFFF */ RAM_64K,
|
||||
/* TBD - can be used for EMS or UMB */
|
||||
/* A0000 - AFFFF */ UNUSED_64K,
|
||||
/* B0000 - BFFFF */ UNUSED_64K,
|
||||
/* C0000 - CFFFF */ UNUSED_64K,
|
||||
/* D0000 - DFFFF */ UNUSED_64K,
|
||||
/* E0000 - EFFFF */ UNUSED_64K,
|
||||
/* Reserved (BIOS) */
|
||||
/* F0000 - FFFFF */ UNUSED_64K,
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
@ -305,25 +365,8 @@ void setup() {
|
||||
|
||||
//Serial.begin(9600);
|
||||
|
||||
// Populate the memory map.
|
||||
// Patch the memory map.
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(memmap)/sizeof(memmap[0]); i++) {
|
||||
memmap[i] = Unused;
|
||||
}
|
||||
|
||||
for (i = 0;
|
||||
i < (0xA0000 >> 11);
|
||||
i++) {
|
||||
memmap[i] = Ram;
|
||||
}
|
||||
|
||||
static_assert((EMS_BASE_MEM & 0x7FF) == 0);
|
||||
for (i = (EMS_BASE_MEM >> 11);
|
||||
i < ((EMS_BASE_MEM+0x10000) >> 11);
|
||||
i++) {
|
||||
memmap[i] = EmsWindow;
|
||||
}
|
||||
|
||||
static_assert((BOOTROM_ADDR & 0x7FF) == 0);
|
||||
static_assert((sizeof(BOOTROM) % 2048) == 0, "BootROM must be in blocks of 2KB");
|
||||
for (i = (BOOTROM_ADDR >> 11);
|
||||
@ -331,7 +374,6 @@ void setup() {
|
||||
i++) {
|
||||
memmap[i] = BootRom;
|
||||
}
|
||||
|
||||
memmap[(BOOTROM_ADDR+sizeof(BOOTROM)) >> 11] = SdCard;
|
||||
}
|
||||
|
||||
@ -454,7 +496,7 @@ inline void PSRAM_Configure() {
|
||||
|
||||
inline uint8_t PSRAM_Read(uint32_t address_in) {
|
||||
|
||||
if (address_in >= EMS_TOTAL_SIZE) {
|
||||
if (address_in >= EMS_MAX_SIZE) {
|
||||
return 0xff;
|
||||
}
|
||||
if (address_in >= 0x7FFFFF) psram_cs=1; else psram_cs=0;
|
||||
@ -502,7 +544,7 @@ inline uint8_t PSRAM_Read(uint32_t address_in) {
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
inline void PSRAM_Write(uint32_t address_in , int8_t local_data) {
|
||||
if (address_in >= EMS_TOTAL_SIZE) {
|
||||
if (address_in >= EMS_MAX_SIZE) {
|
||||
return;
|
||||
}
|
||||
if (address_in >= 0x7FFFFF) psram_cs=1; else psram_cs=0;
|
||||
@ -539,20 +581,13 @@ inline void PSRAM_Write(uint32_t address_in , int8_t local_data) {
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
|
||||
inline uint8_t Internal_RAM_Read() {
|
||||
uint8_t local_temp;
|
||||
|
||||
if (isa_address<0x60000) local_temp = internal_RAM1[isa_address];
|
||||
else local_temp = internal_RAM2[isa_address-0x60000];
|
||||
|
||||
return local_temp;
|
||||
if (isa_address<sizeof(internal_RAM1)) return internal_RAM1[isa_address];
|
||||
else return internal_RAM2[isa_address-sizeof(internal_RAM1)];
|
||||
}
|
||||
|
||||
inline void Internal_RAM_Write() {
|
||||
|
||||
if (isa_address<0x60000) internal_RAM1[isa_address] = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
else internal_RAM2[isa_address-0x60000] = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
|
||||
return;
|
||||
if (isa_address<sizeof(internal_RAM1)) internal_RAM1[isa_address] = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
else internal_RAM2[isa_address-sizeof(internal_RAM1)] = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------------------------------
|
||||
@ -567,10 +602,10 @@ inline void Mem_Read_Cycle()
|
||||
case EmsWindow:
|
||||
page_base_address = (isa_address & 0xFC000);
|
||||
|
||||
if (page_base_address == (EMS_BASE_MEM | 0xC000)) { psram_address = (ems_frame_pointer[3]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == (EMS_BASE_MEM | 0x8000)) { psram_address = (ems_frame_pointer[2]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == (EMS_BASE_MEM | 0x4000)) { psram_address = (ems_frame_pointer[1]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == (EMS_BASE_MEM | 0x0000)) { psram_address = (ems_frame_pointer[0]<<14) | (isa_address & 0x03FFF); }
|
||||
if (page_base_address == ((ems_base_segment<<4) | 0xC000)) { psram_address = (ems_frame_pointer[3]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == ((ems_base_segment<<4) | 0x8000)) { psram_address = (ems_frame_pointer[2]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == ((ems_base_segment<<4) | 0x4000)) { psram_address = (ems_frame_pointer[1]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == ((ems_base_segment<<4) | 0x0000)) { psram_address = (ems_frame_pointer[0]<<14) | (isa_address & 0x03FFF); }
|
||||
|
||||
GPIO7_DR = MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out;
|
||||
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_LOW + DATA_OE_n_LOW ; // Assert CHRDY_n=0 to begin wait states
|
||||
@ -588,17 +623,11 @@ inline void Mem_Read_Cycle()
|
||||
isa_data_out = Internal_RAM_Read();
|
||||
GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out;
|
||||
|
||||
// XTMax_MEM_Response_Array
|
||||
// - Array holds value 0,1,2
|
||||
// 0 = unitiailzed - add wait states and snoop
|
||||
// 1 = No wait states and no response
|
||||
// 2 = No wait states and yes respond
|
||||
//
|
||||
// If XTMax has not seen a read access to this 64 KB page yet, add wait states to give physical RAM (if present) a chance to respond
|
||||
if (XTMax_MEM_Response_Array[(isa_address>>16)] == 2) {
|
||||
if (XTMax_MEM_Response_Array[(isa_address>>16)] == Respond) {
|
||||
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_LOW; // Physical RAM is NOT present at this page so XTMax will respond
|
||||
}
|
||||
else if (XTMax_MEM_Response_Array[(isa_address>>16)] == 0) {
|
||||
else if (XTMax_MEM_Response_Array[(isa_address>>16)] == AutoDetect) {
|
||||
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_LOW + DATA_OE_n_HIGH; // Assert CHRDY_n=0 to begin wait states
|
||||
delayNanoseconds(800);
|
||||
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH; // De-assert CHRDY
|
||||
@ -607,10 +636,10 @@ inline void Mem_Read_Cycle()
|
||||
data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
|
||||
if (data_in == isa_data_out) {
|
||||
XTMax_MEM_Response_Array[(isa_address>>16)] = 1; // Physical RAM is present at this page so XTMax should not respond
|
||||
XTMax_MEM_Response_Array[(isa_address>>16)] = DontRespond; // Physical RAM is present at this page so XTMax should not respond
|
||||
}
|
||||
else {
|
||||
XTMax_MEM_Response_Array[(isa_address>>16)] = 2;
|
||||
XTMax_MEM_Response_Array[(isa_address>>16)] = Respond;
|
||||
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_LOW; // Physical RAM is NOT present at this page so XTMax will respond
|
||||
}
|
||||
}
|
||||
@ -662,10 +691,10 @@ inline void Mem_Write_Cycle()
|
||||
case EmsWindow:
|
||||
page_base_address = (isa_address & 0xFC000);
|
||||
|
||||
if (page_base_address == (EMS_BASE_MEM | 0xC000)) { psram_address = (ems_frame_pointer[3]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == (EMS_BASE_MEM | 0x8000)) { psram_address = (ems_frame_pointer[2]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == (EMS_BASE_MEM | 0x4000)) { psram_address = (ems_frame_pointer[1]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == (EMS_BASE_MEM | 0x0000)) { psram_address = (ems_frame_pointer[0]<<14) | (isa_address & 0x03FFF); }
|
||||
if (page_base_address == ((ems_base_segment<<4) | 0xC000)) { psram_address = (ems_frame_pointer[3]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == ((ems_base_segment<<4) | 0x8000)) { psram_address = (ems_frame_pointer[2]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == ((ems_base_segment<<4) | 0x4000)) { psram_address = (ems_frame_pointer[1]<<14) | (isa_address & 0x03FFF); }
|
||||
else if (page_base_address == ((ems_base_segment<<4) | 0x0000)) { psram_address = (ems_frame_pointer[0]<<14) | (isa_address & 0x03FFF); }
|
||||
|
||||
GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_HIGH + CHRDY_OUT_LOW + trigger_out;
|
||||
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_LOW + CHRDY_OE_n_LOW + DATA_OE_n_HIGH; // Steer data mux to Data[7:0] and Assert CHRDY_n=0 to begin wait states
|
||||
@ -736,16 +765,18 @@ inline void IO_Read_Cycle()
|
||||
{
|
||||
isa_address = 0xFFFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
|
||||
if ((isa_address&0x0FF8)==EMS_BASE_IO) { // Location of 16 KB Expanded Memory page frame pointers
|
||||
if ((isa_address&0x0FF0)==MMAN_BASE) { // Location of Memory MANager registers
|
||||
switch (isa_address) {
|
||||
case EMS_BASE_IO : isa_data_out = ems_frame_pointer[0]; break;
|
||||
case EMS_BASE_IO+1: isa_data_out = ems_frame_pointer[0] >> 8; break;
|
||||
case EMS_BASE_IO+2: isa_data_out = ems_frame_pointer[1]; break;
|
||||
case EMS_BASE_IO+3: isa_data_out = ems_frame_pointer[1] >> 8; break;
|
||||
case EMS_BASE_IO+4: isa_data_out = ems_frame_pointer[2]; break;
|
||||
case EMS_BASE_IO+5: isa_data_out = ems_frame_pointer[2] >> 8; break;
|
||||
case EMS_BASE_IO+6: isa_data_out = ems_frame_pointer[3]; break;
|
||||
case EMS_BASE_IO+7: isa_data_out = ems_frame_pointer[3] >> 8; break;
|
||||
case MMAN_BASE+0 : isa_data_out = ems_frame_pointer[0]; break;
|
||||
case MMAN_BASE+1 : isa_data_out = ems_frame_pointer[0] >> 8; break;
|
||||
case MMAN_BASE+2 : isa_data_out = ems_frame_pointer[1]; break;
|
||||
case MMAN_BASE+3 : isa_data_out = ems_frame_pointer[1] >> 8; break;
|
||||
case MMAN_BASE+4 : isa_data_out = ems_frame_pointer[2]; break;
|
||||
case MMAN_BASE+5 : isa_data_out = ems_frame_pointer[2] >> 8; break;
|
||||
case MMAN_BASE+6 : isa_data_out = ems_frame_pointer[3]; break;
|
||||
case MMAN_BASE+7 : isa_data_out = ems_frame_pointer[3] >> 8; break;
|
||||
case MMAN_BASE+15: isa_data_out = memmap[umb_base_segment >> 7]; break; // Useful for debugging
|
||||
default: isa_data_out = 0xff; break;
|
||||
}
|
||||
|
||||
GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out;
|
||||
@ -785,28 +816,53 @@ inline void IO_Write_Cycle()
|
||||
{
|
||||
isa_address = 0xFFFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
|
||||
if ((isa_address&0x0FF8)==EMS_BASE_IO) { // Location of 16 KB Expanded Memory page frame pointers
|
||||
if ((isa_address&0x0FF0)==MMAN_BASE) { // Location of Memory MANager registers
|
||||
GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_HIGH + CHRDY_OUT_LOW + trigger_out;
|
||||
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_LOW + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH;
|
||||
|
||||
delayNanoseconds(50); // Give some time for write data to be available after IOWR_n goes low
|
||||
gpio6_int = GPIO6_DR;
|
||||
data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
|
||||
switch (isa_address) {
|
||||
case MMAN_BASE+0 : ems_frame_pointer[0] = (ems_frame_pointer[0] & 0xFF00) | data_in; break;
|
||||
case MMAN_BASE+1 : ems_frame_pointer[0] = (ems_frame_pointer[0] & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case MMAN_BASE+2 : ems_frame_pointer[1] = (ems_frame_pointer[1] & 0xFF00) | data_in; break;
|
||||
case MMAN_BASE+3 : ems_frame_pointer[1] = (ems_frame_pointer[1] & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case MMAN_BASE+4 : ems_frame_pointer[2] = (ems_frame_pointer[2] & 0xFF00) | data_in; break;
|
||||
case MMAN_BASE+5 : ems_frame_pointer[2] = (ems_frame_pointer[2] & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case MMAN_BASE+6 : ems_frame_pointer[3] = (ems_frame_pointer[3] & 0xFF00) | data_in; break;
|
||||
case MMAN_BASE+7 : ems_frame_pointer[3] = (ems_frame_pointer[3] & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case MMAN_BASE+10: ems_base_segment = (ems_base_segment & 0xFF00) | data_in; break;
|
||||
case MMAN_BASE+11: ems_base_segment = (ems_base_segment & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case MMAN_BASE+12: // Num 16K pages + commit operation
|
||||
if (ems_base_segment >= 0xA000 && ems_base_segment + (data_in << 10) <= 0xF000) {
|
||||
const unsigned int base = ems_base_segment >> 7; // 64K segment to 2KB offset
|
||||
const unsigned int count = data_in << 3; // 16KB pages to 2KB pages
|
||||
for (unsigned int i = 0; i < count; i++) {
|
||||
memmap[base + i] = EmsWindow;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MMAN_BASE+13: umb_base_segment = (umb_base_segment & 0xFF00) | data_in; break;
|
||||
case MMAN_BASE+14: umb_base_segment = (umb_base_segment & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case MMAN_BASE+15: // Num 2K pages + commit operation
|
||||
if (umb_base_segment >= 0xA000 && umb_base_segment + (data_in << 7) <= 0xF000) {
|
||||
const unsigned int base = umb_base_segment >> 7; // 64K segment to 2KB offset
|
||||
for (unsigned int i = 0; i < data_in; i++) {
|
||||
memmap[base + i] = Ram;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete
|
||||
gpio6_int = GPIO6_DR;
|
||||
gpio9_int = GPIO9_DR;
|
||||
}
|
||||
|
||||
data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
|
||||
|
||||
switch (isa_address) {
|
||||
case EMS_BASE_IO : ems_frame_pointer[0] = (ems_frame_pointer[0] & 0xFF00) | data_in; break;
|
||||
case EMS_BASE_IO+1: ems_frame_pointer[0] = (ems_frame_pointer[0] & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case EMS_BASE_IO+2: ems_frame_pointer[1] = (ems_frame_pointer[1] & 0xFF00) | data_in; break;
|
||||
case EMS_BASE_IO+3: ems_frame_pointer[1] = (ems_frame_pointer[1] & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case EMS_BASE_IO+4: ems_frame_pointer[2] = (ems_frame_pointer[2] & 0xFF00) | data_in; break;
|
||||
case EMS_BASE_IO+5: ems_frame_pointer[2] = (ems_frame_pointer[2] & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
case EMS_BASE_IO+6: ems_frame_pointer[3] = (ems_frame_pointer[3] & 0xFF00) | data_in; break;
|
||||
case EMS_BASE_IO+7: ems_frame_pointer[3] = (ems_frame_pointer[3] & 0x00FF) | ((uint16_t)data_in << 8); break;
|
||||
}
|
||||
|
||||
GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out;
|
||||
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH;
|
||||
}
|
||||
@ -862,10 +918,9 @@ void loop() {
|
||||
|
||||
gpio6_int = GPIO6_DR;
|
||||
gpio9_int = GPIO9_DR;
|
||||
|
||||
if ((gpio9_int&0x80000010)==0) IO_Read_Cycle(); // Isolate and check AEN and IO Rd/Wr
|
||||
else if ((gpio9_int&0x80000020)==0) IO_Write_Cycle();
|
||||
else if ((gpio9_int&0x00000040)==0) Mem_Read_Cycle();
|
||||
else if ((gpio9_int&0x00000080)==0) Mem_Write_Cycle();
|
||||
else if ((gpio9_int&0x00000080)==0) Mem_Write_Cycle();
|
||||
}
|
||||
}
|
||||
@ -3027,18 +3027,25 @@ instmsg PROC NEAR
|
||||
RET
|
||||
instmsg ENDP
|
||||
;--------------------------------------------------------------------
|
||||
; Check EMS i/o port.
|
||||
; Initialize EMS window and check EMS i/o port.
|
||||
; output
|
||||
; for lo-tech EMS board, we cannot read from the page registers
|
||||
; hence we just return OK anyway.
|
||||
; cf = 0 : OK
|
||||
; cf = 1 : NG
|
||||
;--------------------------------------------------------------------
|
||||
ckemsio PROC NEAR
|
||||
MOV DX,CS:EMSIO
|
||||
; JJP IN AL,DX
|
||||
; JJP CMP AL,255 ;check TRS flag
|
||||
; JJP JE ckems3
|
||||
ADD DX,10 ; EMS segment register
|
||||
MOV AX,CS:PAGE_FRAME_SEG
|
||||
OUT DX,AX
|
||||
ADD DX,3 ; debug base register
|
||||
OUT DX,AX
|
||||
DEC DX ; EMS pages count register
|
||||
MOV AL,PHYS_PAGES
|
||||
OUT DX,AL
|
||||
ADD DX,3 ; debug register
|
||||
IN AL,DX
|
||||
CMP AL,2 ; Region::EmsWindow
|
||||
JNE ckems3
|
||||
ckems4:
|
||||
CLC ;reset CF
|
||||
RET
|
||||
@ -3520,9 +3527,9 @@ info:
|
||||
; EMM driver initial routine work data area
|
||||
;--------------------------------------------------------------------
|
||||
start_msg db CR,LF
|
||||
DB 'XTEMM: EMM Driver for XTMax r02',CR,LF
|
||||
DB 'XTEMM: EMM Driver for XTMax r03',CR,LF
|
||||
db ' Based on Lo-tech EMM Driver for the Lo-tech 2MB EMS board.',CR,LF
|
||||
db ' Based on modifications by Michael Karcher.',CR,LF
|
||||
db ' Based on modifications by Michael Karcher.',CR,LF
|
||||
db ' Based on original works Copyright (c) 1988, Alex Tsourikov.',CR,LF
|
||||
db ' All rights reserved.',CR,LF
|
||||
db 'Using EMS '
|
||||
|
||||
@ -29,7 +29,6 @@ Syntax: DEVICE=LTEMM.EXE [/switches]
|
||||
/i:nnn - EMS i/o port base address (260)
|
||||
/h:nnn - Maximal number of handles (64)
|
||||
/d:nn - Depth of contest saves (5)
|
||||
/f:nnn - First page number (0)
|
||||
/n - Bypass memory test
|
||||
/x - Perform long memory test
|
||||
/3 - Use only EMS 3.2 functions
|
||||
|
||||
130
XTMax/Drivers/README.md
Normal file
130
XTMax/Drivers/README.md
Normal file
@ -0,0 +1,130 @@
|
||||
# XTMax Device Drivers
|
||||
|
||||
## BIOS Extension ROM for SD Card (BootROM)
|
||||
|
||||
The XTMax maps a BIOS Extension ROM at address 0xCE000-0xCE7FF, plus a bank of registers at address 0xCE800-0xCEFFF.
|
||||
|
||||
The BIOS Extension ROM presents the SD Card on the Teensy as a fixed disk drive that can be used for booting and/or for
|
||||
storage in MS-DOS and other operating systems using INT13h fixed disk services (note: OS/2 does not use INT13h fixed
|
||||
disk services and therefore cannot use the SD Card).
|
||||
|
||||
The ROM can be relocated by changing the address `BOOTROM_ADDR` in the [`bootrom.h`](../Code/XTMax/bootrom.h) and
|
||||
re-deploying the Teensy sketch. The address **must** be a multiple of 2048 bytes (2KB) and must be within the range
|
||||
0xC8000-DF800 (this is the range that the BIOS searches).
|
||||
|
||||
### Preparing an SD Card for use with MS-DOS
|
||||
|
||||
The preferred method for preparing an SD Card for use is to use the machine with the XTMax. From an MS-DOS prompt, begin
|
||||
with re-writing the Master Boot Record (MBR) onto the SD Card. This is needed in order to make sure that the SD Card can
|
||||
be used for booting. Modern devices are shipped pre-formatted with an MBR that is not compatible with older x86
|
||||
micro-processors.
|
||||
|
||||
```
|
||||
A:\> FDISK /MBR
|
||||
```
|
||||
|
||||
Next, partitions can be created on the SD Card with `FDISK`.
|
||||
|
||||
```
|
||||
A:\> FDISK
|
||||
```
|
||||
|
||||
If there is another fixed disk drive, be sure to select the correct drive from the `FDISK` menu. The existing partition
|
||||
on the SD Card must first be deleted, before creating a new Primary Partition. **This will destroy the entire content of
|
||||
the SD Card**. The new Primary Partition must be set as Active if the SD Card must be used for booting.
|
||||
|
||||
The partition on the SD Card will now appear as a new logical drive, typically `C:` or `D:` depending on availability.
|
||||
|
||||
Finally, the partition must be formatted. Use `FORMAT` and use the `/S` switch if the SD Card must be used for booting.
|
||||
|
||||
Note: MS-DOS will typically limit a partition size to 2GB. However, it is possible to create 3 additional Extended
|
||||
Partitions to increase the usage of the SD Card. These partitions will appear as new logical drives, such as `E:`, `F:`,
|
||||
etc... depending on availability.
|
||||
|
||||
## MS-DOS Driver for SD Card (XTSD)
|
||||
|
||||
This driver is provided as a back-up option for machines without support for BIOS Extension ROMs. It is based on the
|
||||
[SDPP](https://github.com/nilseuropa/sdpp) driver originally written by Robert Armstrong and later improved by Dan
|
||||
Marks.
|
||||
|
||||
**This driver is not necessary when the BIOS Extension ROM is loaded by the BIOS during boot.**
|
||||
|
||||
The device driver can be found here: [`XTSD.SYS`](https://raw.githubusercontent.com/MicroCoreLabs/Projects/master/XTMax/Drivers/XTSD.SYS).
|
||||
Once downloaded, it must be placed on a drive accessible during boot and must be invoked from `CONFIG.SYS` as shown in
|
||||
the example below:
|
||||
|
||||
```
|
||||
DEVICE=A:\XTSD.SYS
|
||||
```
|
||||
|
||||
When loaded, the driver will create a new logical drive for the SD Card, typically `C:` or `D:` depending on
|
||||
availability.
|
||||
|
||||
### Preparing an SD Card for use with MS-DOS
|
||||
|
||||
The SD Card can be prepared from another machine. In this example, the SD Card is prepared from a Windows 10/11 machine.
|
||||
|
||||
Use `DISKPART`. First, use `LIST DISK` to find the disk number of the SD Card then `SELECT DISK #` with the appropriate
|
||||
disk number.
|
||||
|
||||
Next, use `CLEAN` to delete all partitions. **This will destroy the entire content of the SD Card**.
|
||||
|
||||
Finally, create a new partition with `CREATE PART PRIMARY SIZE=#` by specifying the desired partition size in MB.
|
||||
Depending on the version of MS-DOS on the machine that will be using the SD Card, there are limit on the size (typically
|
||||
2048 ie 2GB).
|
||||
|
||||
The partition must be formatted, for example with `FORMAT #: /FS:FAT /Q`.
|
||||
|
||||
## EMS Driver for MS-DOS (XTEMM)
|
||||
|
||||
This driver provides LIM 4.0 Expanded Memory (EMS) through the [PSRAM](https://www.pjrc.com/store/psram.html) on the
|
||||
Teensy. It is based on the LoTech [`LTEMM.EXE`](https://www.lo-tech.co.uk/wiki/LTEMM.EXE) driver and inspired by work by
|
||||
Alex Tsourikov and Michael Karcher. Note that while the driver is compliant with EMS 4.0, it does not support memory
|
||||
back-filling.
|
||||
|
||||
The device driver can be found here: [`XTEMM.EXE`](https://raw.githubusercontent.com/MicroCoreLabs/Projects/master/XTMax/Drivers/XTEMM.EXE).
|
||||
Once downloaded, it must be placed on a drive accessible during boot and must be invoked from `CONFIG.SYS` as shown in
|
||||
the example below:
|
||||
|
||||
```
|
||||
DEVICE=A:\XTEMM.EXE /N
|
||||
```
|
||||
|
||||
The address of the memory window used by the EMS driver is 0xD0000-0xDFFFF by default and can be changed with the `/P`
|
||||
argument. For example, to use segment 0xE000 (mapping to 0xE0000-0xEFFFF), the syntax is as follows:
|
||||
|
||||
```
|
||||
DEVICE=A:\XTEMM.EXE /P:E000 /N
|
||||
```
|
||||
|
||||
## UMB Driver for MS-DOS (XTUMBS)
|
||||
|
||||
This driver provides Upper Memory Blocks (UMBs) in unused regions of the Upper Memory Area (UMA). It is based on the
|
||||
`USE!UMBS` driver originally written by Marco van Zwetselaar and later rewritten by Krister Nordvall and published on
|
||||
the [VCFED forum](https://forum.vcfed.org/index.php?threads/loading-dos-high-on-a-xt.32320/).
|
||||
|
||||
The device driver can be found here: [`XTUMBS.SYS`](https://raw.githubusercontent.com/MicroCoreLabs/Projects/master/XTMax/Drivers/XTUMBS.SYS).
|
||||
Once downloaded, it must be placed on a drive accessible during boot and must be invoked from `CONFIG.SYS` as shown in
|
||||
the example below:
|
||||
|
||||
```
|
||||
DEVICE=A:\XTUMBS.SYS D000-E000
|
||||
```
|
||||
|
||||
In the example above, the memory region at 0xD0000-0xDFFFF will be used as an UMB. **Care must be taken to not conflict
|
||||
with other memory regions used by periperals or other drivers.** For example, the region at 0xD0000 may also be used
|
||||
by the EMS driver, and both drivers shall not be configured to conflict with each other.
|
||||
|
||||
The XTMax can create UMBs at any address within the 0xA0000-0xEFFFF range. The only restriction is that the address and
|
||||
size of the UMB must be a multiple of 2048 bytes (2KB).
|
||||
|
||||
The `XTUMBS` driver can accept several ranges for UMBs, as shown in the example below with two distinct ranges:
|
||||
|
||||
```
|
||||
DEVICE=A:\XTUMBS.SYS A000-B000 D000-E000
|
||||
```
|
||||
|
||||
**Note that the XTMax only enables RAM for the UMBs upon loading the `XTUMBS` driver. Therefore, tools such as
|
||||
[`TEST!UMB.EXE](https://raw.githubusercontent.com/MicroCoreLabs/Projects/master/XTMax/Drivers/TEST!UMB.EXE) cannot be used to
|
||||
identify available UMBs.** Instead, the user must identify the unavailable ranges (such as video RAM or ROMs) with tools
|
||||
like CheckIt! and determine which ranges are safe to use as UMBs.
|
||||
BIN
XTMax/Drivers/TEST!UMB.EXE
Normal file
BIN
XTMax/Drivers/TEST!UMB.EXE
Normal file
Binary file not shown.
2
XTMax/Drivers/USEUMB/.gitignore
vendored
Normal file
2
XTMax/Drivers/USEUMB/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.sys
|
||||
*.exe
|
||||
20
XTMax/Drivers/USEUMB/.vscode/tasks.json
vendored
Normal file
20
XTMax/Drivers/USEUMB/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build with NASM",
|
||||
"type": "shell",
|
||||
"command": ".\\build.cmd && copy *.SYS ..\\",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
"problemMatcher": [],
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
24
XTMax/Drivers/USEUMB/README
Normal file
24
XTMax/Drivers/USEUMB/README
Normal file
@ -0,0 +1,24 @@
|
||||
==============================================================
|
||||
|
||||
Please read the manual. It's only 14 pages, several of which
|
||||
you may skip. It is included in this archive under the name
|
||||
USE!UMBS.DOC. If you want to print it out (which I strongly
|
||||
recommend), simply type this command at the dos prompt:
|
||||
TYPE USE!UMBS.DOC >LPT1
|
||||
|
||||
--------------------------------------------------------------
|
||||
|
||||
I dedicated all of this software to the public domain. Feel
|
||||
free to copy it and give it to anyone you wish. If you do so,
|
||||
please copy the *entire* archive, with all of the following
|
||||
files included:
|
||||
|
||||
--------------------------------------------------------------
|
||||
|
||||
README : this file Marco van.Zwetselaar
|
||||
USE!UMBS.DOC : documentation Oorsprongpark 5
|
||||
USE!UMBS.SYS : the device driver 3581 ES Utrecht (NL)
|
||||
USE!UMBS.ASM : the source code Fido NetMail 2:281/701
|
||||
TEST!UMB.EXE : tests for UMBs Phone 030-313128
|
||||
|
||||
==============================================================
|
||||
217
XTMax/Drivers/USEUMB/TEST!UMB.ASM
Normal file
217
XTMax/Drivers/USEUMB/TEST!UMB.ASM
Normal file
@ -0,0 +1,217 @@
|
||||
TITLE Test_umb will test for Upper Memory Blocks
|
||||
|
||||
CR EQU 0Dh
|
||||
LF EQU 0Ah
|
||||
fwd EQU 00h
|
||||
bwd EQU 0FFh
|
||||
yes EQU 00h
|
||||
no EQU 0FFh
|
||||
|
||||
cseg segment public
|
||||
assume cs:cseg, ds:cseg, es:nothing
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
; Code
|
||||
|
||||
init: push cs
|
||||
pop ds
|
||||
|
||||
mov ah, 09h
|
||||
mov dx, offset hello$
|
||||
int 21h
|
||||
|
||||
cld ;lets be sure
|
||||
mov es, [initadr] ;start there (A000)
|
||||
|
||||
nxtBlk: call ChkRAM
|
||||
mov [jmpsze], 0400h ;take 400h size steps
|
||||
mov [direct], fwd ;move to the right again
|
||||
cmp [flip], yes
|
||||
jnz short sayNo
|
||||
|
||||
sayYes: mov dx, offset yesRAM$ ;found RAM
|
||||
mov [flip], yes ; indicate with flip1
|
||||
jmp short showMs
|
||||
|
||||
sayNo: mov dx, offset noRAM$ ;found no RAM
|
||||
mov [flip], no ; indicate with flip0
|
||||
|
||||
showMs: call messge ;and tell it
|
||||
|
||||
move: cmp [direct], bwd ;backward?
|
||||
jz short backw
|
||||
mov di, es
|
||||
add di, [jmpsze] ;jump forward
|
||||
mov es, di
|
||||
jc endIt
|
||||
jmp short cont
|
||||
|
||||
backw: mov di, es
|
||||
sub di, [jmpsze] ;jump backward
|
||||
mov es, di
|
||||
|
||||
cont: call ChkRAM ;check location for RAM
|
||||
jz move ;if no flip - keep jump'n
|
||||
|
||||
xor [direct], 0FFh ;invert direction
|
||||
mov ax, [jmpsze] ;get jmpsze
|
||||
shr ax, 1 ;divide by 2
|
||||
mov [jmpsze], ax ;and store new
|
||||
jnz move ;jump other way half dist'ce
|
||||
|
||||
cmp [direct], bwd ;if direction bwd, then we are
|
||||
jnz goOn ;already on begin new blk, so we
|
||||
mov di, es ;we must recede one position
|
||||
dec di ;for end of last blk
|
||||
mov es, di ;so move left one paragraph
|
||||
xor [flip], 0FFh ;don't worry, we'll flip back
|
||||
goOn: call endMes ;print this (end)location
|
||||
xor [flip], 0FFh ;but if stand before RAMflip wrong
|
||||
mov di, es ;and proceed to begin next block
|
||||
inc di
|
||||
mov es, di
|
||||
jmp nxtBlk
|
||||
|
||||
endIt: mov dx, offset last$
|
||||
mov ah, 09h
|
||||
int 21h
|
||||
mov dx, offset bye$
|
||||
int 21h
|
||||
mov dx, offset warn$
|
||||
int 21h
|
||||
mov ax, 4C00h
|
||||
int 21h
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
; Variables
|
||||
|
||||
jmpsze dw ? ;jumpsize
|
||||
initadr dw 0A000h ;starting address
|
||||
direct db fwd ;direction
|
||||
flip db yes ;ram at last loc
|
||||
|
||||
hello$ db CR,LF,'ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»',CR,LF, \
|
||||
'º Test_UMB checks for RAM in Upper Memory º',CR,LF, \
|
||||
'º ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ º$'
|
||||
|
||||
yesRAM$ db CR,LF,'º ³ Found RAM at paragraph $'
|
||||
noRAM$ db CR,LF,'º ³ None at paragraph $'
|
||||
contd$ db '#### until $'
|
||||
endMes$ db '#### ³ º$'
|
||||
last$ db 'FFFF ³ º',CR,LF,'$'
|
||||
|
||||
bye$ db 'º ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ º',CR,LF, \
|
||||
'º Author: Marco van Zwetselaar 8 Nov 1991 º',CR,LF, \
|
||||
'ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ',CR,LF,'$'
|
||||
|
||||
warn$ db CR,LF,'PLEASE NOTE: Not all RAM displayed can be used!',CR,LF, \
|
||||
' In *general*, segment A, D and E are safe.',CR,LF,CR,LF,'$'
|
||||
|
||||
;-------------------------------------------------------------------
|
||||
; Procedures
|
||||
|
||||
chkram proc near
|
||||
|
||||
;takes : es : is paragraph to test
|
||||
;destr : di, bx, dx, cx
|
||||
;retur : zeroflag if flips equal, dl=old flip (FF=none, 00=RAM)
|
||||
|
||||
xor di, di
|
||||
mov bx, es:[di] ;get memory contents at es:0
|
||||
mov dx, bx ;store in dx
|
||||
xor dx, 0FFFFh ;invert all bits
|
||||
mov es:[di], dx ;and store in memory again
|
||||
mov cx, 080h ;Pause a moment, so that
|
||||
loop $ ;we don't read what we wrote
|
||||
cmp es:[di], dx ;compare to what we put there
|
||||
mov es:[di], bx ;and restore original value
|
||||
mov dl, [flip] ;save old flip
|
||||
jz flip0 ;found ram?
|
||||
mov [flip], no ; NOT - flip to no
|
||||
jmp short pfff
|
||||
flip0: mov [flip], yes ; YES - flip to yes
|
||||
pfff: cmp dl, [flip] ;set ZFlag if flipped
|
||||
ret
|
||||
|
||||
chkram endp
|
||||
|
||||
messge proc near
|
||||
|
||||
;takes : ds:dx points to mess (no/yesRAM)
|
||||
; : es is segment-addr = paragr
|
||||
;destr : di, bx, ax
|
||||
;retur : unimportant - will print mess & addresses
|
||||
|
||||
mov ah, 09h ;print yes/noRAM
|
||||
int 21h
|
||||
|
||||
mov dx, es ;paragraph into dx
|
||||
mov di, offset contd$ ;point di to location where
|
||||
push es
|
||||
push cs ; it should be patched in
|
||||
pop es
|
||||
mov bx, offset digs ;ds:bx point to begin xtable
|
||||
mov ax, dx ;dx is paragraph address
|
||||
xchg al, ah ;ah patched 1st: must be in al
|
||||
call makehex
|
||||
mov ax, dx ;then patch al in
|
||||
call makehex
|
||||
mov dx, offset contd$ ;then print rest of messge
|
||||
mov ah, 09h
|
||||
int 21h
|
||||
pop es
|
||||
|
||||
ret
|
||||
|
||||
messge endp
|
||||
|
||||
endMes proc near
|
||||
|
||||
mov dx, es ;paragraph number in dx=es
|
||||
mov di, offset endMes$ ;point es:di to patch
|
||||
push es ;but save es for later!
|
||||
push cs
|
||||
pop es
|
||||
mov bx, offset digs ;point ds:bx to xlat tbl
|
||||
mov ax, dx
|
||||
xchg al, ah
|
||||
call makehex
|
||||
mov ax, dx
|
||||
call makehex
|
||||
mov dx, offset endMes$ ;and show endlocation
|
||||
mov ah, 09h
|
||||
int 21h
|
||||
pop es ;reset es
|
||||
|
||||
ret
|
||||
|
||||
endMes endp
|
||||
|
||||
makehex proc near
|
||||
|
||||
;takes : al : byte to be conv'ted to ascii (like FCh - 'FC')
|
||||
; ds:bx : points to beginning of xlat table
|
||||
; es:di : points to location where "XX" should come
|
||||
;destr : ax, di will point two bytes further
|
||||
;retur : ascii digits in locations es:di and es:di+1
|
||||
|
||||
db 0D4h, 010h ;adjust for ascii multip: ah->ax/16
|
||||
; al->rest
|
||||
|
||||
xchg al, ah ;high nibble first
|
||||
xlat ;ds:bx must point to right dig
|
||||
stosb ;store the string-byte
|
||||
|
||||
xchg al, ah
|
||||
xlat ;low level
|
||||
stosb
|
||||
|
||||
ret
|
||||
|
||||
digs db '0123456789ABCDEF'
|
||||
|
||||
makehex endp
|
||||
|
||||
cseg ends
|
||||
end
|
||||
|
||||
470
XTMax/Drivers/USEUMB/USE!UMBS.ASM
Normal file
470
XTMax/Drivers/USEUMB/USE!UMBS.ASM
Normal file
@ -0,0 +1,470 @@
|
||||
; 1 tab = 4 spaces
|
||||
|
||||
;
|
||||
; This is a rewrite of Marco van Zwetselaar's USE!UMBS.SYS v2.0 from 1991.
|
||||
;
|
||||
; Changes in this version (v2.2);
|
||||
; * UMBs are now initialized to avoid parity errors.
|
||||
; * Minor size optimizations.
|
||||
;
|
||||
; Changes in the previous version (v2.1);
|
||||
; * This file assembles in NASM.
|
||||
; * Optimizations to reduce memory usage.
|
||||
; * Command line parameters are now used in CONFIG.SYS to specify address ranges for UMBs.
|
||||
;
|
||||
; Example for a single 128 KB UMB starting at segment D000h:
|
||||
;
|
||||
; DEVICE=USE!UMBS.SYS D000-F000
|
||||
;
|
||||
; Please report bugs to me at krille_n_@hotmail.com
|
||||
;
|
||||
; Thanks!
|
||||
;
|
||||
; Krister Nordvall
|
||||
;
|
||||
|
||||
[cpu 8086]
|
||||
|
||||
;--------------------------------------------------------------------
|
||||
; Skips the immediately following 2 byte instruction by using it
|
||||
; as an immediate value to a dummy instruction.
|
||||
; Destroys the contents of %1.
|
||||
;
|
||||
; SKIP2B
|
||||
; Parameters:
|
||||
; %1: Any 16 bit general purpose register or F for flags.
|
||||
; Returns:
|
||||
; Nothing
|
||||
; Corrupts registers:
|
||||
; %1
|
||||
;--------------------------------------------------------------------
|
||||
%macro SKIP2B 1
|
||||
%ifidni %1, f
|
||||
db 03Dh ; Opcode byte for CMP AX, <immed>
|
||||
;db 0A9h ; Alt. version TEST AX, <immed>
|
||||
%elifidni %1, ax
|
||||
db 0B8h ; Opcode byte for MOV AX, <immed>
|
||||
%elifidni %1, cx
|
||||
db 0B9h ; Opcode byte for MOV CX, <immed>
|
||||
%elifidni %1, dx
|
||||
db 0BAh ; Opcode byte for MOV DX, <immed>
|
||||
%elifidni %1, bx
|
||||
db 0BBh ; Opcode byte for MOV BX, <immed>
|
||||
%elifidni %1, sp
|
||||
db 0BCh ; Opcode byte for MOV SP, <immed>
|
||||
%elifidni %1, bp
|
||||
db 0BDh ; Opcode byte for MOV BP, <immed>
|
||||
%elifidni %1, si
|
||||
db 0BEh ; Opcode byte for MOV SI, <immed>
|
||||
%elifidni %1, di
|
||||
db 0BFh ; Opcode byte for MOV DI, <immed>
|
||||
%else
|
||||
%error "Invalid parameter passed to SKIP2B"
|
||||
%endif
|
||||
%endmacro
|
||||
|
||||
TAB equ 9
|
||||
CR equ 13
|
||||
SPACE equ 32
|
||||
|
||||
bRH_Command equ 2
|
||||
wRH_Status equ 3
|
||||
fpRH_BreakAddress equ 14
|
||||
fpRH_CommandLine equ 18
|
||||
|
||||
|
||||
org 0
|
||||
|
||||
|
||||
fpNextDeviceDriver dd -1
|
||||
wDeviceAttributeWord dw 0E000h
|
||||
wOffsetStrategyRoutine dw StrategyRoutine
|
||||
wOffsetInterruptRoutine dw InterruptRoutine
|
||||
sDeviceName db 'ZwetsUMB'
|
||||
|
||||
fpRequestHeader dd 0
|
||||
|
||||
Interrupt2FhHandler:
|
||||
cmp ah, 43h
|
||||
je SHORT RequestIsForMe
|
||||
|
||||
db 0EAh ; Far jump opcode
|
||||
fpOldInterrupt2FhHandler:
|
||||
dd 0 ; Pointer filled in during initialization
|
||||
|
||||
RequestIsForMe:
|
||||
cmp al, 10h
|
||||
jne SHORT ReturnHandlerExists
|
||||
|
||||
mov bx, UMBController
|
||||
push cs
|
||||
pop es
|
||||
iret
|
||||
|
||||
ReturnHandlerExists:
|
||||
mov al, 80h
|
||||
iret
|
||||
|
||||
|
||||
StrategyRoutine:
|
||||
mov [cs:fpRequestHeader], bx
|
||||
mov [cs:fpRequestHeader+2], es
|
||||
retf
|
||||
|
||||
|
||||
InterruptRoutine:
|
||||
push es
|
||||
push bx
|
||||
push ax
|
||||
|
||||
les bx, [cs:fpRequestHeader]
|
||||
mov al, [es:bx+bRH_Command]
|
||||
test al, al
|
||||
jz SHORT Install
|
||||
|
||||
cmp al, 10h
|
||||
jbe SHORT .NotImplemented
|
||||
mov ax, 8003h ; "Unknown command"
|
||||
SKIP2B f
|
||||
.NotImplemented:
|
||||
xor ax, ax
|
||||
|
||||
Return:
|
||||
or ax, 100h ; Set Done bit
|
||||
mov [es:bx+wRH_Status], ax
|
||||
|
||||
pop ax
|
||||
pop bx
|
||||
pop es
|
||||
retf
|
||||
|
||||
|
||||
UMBController:
|
||||
; The first 5 bytes of Himem handlers are special and must not be changed.
|
||||
jmp SHORT .CheckIfUMBorXMSrequest
|
||||
nop
|
||||
nop
|
||||
nop
|
||||
|
||||
.CheckIfUMBorXMSrequest:
|
||||
cmp ah, 10h
|
||||
je SHORT UMBrequest
|
||||
|
||||
JMPtoOurXMShandler:
|
||||
jmp SHORT XMSrequest ; This jump is patched out during init if an existing XMS handler is detected
|
||||
fpOldXMShandler equ JMPtoOurXMShandler+1
|
||||
db 0
|
||||
db 0
|
||||
db 0
|
||||
|
||||
UMBrequest:
|
||||
push si
|
||||
push cx
|
||||
push bx
|
||||
|
||||
SKIP2B si
|
||||
.wOffsetFreeUMBs:
|
||||
dw 0 ; Offset filled in during init
|
||||
|
||||
xor cx, cx
|
||||
xchg dx, cx ; DX = 0, CX = Requested block size
|
||||
|
||||
.Search:
|
||||
cs
|
||||
lodsw ; Load start address of range
|
||||
test ax, ax ; Are we at the end of the list?
|
||||
jz SHORT .NoBlockFound ; Jump if so
|
||||
mov bx, ax ; Segment is returned in BX
|
||||
inc ax ; Block already given away?
|
||||
cs
|
||||
lodsw ; Load length of block
|
||||
jz SHORT .Search ; If yes, get next block
|
||||
cmp dx, ax ; Is it larger than the largest found so far?
|
||||
ja SHORT .CheckSize ; If not, check size to see if it's large enough
|
||||
mov dx, ax ; It is so save it as the largest so far
|
||||
|
||||
.CheckSize:
|
||||
cmp cx, ax ; Large enough to fulfill request?
|
||||
ja SHORT .Search ; Jump if not
|
||||
|
||||
mov WORD [cs:si-4], 0FFFFh ; Mark as given away
|
||||
mov dx, 1 ; Return Success in AX and size of block in DX
|
||||
xchg dx, ax
|
||||
pop cx ; Remove BX from stack
|
||||
jmp SHORT .Return
|
||||
|
||||
.NoBlockFound:
|
||||
pop bx ; Restore BX
|
||||
mov bl, 0B0h ; Return "Smaller UMB available" in BL
|
||||
test dx, dx ; Size of largest block found = 0?
|
||||
jnz SHORT .Return ; If not, assumption was correct
|
||||
inc bx ; Yes, return "No UMBs available" instead
|
||||
|
||||
.Return:
|
||||
pop cx
|
||||
pop si
|
||||
retf
|
||||
|
||||
|
||||
XMSrequest:
|
||||
test ah, ah ; Get XMS version?
|
||||
jnz SHORT .NotGetVersion
|
||||
|
||||
xor bx, bx ; Internal revision number
|
||||
cwd ; HMA not present
|
||||
jmp SHORT .Return
|
||||
|
||||
.NotGetVersion:
|
||||
cmp ah, 8 ; Query extended memory?
|
||||
jne SHORT .NotQueryExtendedMem
|
||||
cwd ; 0 KB extended memory
|
||||
|
||||
.NotQueryExtendedMem:
|
||||
mov bl, 80h ; Error: Not implemented
|
||||
|
||||
.Return:
|
||||
xor ax, ax ; Always return failure
|
||||
retf
|
||||
|
||||
|
||||
Install:
|
||||
push cx
|
||||
push dx
|
||||
push ds
|
||||
push si
|
||||
|
||||
push cs
|
||||
pop ds
|
||||
|
||||
mov ah, 9
|
||||
mov dx, s$Hello1
|
||||
int 21h
|
||||
mov dx, s$Author
|
||||
int 21h
|
||||
|
||||
; Is there an XMS handler already?
|
||||
mov ax, 4300h
|
||||
int 2Fh
|
||||
cmp al, 80h
|
||||
jne SHORT .OKtoInstall ; No, it's OK to install (with our handler)
|
||||
|
||||
; Yes, patch out the short unconditional jump to our XMS handler
|
||||
mov BYTE [JMPtoOurXMShandler], 0EAh ; 'jmp far ...'
|
||||
|
||||
; Then get the address to the old handler and store it
|
||||
mov ax, 4310h
|
||||
int 2Fh
|
||||
mov [fpOldXMShandler], bx
|
||||
mov [fpOldXMShandler+2], es
|
||||
|
||||
; To reduce memory usage we also move the breakpoint to exclude our XMS handler
|
||||
mov WORD [.wOffsetBreakpoint], XMSrequest
|
||||
|
||||
; Tell the user we found an existing handler
|
||||
mov ah, 9
|
||||
mov dx, s$XMMfound
|
||||
int 21h
|
||||
|
||||
; Check if it services UMBs by trying to allocate far too much
|
||||
mov ah, 10h
|
||||
cwd
|
||||
dec dx
|
||||
call FAR [fpOldXMShandler]
|
||||
|
||||
; Assume we are not needed
|
||||
mov dx, s$NotInstalled
|
||||
xor ax, ax
|
||||
|
||||
cmp bl, 80h ; Error: Not implemented?
|
||||
je SHORT .OKtoInstall
|
||||
jmp .StoreBreakPointer
|
||||
|
||||
.OKtoInstall:
|
||||
; Get the breakpoint (Install or XMSrequest) to BX and store it as the start of the FreeUMBs list
|
||||
mov bx, [.wOffsetBreakpoint]
|
||||
mov [UMBrequest.wOffsetFreeUMBs], bx
|
||||
|
||||
; Time to interpret the command line in CONFIG.SYS
|
||||
lds si, [fpRequestHeader]
|
||||
lds si, [si+fpRH_CommandLine]
|
||||
|
||||
push cs ; For restoring DS later
|
||||
|
||||
mov cx, 4 ; Hex digit count in CH = 0, Shift count in CL = 4
|
||||
xor ah, ah ; WORD parameter count in AH
|
||||
; First scan until we find a whitespace (tab or space) to find the start of parameters
|
||||
.SearchForWhiteSpace:
|
||||
lodsb
|
||||
cmp al, CR
|
||||
je .EndOfLineEncountered
|
||||
cmp al, SPACE
|
||||
je SHORT .SearchForParameter
|
||||
cmp al, TAB
|
||||
jne SHORT .SearchForWhiteSpace
|
||||
|
||||
; We've found the first whitespace which means we've reached the end of the path+filename
|
||||
.SearchForParameter:
|
||||
lodsb
|
||||
cmp al, CR
|
||||
je SHORT .EndOfLineEncountered
|
||||
cmp al, SPACE
|
||||
je SHORT .SearchForParameter
|
||||
cmp al, TAB
|
||||
je SHORT .SearchForParameter
|
||||
|
||||
; We have the first byte of a parameter
|
||||
dec si
|
||||
.NextHexDigit:
|
||||
lodsb
|
||||
inc ch
|
||||
cmp al, '9'
|
||||
jbe SHORT .NotAtoF
|
||||
and al, ~32
|
||||
cmp al, 'F'
|
||||
ja SHORT .ParameterError
|
||||
cmp al, 'A'
|
||||
jb SHORT .ParameterError
|
||||
sub al, 7
|
||||
.NotAtoF:
|
||||
sub al, '0'
|
||||
jb SHORT .ParameterError
|
||||
shl dx, cl
|
||||
or dl, al
|
||||
and ch, 3
|
||||
jnz SHORT .NextHexDigit
|
||||
|
||||
; We have a complete WORD in DX
|
||||
inc ah ; Increment WORD count
|
||||
sahf ; WORD count Odd or Even?
|
||||
jc SHORT .FirstWordOfParameter
|
||||
sub dx, [cs:bx-2] ; Convert end of range to length
|
||||
jbe SHORT .ParameterError ; End of range below or equal to start of range
|
||||
|
||||
; Program the range
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
mov ax, [cs:bx-2]
|
||||
mov bx, dx
|
||||
mov dx, 26dh ; UMB base register
|
||||
out dx, ax
|
||||
mov dx, 26fh ; UMB pages count register
|
||||
mov ax, bx
|
||||
mov cl, 7
|
||||
shr ax, cl ; bytes to 2K pages
|
||||
out dx, al
|
||||
shl ax, cl ; 2K pages (back) to bytes
|
||||
mov dx, ax
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
test dx, dx
|
||||
jz SHORT .ParameterError ; Range was smaller than 2KB
|
||||
.FirstWordOfParameter:
|
||||
mov [cs:bx], dx
|
||||
inc bx
|
||||
inc bx
|
||||
lodsb
|
||||
sahf
|
||||
jc SHORT .CheckIfDash
|
||||
cmp al, CR
|
||||
je SHORT .EndOfLineEncountered
|
||||
cmp al, SPACE
|
||||
je SHORT .SearchForParameter
|
||||
cmp al, TAB
|
||||
je SHORT .SearchForParameter
|
||||
SKIP2B ax ; Fall through to .ParameterError
|
||||
.CheckIfDash:
|
||||
cmp al, '-'
|
||||
je SHORT .NextHexDigit
|
||||
|
||||
.ParameterError:
|
||||
pop ds ; DS = CS
|
||||
|
||||
mov dx, s$ParamError
|
||||
xor ax, ax
|
||||
jmp SHORT .StoreBreakPointer
|
||||
|
||||
.EndOfLineEncountered:
|
||||
test ah, ah
|
||||
jz SHORT .ParameterError ; No parameters at all
|
||||
|
||||
pop ds ; DS = CS
|
||||
|
||||
mov WORD [bx], 0 ; End of Free UMBs block marker
|
||||
inc bx
|
||||
inc bx
|
||||
mov [.wOffsetBreakpoint], bx
|
||||
|
||||
; We need to initialize the UMBs by writing to every address to avoid parity errors later when reading
|
||||
mov si, [UMBrequest.wOffsetFreeUMBs]
|
||||
push di
|
||||
|
||||
.InitNextBlock:
|
||||
lodsw ; Segment address of UMB to AX
|
||||
test ax, ax
|
||||
jz SHORT .AllBlocksInitialized
|
||||
xchg bx, ax ; Save address in BX
|
||||
lodsw ; Block size in paragraphs to AX
|
||||
xor dx, dx
|
||||
xchg dx, ax ; DX = Paragraph count, AX = Zero
|
||||
xor di, di ; Point ES:DI to start of UMB
|
||||
.InitNextSegment:
|
||||
mov es, bx
|
||||
cmp dh, 10h ; Block larger than or equal to a full segment?
|
||||
jb SHORT .LessThan64KB
|
||||
mov cx, 8000h ; We need to write (at least) a full 64 KB segment
|
||||
add bh, 10h ; Add 64 KB to the segment address for the next iteration (if any)
|
||||
sub dh, 10h ; Subtract 64 KB from the paragraph count
|
||||
rep stosw
|
||||
jmp SHORT .InitNextSegment
|
||||
.LessThan64KB:
|
||||
mov cl, 3
|
||||
shl dx, cl ; Paragraphs to WORDs
|
||||
mov cx, dx ; WORD count to CX
|
||||
rep stosw
|
||||
jmp SHORT .InitNextBlock
|
||||
|
||||
.AllBlocksInitialized:
|
||||
pop di
|
||||
|
||||
; Get handler for Interrupt 2Fh and store it
|
||||
mov ax, 352Fh
|
||||
int 21h
|
||||
mov [fpOldInterrupt2FhHandler], bx
|
||||
mov [fpOldInterrupt2FhHandler+2], es
|
||||
|
||||
; Then hook it
|
||||
mov ax, 252Fh
|
||||
mov dx, Interrupt2FhHandler
|
||||
int 21h
|
||||
|
||||
; Tell the user we are installed
|
||||
mov dx, s$Installed
|
||||
SKIP2B ax
|
||||
.wOffsetBreakpoint:
|
||||
dw Install ; Default breakpoint offset is Install
|
||||
|
||||
.StoreBreakPointer:
|
||||
les bx, [fpRequestHeader]
|
||||
mov [es:bx+fpRH_BreakAddress], ax
|
||||
mov [es:bx+fpRH_BreakAddress+2], cs
|
||||
|
||||
mov ah, 9
|
||||
int 21h ; Print Installed/NotInstalled/ParamError
|
||||
|
||||
xor ax, ax ; No errors
|
||||
pop si
|
||||
pop ds
|
||||
pop dx
|
||||
pop cx
|
||||
jmp Return
|
||||
|
||||
|
||||
s$Hello1 db "XTUMBS: UMB Manager for XTMax v2.2",0Dh,0Ah,'$'
|
||||
s$Author db " Based on rewritten USE!UMBS by Krister Nordvall",0Dh,0Ah
|
||||
db " Based on original work by Marco van Zwetselaar",0Dh,0Ah,'$'
|
||||
s$XMMfound db "Found XMS Manager.",0Dh,0Ah,'$'
|
||||
s$Installed db "UMB Manager Installed.",0Dh,0Ah,0Ah,'$'
|
||||
s$NotInstalled db "Not Installed: UMB is already managed!",0Dh,0Ah,0Ah,'$'
|
||||
s$ParamError db "Not Installed: Invalid Command Line!",0Dh,0Ah,0Ah,'$'
|
||||
692
XTMax/Drivers/USEUMB/USE!UMBS.DOC
Normal file
692
XTMax/Drivers/USEUMB/USE!UMBS.DOC
Normal file
@ -0,0 +1,692 @@
|
||||
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 1
|
||||
==============================================================
|
||||
|
||||
DOCUMENTATION FOR USE!UMBS.SYS Ver 2.0 Utrecht, 21 Nov 91
|
||||
|
||||
--------------------------------------------------------------
|
||||
|
||||
PROGRAM USE!UMBS.SYS
|
||||
Upper Memory Block Manager for PC/XT/ATs
|
||||
|
||||
PURPOSE This program is a device driver that will handle
|
||||
calls for Upper Memory Blocks. In doing so, it gives
|
||||
you the possibility to save conventional memory by
|
||||
storing device drivers and resident programs in the
|
||||
UMBs and hence save conventional memory. It takes up
|
||||
only 256 bytes of your (conventional) memory and is
|
||||
fully compatible with MS-DOS 5.0.
|
||||
|
||||
REQUIRES It will work on any PC/XT/AT or higher, either with
|
||||
or without extended memory. What you obviously
|
||||
*must* have are UMBs, and MS-DOS Version 5.0. It
|
||||
will not be useful on 386sx or higher.
|
||||
|
||||
EXTRA'S Since Video-RAM is RAM in Upper Memory too, you can
|
||||
use it just as well as other UMBs. You only have to
|
||||
take care that you use an UNused part of Video memo-
|
||||
ry.
|
||||
|
||||
PROBLEMS Since ExPANded Memory is remapped to the range of
|
||||
addresses where UMBs would normally be, I think this
|
||||
program will not cooperate with your expanded memory
|
||||
manager. Since I could not test the program on many
|
||||
different configurations, I kindly ask you to report
|
||||
any problems to me. I don't expect many problems
|
||||
though, since USE!UMBS is a `friendly' programme: it
|
||||
complies completely with the rules of MS-DOS 5.0.
|
||||
|
||||
AUTHOR Marco van Zwetselaar Phone: 030-313128
|
||||
Oorsprongpark 5 Email: zwets@rivm.nl
|
||||
3581 ES Utrecht
|
||||
The Netherlands
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 2
|
||||
==============================================================
|
||||
|
||||
I wrote this program for my own entertainment, not in order to
|
||||
make money. Therefore I dedicate it to the Public Domain. Feel
|
||||
free to copy it and pass it on to friends - just make sure
|
||||
this documentation file is included.
|
||||
|
||||
If you find this program useful enough to reward me for writ-
|
||||
ing it, you may send me a donation anuwhere from 50 cents upto
|
||||
25 guilders. My giro number is 5636618, my snailmail address
|
||||
is displayed above.
|
||||
|
||||
If you have any questions, just contact me via one of the
|
||||
above-mentioned addresses. I will be pleased to help you out -
|
||||
whether you are a donator or not. Also, if you find any incon-
|
||||
sistencies or mistakes in this documentation, please notify me
|
||||
of them, so that I can correct them in a possible next versi-
|
||||
on. Finally, if you think you can improve the driver, please
|
||||
do so. For this purpose I have included the asm-code code in
|
||||
the archive. But if you do so: keep it well documented.
|
||||
|
||||
Marco van Zwetselaar.
|
||||
|
||||
==============================================================
|
||||
|
||||
CONTENTS
|
||||
|
||||
1. General Introduction & Definitions 3
|
||||
|
||||
2. Preparations 6
|
||||
|
||||
3. Using VideoRAM 7
|
||||
|
||||
4. Patching in the Addresses 9
|
||||
|
||||
5. Installation 12
|
||||
|
||||
Appendix 1. Functional description of driver (freaks) 13
|
||||
|
||||
Appendix 2. Detailed description of driver (utter freaks) 14
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 3
|
||||
==============================================================
|
||||
|
||||
1. General Introduction & Definition of Terms:
|
||||
|
||||
In this first section I will explain how the memory on IBM-
|
||||
compatibles is organized, and what UMBs actually are. If you
|
||||
are not interested in `backgrounds', you may skip this section
|
||||
and move on to section 2 (page 6) rightaway. (I advise you to
|
||||
at least have a glance at this section though.)
|
||||
|
||||
Conventional Memory
|
||||
Conventional memory is the memory that is present on any
|
||||
IBM or compatible. Its maximum size is 640K, and nearly
|
||||
all IBM-compatible computers have exactly that amount.
|
||||
Conventional memory is used in a conventional way, i.e.
|
||||
any user program may make use of it, as may the operating
|
||||
system. Actually, most user programs won't even use
|
||||
anything except conventional memory (unless specifically
|
||||
told to do so). Conventional memory resides in the first
|
||||
640K of the adressable memory. That is, at the addresses
|
||||
00000-9FFFF.
|
||||
|
||||
Addressable Memory
|
||||
The computer can address more than just 640K of conven-
|
||||
tional memory. The maximum amount a specific computer can
|
||||
address depends on the type of CPU it has (8086, 80286,
|
||||
and so on). But whatever CPU it may have, it can *always*
|
||||
address the first 1M of memory. (That's why it is called
|
||||
Adressable Memory, I suppose.)
|
||||
Addressable Memory consists of two parts: the first 640K
|
||||
are Conventional Memory (adresses 00000-9FFFF), the
|
||||
remaining 384K are Upper Memory (adresses A0000-FFFFF).
|
||||
|
||||
Upper Memory
|
||||
Upper Memory is the upper 384K of Adressable Memory,
|
||||
which begins just beyond the 640K conventional memory
|
||||
border. This implies that it is located at the addresses
|
||||
A0000-FFFFF.
|
||||
|
||||
Since Upper Memory is normally addressable on any PC, you
|
||||
might wonder why programs don't make use of it. The
|
||||
reasons are the following:
|
||||
(1) The operating system and the hardware make use of
|
||||
parts of it already. For example, anything you see
|
||||
on the screen is stored in an area in UM - you can
|
||||
probably imagine what will happen if you mess around
|
||||
in that area. Also the computer itself will store
|
||||
some of its vital data in UM - and we don't want to
|
||||
embarrass MS-DOS, who's having hard times already.
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 4
|
||||
==============================================================
|
||||
|
||||
(2) Even if there are parts of Upper Memory that are not
|
||||
in use already, these parts may not be RAM. What
|
||||
this means is that one may *read* data from those
|
||||
locations, but not *write* anything into them. (In
|
||||
fact, you can try and write something into them, but
|
||||
it will vanish mysteriously into thin air.)
|
||||
Most computers don't have RAM in these areas, first-
|
||||
ly because that would make the computer more expen-
|
||||
sive, and secondly because MS-DOS was not designed
|
||||
to use anything above the 640K border anyway.
|
||||
(3) Even if there are unused parts of UM that do consist
|
||||
of RAM (readable & writeable memory), dos will not
|
||||
normally make them available as conventional memory.
|
||||
This is precisely why I wrote this device driver:
|
||||
since Version 5.0, Dos can use the UMBs to store
|
||||
prog- rams, namely device drivers and TSRs. Device
|
||||
drivers are the files that you install via the DEVI-
|
||||
CE=... lines in your config.sys; they take care of
|
||||
interfacing dos with your hardware. Dos usually
|
||||
loads these devices in conventional memory. If you
|
||||
have UMBs (or a 386) you can load the devices into
|
||||
them using the DEVICEHIGH=... statement, instead of
|
||||
the DEVICE=... statement. TSRs (Terminate and Stay
|
||||
Resident) programs are programs that stay in memory
|
||||
after they are executed. Some of these programs stay
|
||||
resident so that you can invoke them during other
|
||||
programs using a HotKey (sidekick for example),
|
||||
others stay resident because they perform tasks in
|
||||
the background (like screenblankers, autopark, dos-
|
||||
key, fastopen, etc). Normally, TSRs will be loaded
|
||||
into conventional memory. Dos 5.0 provides the com-
|
||||
mand LOADHIGH (may be abbreviated to LH) to put them
|
||||
into the UMBs. You do this by preceding the TSR's
|
||||
invocation line in the autoexec.bat by LH (or LOAD-
|
||||
HIGH). So, if you 'd normally use "FASTOPEN C:=200",
|
||||
you now put "LH FASTOPEN C:=200" in the autoexec.
|
||||
|
||||
Extended Memory
|
||||
Extended Memory is, by definition, all memory that is
|
||||
located beyond the 1MB border. So, its addresses start at
|
||||
100000. Since a computer needs to have more than 20
|
||||
address lines in order to address such large addresses,
|
||||
PCs and XTs can't have extended memory (they have preci-
|
||||
sely 20 lines). On an AT or higher one can access exten-
|
||||
ded memory by enabling address lines A20 (and higher - if
|
||||
you start counting at 0, that is the 21st line and hig-
|
||||
her).
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 5
|
||||
==============================================================
|
||||
|
||||
So in order to make use of extended memory, a program
|
||||
must have a special design - more and more programs are
|
||||
offering eXtended memory support. But since many programs
|
||||
use eXtended memory in many different ways, conflicts may
|
||||
arise. In order to resolve these, a standard way of
|
||||
accessing extended memory was developed.
|
||||
This is specified in the XMS (eXtended Memory Specifica-
|
||||
tion). MS-Dos 5.0 provides you with a manager for XM -
|
||||
this manager will 'hand out' extended memory to programs
|
||||
that make a request according to XMS specs. The problem
|
||||
with dos's XMS-manager (HIMEM.SYS) is that it doesn't
|
||||
handle requests for UMBs (they simply haven't implemented
|
||||
that function, probably because most XTs and ATs don't
|
||||
have UMBs anyway). What MicroSoft does provide is
|
||||
EMM386.EXE, which is an exPANded memory manager that
|
||||
handles UMB-requests as a side-effect. The problem is
|
||||
that this manager can only be installed on 386s or hig-
|
||||
her. The reason for this is that only a 386 has the
|
||||
ability to 'remap' expanded memory to UMB locations, thus
|
||||
providing RAM in Upper Memory locations.
|
||||
|
||||
So, what can you do if you have UMBs on an XT or AT?
|
||||
Suppose you have extended memory - so you can install
|
||||
HIMEM.SYS - then you still can't use the UMBs because
|
||||
EMM386.EXE won't work on your machine... Now say you
|
||||
have no extended memory *at all* (which will always be
|
||||
the case on an XT), then you can't load himem in the
|
||||
first place! In both cases, USE!UMBS will be the right
|
||||
thing to use.
|
||||
|
||||
HMA - High Memory Area
|
||||
The HMA is the first block of 64K of extended memory (so
|
||||
with addresses 100000-10FFFF). Since Dos 5.0, it is
|
||||
possible to load the system files into this area. (System
|
||||
files are *not* the devices that you install: dos in-
|
||||
stalls them at boot-time!)
|
||||
In order to highload these systemfiles, you must have
|
||||
extended memory, and insert the lines DEVICE=HIMEM.SYS
|
||||
and DOS=HIGH at the front of your config.sys file. If you
|
||||
don't have an HMA, then you can not use dos=high. You can
|
||||
use dos=umb though.
|
||||
|
||||
Expanded Memory
|
||||
Expanded memory can't be defined in terms of 'adresses',
|
||||
since it is organized altogether differently. It resides
|
||||
on a separate 'card' that you plug into a free slot in
|
||||
your computer, and it cannot be accessed all at once but
|
||||
in 'pages'.
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 6
|
||||
==============================================================
|
||||
|
||||
What happens is that pages of say 16K are 'remapped' from the
|
||||
expanded memory board to addresses in Upper Memory. If the
|
||||
computers wants to find something in an area elsewhere on the
|
||||
card, an expanded memory manager must take care of storing the
|
||||
present page and making the new page active. As was the case
|
||||
with XMS, people have also devised a standard for access to
|
||||
expanded memory. This standard is the LIM/EMS specification
|
||||
(now at revision 4.0). Dos 5.0 provides a manager for it:
|
||||
EMM386.EXE. As said before, this manager will only work on a
|
||||
386, and since it takes care of the UMBs too, you are advised
|
||||
to rather use EMM386 when you have a 386 or higher. (USE!UMBS
|
||||
will, in fact, not install if it finds out that a UMB manager
|
||||
was installed already.)
|
||||
|
||||
==============================================================
|
||||
|
||||
2. Preparations
|
||||
|
||||
This program will install a UMB manager on any PC, XT, AT or
|
||||
higher, whether it has extended or expanded memory or not. In
|
||||
order to be able use it, it must have UMBs, i.e. holes in the
|
||||
memory-area between 640k and 1M that are filled with RAM.
|
||||
|
||||
How do you find out whether you have UMBs? Firstly, let me say
|
||||
that there are not many PC/XT/ATs that do have them (refer to
|
||||
section 1 if you want to find out why). One XT that I know of
|
||||
certainly has them, namely the Philips 31xx series XTs. I ori-
|
||||
ginally wrote the program for precisely that machine. Later on
|
||||
I found out it might be useful for other machines as well.
|
||||
|
||||
If you want to find out whether you have UMBs, run the program
|
||||
TEST!UMB.EXE. This program will run through the upper memory
|
||||
and try if it can write information there. (By the way: don't
|
||||
worry. It won't destroy anything while doing that!)
|
||||
|
||||
The locations where TEST!UMB can succesfully change values are
|
||||
RAM locations. It will display a table with its findings, sta-
|
||||
ting:
|
||||
"None at paragraphs xxxx until xxxx" or
|
||||
"Found RAM at paragraphs xxxx until xxxx"
|
||||
|
||||
Don't be too optimistic if it displays a range of adresses
|
||||
where it finds RAM: it will always find at least one such
|
||||
range! That range is occupied with Video-RAM, and you can't
|
||||
simply use all of that as a UMB (refer to section 1 for de-
|
||||
tails).
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 7
|
||||
==============================================================
|
||||
|
||||
So now comes the tricky bit: which ranges can you use?
|
||||
First of all, if TEST!UMB shows that there is RAM in the range
|
||||
D000 until EFFF, then you have "true" UMBs. And you can use my
|
||||
device driver rightaway. These two blocks (the D and the E
|
||||
block) provide you with 128K of Upper Memory - probably by far
|
||||
enough to store all of your device drivers and TSRs.
|
||||
So, if you are in that lucky situation and don't want to
|
||||
complicate matters, you can move on to section 5 (Installa-
|
||||
tion, page 12) rightway.
|
||||
|
||||
If you were less fortunate and TEST!UMB showed that there is
|
||||
no RAM in that range, or in only a part of that range, or if
|
||||
you don't want to use all of that range, or if you want to use
|
||||
more than one range, then you should read section 3 and/or
|
||||
section 4.
|
||||
|
||||
==============================================================
|
||||
|
||||
3. Using VideoRAM or other ranges as a UMB
|
||||
|
||||
If you don't have RAM in the D000-EFFF range, or if you want
|
||||
to use a different range of memory, then you must make a small
|
||||
modification to the driver: you must `patch in' the addresses
|
||||
that it should manage.
|
||||
This may sound difficult, and yes, it is not simple... The
|
||||
point is that I had wanted to use command line parameters to
|
||||
specify the range(s) the driver should manage... but I don't
|
||||
know how to program that option. [So, If YOU are a proficient
|
||||
Assembly programmer, please change the source code and include
|
||||
that option!]
|
||||
|
||||
Anyway, let's go for it:
|
||||
If TEST!UMB showed that you have RAM outside the D000-EFFF
|
||||
range, that RAM may be of three kinds:
|
||||
(1) Completely free RAM - not used by the videocard or by any
|
||||
other program. This is good news: you can use it as a UMB
|
||||
without any problems - you only have to patch the addres-
|
||||
ses into USE!UMBS.SYS.
|
||||
(2) Graphics VideoRAM - this is only used by the video system
|
||||
when you are working in graphics mode. If you don't use
|
||||
graphics, you may use this RAM as a UMB. Beware to boot
|
||||
your computer without USE!UMBS.SYS if you intend to use
|
||||
graphics programs! (It won't damage anything, though,
|
||||
your computer will simply hang once it switches to grap-
|
||||
hics mode.)
|
||||
(3) Text VideoRAM - sorry, but you really can't use this. If
|
||||
you would, then how could you get anything on the screen?
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 8
|
||||
==============================================================
|
||||
|
||||
Finding out to which of the three categories your RAM belongs
|
||||
is complicated: it depends on your videocard. I will try and
|
||||
describe as well as I can what ranges each videocard uses. As
|
||||
said above: you can use any range as long as it doesn't inclu-
|
||||
de the Text Range; and you may use the Graphics Range, but
|
||||
only if you don't switch to graphics mode. Read the Advice
|
||||
carefully - but note that this doesn't guarantee anything!
|
||||
(Thanks to Eef Hartman for the information about addresses.)
|
||||
|
||||
Monochrome Display Adapter (MDA)
|
||||
TEXT : B000-B0FF (4K)
|
||||
GRAPHICS : None (0K)
|
||||
ADVICE This is a very old-fashioned one. It was in the
|
||||
original IBMs. It can't do any graphics, only text.
|
||||
So if you appear to have *any* RAM outside the text
|
||||
range specified above: use it.
|
||||
|
||||
Color Graphics Adapter (CGA)
|
||||
TEXT : B800-B8FF (4K)
|
||||
GRAPHICS : B800-BBFF (16K)
|
||||
ADVICE If there is any RAM outside the graphics range
|
||||
(B800-BBFF) then that RAM is not used by the CGA
|
||||
adaptor, and you may problemlessly use it.
|
||||
If you want to use the graphics range, take care:
|
||||
this may give problems since the CGA adapter often
|
||||
uses it as 4 pages of text.
|
||||
|
||||
Hercules Adapter
|
||||
TEXT : B000-B0FF (4K)
|
||||
GRAPHICS : B000-BFFF (64K) full
|
||||
or : B000-B7FF (32K) half
|
||||
ADVICE If there is any RAM outside the graphics range
|
||||
(B000-BFFF) then that RAM is not used by the Hercu-
|
||||
les adaptor, and you may problemlessly use it.
|
||||
If you want to use the graphics range, take care:
|
||||
the hercules adapter may use the first half of its
|
||||
RAM (B000-B7FF) to store several text pages. So if
|
||||
you want to use the graphics range, use B800-BFFF.
|
||||
If you have a half (1 page) hercules, then you don't
|
||||
have that range.
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 9
|
||||
==============================================================
|
||||
|
||||
Enhanced Graphics Adapter (EGA)
|
||||
TEXT : B000-B0FF (4K) mono mode
|
||||
: B800-B8FF (4K) color mode
|
||||
GRAPHICS : A000-AFFF (64K)
|
||||
ADVICE As you see, you can use the A segment as a UMB if
|
||||
you don't use graphics applications.
|
||||
You may also use parts of the B segment, but notice
|
||||
that the EGA card will use one of the two text are-
|
||||
as: the lower one when it is in mode MONO, the upper
|
||||
one when it is in mode CO80.
|
||||
|
||||
V? Graphics Adapter (VGA)
|
||||
TEXT : same as EGA
|
||||
GRAPHICS : same as EGA, but sometimes also the range
|
||||
B000-BFFF (64K)
|
||||
ADVICE There is a large variety of VGA cards. I can't tell
|
||||
you precisely what ranges you may use. What is sure
|
||||
is that you can follow the advice of the EGA card:
|
||||
as long as you don't use graphics, the A000-AFFF
|
||||
range is at your disposal.
|
||||
|
||||
==============================================================
|
||||
|
||||
4. Patching in the addresses
|
||||
|
||||
This is the hardest bit. As I mentioned before, I wrote this
|
||||
driver for the Philips 35xx series, so it will by default only
|
||||
manage the block from D000 until EFFF. If you don't have that
|
||||
entire block at your disposal, you will have to change some
|
||||
code in the file. I will describe below how you can patch in
|
||||
the adresses using the DEBUG program, which you will have,
|
||||
since it came with the MS-DOS package.
|
||||
|
||||
First of all, you need to know the addresses of the block(s)
|
||||
you want to patch in. The maximum number of separate blocks
|
||||
you can patch in is three. I don't think you will need more
|
||||
than that; if you think you do, contact me, and I can fix it
|
||||
for you. (As long as the RAM is contiguous, you can specify it
|
||||
in one block, however long the contiguous block is.)
|
||||
|
||||
Once you know the starting and the ending address of a block,
|
||||
you should calculate its length (in paragraphs). How do you do
|
||||
that? You simply subtract the beginning address from the end
|
||||
adress, USING HEXADECIMAL CALCULATION. [Hex calculation goes
|
||||
just like decimal calculation, only that the numbers 10
|
||||
through 15 are changed to A through F]
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 10
|
||||
==============================================================
|
||||
|
||||
Some examples:
|
||||
|
||||
End address : AFFF BFFF BBFF E7FF EFFF EFFF
|
||||
Begin address : A000 B800 B0FF E000 D7FF D000
|
||||
------------- - ---- ---- ---- ---- ---- ----
|
||||
Length : 0FFF 07FF 0B00 07FF 1800 1FFF
|
||||
|
||||
So, what you do is (just as with decimal calculation): go from
|
||||
right to left and each time subtract two digits. If you have
|
||||
to `borrow' you can do so. Keep in mind that e.g. F-7=8 (bec-
|
||||
ause 15-7=8) and that 10-8=8, because 16-8=8.
|
||||
|
||||
Ok, now you must patch the starting address and the length of
|
||||
each block into USE!UMBS.SYS. Only ... there is a twist now:
|
||||
both values have to be reversed bytewise before being patched
|
||||
in. It's best to explain this using an example: suppose you
|
||||
have a block, which starts at B800 and has length 07FF, then
|
||||
you reverse the bytes as follows:
|
||||
|
||||
Address Length
|
||||
B8 00 07 FF
|
||||
\ / \ /
|
||||
/ \ / \
|
||||
00 B8 FF 07
|
||||
|
||||
So, the sequence B800 07FF becomes 00 B8 FF 07. And this is
|
||||
the sequence we will patch in. If you have more blocks, trans-
|
||||
pose them in the same way, and append them to this sequence.
|
||||
(But *never* more than three blocks in total!!!)
|
||||
|
||||
Then startup the debug program with the following command:
|
||||
|
||||
DEBUG USE!UMBS.SYS
|
||||
|
||||
and debug will report with its prompt:
|
||||
-
|
||||
(if this doesn't happen: make sure debug is in the search path
|
||||
and use!umbs.sys is in the current directory. You can type Q
|
||||
to exit from debug).
|
||||
|
||||
Now type:
|
||||
|
||||
-E153
|
||||
|
||||
(don't type the hyphen, and finish with carriage return)
|
||||
and debug will say this
|
||||
|
||||
xxxx:0153 00._
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 11
|
||||
==============================================================
|
||||
|
||||
Now, type the first byte of your sequence, and finish with a
|
||||
SPACE, NOT A CARRIAGE RETURN!!!. So, if your first byte was
|
||||
(for example) AB, you will now see something like this:
|
||||
|
||||
xxxx:0153 00.AB D0._
|
||||
|
||||
Now, type the next byte, AGAIN FOLLOWED BY A SPACE, NOT A
|
||||
CARRIAGE RETURN! And keep on doing this until you have entered
|
||||
the whole sequence (which amounts to 4 bytes for one block, 8
|
||||
bytes for two blocks, 12 for three blocks). After having
|
||||
completed this, STILL DON'T PRESS CARRIAGE RETURN, but enter
|
||||
another four bytes, all with value 00, every time using the
|
||||
spacebar to move to the next. (These 00-bytes signal the end
|
||||
of the list.)
|
||||
|
||||
If you have done that, you may now finally press RETURN to get
|
||||
back to the debug-prompt. If you made any mistakes, you can
|
||||
now press Q to quit without changes, but if everything went
|
||||
alright, press W to write away the changes. (And afterwards Q
|
||||
to exit the programme.)
|
||||
|
||||
Well, that was it... Now you can continue to the next section
|
||||
and finally install USE!UMBS.SYS.
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 12
|
||||
==============================================================
|
||||
|
||||
5. Installation
|
||||
|
||||
In order to install USE!UMBS.SYS, follow the following three
|
||||
steps carefully.
|
||||
|
||||
STEP I: Tell DOS to install the device driver.
|
||||
You do this by adding this line to your config.sys:
|
||||
DEVICE=USE!UMBS.SYS
|
||||
(Provided USE!UMBS.SYS is in the root directory.)
|
||||
The position at which this line is placed is important! If you
|
||||
have an extended or expanded memorymanager (like HIMEM.SYS),
|
||||
then the line DEVICE=USE!UMBS.SYS must come *after* the line
|
||||
specifying the other manager. On the other hand, it must come
|
||||
*before* any other line that starts with DEVICE=.
|
||||
On the whole: put it as much as possible toward the beginning
|
||||
of your config.sys, but never before the installation line of
|
||||
an XMS or EMS driver.
|
||||
|
||||
STEP II: Tell DOS to actually use the UMBs
|
||||
You do this as follows: If there is a line saying DOS=HIGH in
|
||||
your config.sys, then change it to DOS=HIGH,UMB. If there is
|
||||
no such line, then add the line DOS=UMB to the config.sys.
|
||||
Also here, position is important: make sure the line is on the
|
||||
*very first* line of your config.sys. (And therefore comes
|
||||
somewhere before DEVICE=USE!UMBS.SYS)
|
||||
|
||||
STEP III: Tell DOS which things to put in the UMBs
|
||||
There are two kinds of things that can be put in the UMBs:
|
||||
device drivers and TSRs. Device drivers are `highloaded' by
|
||||
changing their lines in the config.sys from DEVICE=... to
|
||||
DEVICEHIGH=.... The TSRs are highloaded by preceding their
|
||||
invocation line in the autoexec.bat with LOADHIGH (or LH). So:
|
||||
if there formerly was a line saying AUTOPARK in your auto-
|
||||
exec.bat, now it should become LH AUTOPARK.EXE or LOADHIGH
|
||||
AUTPARK.EXE.
|
||||
[NOTE: Some people load TSRs via the config.sys instead of the
|
||||
autoexec.bat by using the line INSTALL=.... If this is the
|
||||
case, you better remove them from the config.sys and LOADHIGH
|
||||
them via the autoexec.bat.]
|
||||
|
||||
Well, that's all there is to it.
|
||||
Once you have made all the changes, try MEM to see how much
|
||||
memory you have left. Then reboot (and see USE!UMBS sign on),
|
||||
wait for the DOS-prompt and then run MEM again. Calculate the
|
||||
difference USE!UMBS makes. Now divide this difference by 2000.
|
||||
The result is - in my humble opinion - a reasonable donation
|
||||
for the author. (But, of course, it's up to you...)
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 13
|
||||
==============================================================
|
||||
|
||||
Appendix 1. Functional description of the driver
|
||||
(for the freaks).
|
||||
|
||||
This program is a device driver that will install a routine
|
||||
that handles requests for UMBs. These requests are made by
|
||||
MS-Dos if it has read the statement DOS=[high,]UMB in the
|
||||
config.sys file and encounters a DEVICEHIGH or a LOADHIGH
|
||||
statement. (For more information about devicehigh and loadhigh
|
||||
see the MS-Dos 5.0 manual.)
|
||||
|
||||
The UMB-requests are normally sent to the extended memory
|
||||
manager, which, in the case of Dos 5.0, is HIMEM.SYS. There
|
||||
are two problems here. Firstly, if you don't have extended
|
||||
memory, you cannot have Himem.sys installed. And since PCs and
|
||||
XTs can't even have extended memory, they can never install
|
||||
himem.sys. Secondly, even if you DO have extended memory AND
|
||||
install Himem.sys, you still have no access to the UMBs becau-
|
||||
se Himem doesn't implement a UMB manager, only an XMS handler.
|
||||
The UMB-handler is provided by a separate device driver,
|
||||
namely EMM386.SYS. And yes, as the name suggests, you can't
|
||||
install this on an AT (286).
|
||||
|
||||
So, what this USE!UMBS does is the following: it will install
|
||||
a routine that will intercept any requests to the extended
|
||||
memory manager. It then checks this request in order to see if
|
||||
it is a request for UMBs. If it is, then it will handle the
|
||||
request, otherwise it will pass them on to the XMS handler. If
|
||||
you don't have an XMS driver installed (which is quite fair if
|
||||
you don't have eXtended memory), USE!UMBS will not forward the
|
||||
request but answer it with a polite "no", so that nothing will
|
||||
hang or mess up. (So, in a way, USE!UMBS will install a HIMEM
|
||||
manager too - but since there is no high memory to manage, it
|
||||
won't have much to do anyway.)
|
||||
|
||||
==============================================================
|
||||
|
||||
|
||||
USE!UMBS Documentation Page 14
|
||||
==============================================================
|
||||
|
||||
Appendix 2. Technical description of the driver
|
||||
(details for the real freaks)
|
||||
|
||||
A request to the XMS manager goes in two steps. First, the
|
||||
caller will want to find out whether there is a manager and,
|
||||
if so, where it is. Second, it will call the manager with a
|
||||
specification of what it should do.
|
||||
|
||||
The first step is done via interrupt 2Fh (the multiplexer).
|
||||
This interrupt handles a lot of very different requests, which
|
||||
it classifies by looking in the AH register. If this contains
|
||||
43h, the request is for the XMS manager. So what we do is
|
||||
chain a little bit of code to the front of the interrupt 2Fh
|
||||
handler - this added code will determine if AH=43h. If it is
|
||||
not, it gives control back to the old INT 2F handler, if it
|
||||
is, it will take over.
|
||||
|
||||
Once it has taken over, it will check the AL register. This
|
||||
register specifies the precise nature of the question. It can
|
||||
contain only two possible values: 00h and 10h. If it contains
|
||||
00h, this means that the question is "Hullo! Is there any
|
||||
XMS-manager installed?", and our response should be "Yo!"
|
||||
(because that's exactly what we are installing). We signal a
|
||||
yes by returning 80h in the AL register. If AL contains 10h
|
||||
upon entry, then the question is "Well then, where can I find
|
||||
that XMS manager?". So in this case we return its address in
|
||||
the registers ES:BX. The address we pass is, yes, the address
|
||||
of the XMS manager that we are installing.
|
||||
|
||||
The second step. After the caller has used the interrupt
|
||||
described above to find out about the existence (4300) and the
|
||||
whereabouts (4310) of the XMS manager, it will at some point
|
||||
call it. It calls it by simply making a FAR JMP to the address
|
||||
that was previously specified in ES:BX.
|
||||
|
||||
Upon entering the XMS manager, we first have to check its AH
|
||||
register in order to find out whether the request is for UMBs
|
||||
or for extended memory. If it is anything else than 10h (= "I
|
||||
want a UMB"), our UMB-manager will do the following: (a) IF
|
||||
another XMS-manager (like MS-Dos's HIMEM.SYS) was loaded
|
||||
before, it will pass the request on to that manager, (b) IF
|
||||
NOT, it will return an errorcode saying that there is no XMS
|
||||
memory. If the request actually is for UMBs (AH=10h), then it
|
||||
will provide them as long as there are any.
|
||||
|
||||
[END OF DOCS]
|
||||
==============================================================
|
||||
1
XTMax/Drivers/USEUMB/build.cmd
Normal file
1
XTMax/Drivers/USEUMB/build.cmd
Normal file
@ -0,0 +1 @@
|
||||
..\Driver_Build_Tools\NASM\nasm.exe -f bin -o XTUMBS.SYS USE!UMBS.ASM
|
||||
Binary file not shown.
BIN
XTMax/Drivers/XTUMBS.SYS
Normal file
BIN
XTMax/Drivers/XTUMBS.SYS
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user