1
0
mirror of synced 2026-01-12 00:02:46 +00:00

Many fixes and improvements to the BIOS Extension ROM. (#33)

* Revert "Uploaded_2_9_2025"

This reverts commit ec79bbdbc9052617461a3c1b4952290a05a51adb.

* Fixing DEBUG_IO builds.

* Make the IO port base a define.

* Fix CPU test to properly handle 808x vs V20.

* Improve timeout management logic.

* Improve SD Card initialization logic.

* Implement INT18h bootstrapping.

* Implementing a different test for processor type.

* Allow use with another fixed drive (eg: ESDI drive).

* Allow swapping driver ID between the BIOS disk and XTMax.

* Fix address of the ROM segment.

* Fixing missing STI at the top of the handler.

* Major rework of IO to use MOVSW.

* More code reorg and auto-detecting second drive.

* Update XTSD to use MOVSW.

* Add diagnostics program.

* Workaround for MS-DOS strange handling of interrupts.

* Use a lookup table for the memory map.

* Make the BootROM relocatable.

* Some more refactor of the Teensy code.
This commit is contained in:
Matthieu Bucchianeri 2025-02-17 15:11:37 -08:00 committed by GitHub
parent ec79bbdbc9
commit fe8385da08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 1199 additions and 456 deletions

View File

@ -37,11 +37,18 @@
//
// Revision 7 01/12/2025
// - Refactor SD card I/O
// - Add support for 16-bit EMS page offsets.
// - Add support for 16-bit EMS page offsets
//
// Revision 8 01/20/2025
// - Added chip select for a second PSRAM to allow access to 16 MB of Expanded RAM
//
// Revision 9 01/26/2025
// - Add support for BIOS ROM extension (Boot ROM)
// - Add scrach registers for Boot ROM hooking
//
// Revision 10 02/17/2025
// - Use a lookup table for the memory map
//
//------------------------------------------------------------------------
//
// Copyright (c) 2024 Ted Fried
@ -71,6 +78,8 @@
#include <stdint.h>
#include <stdio.h>
#include "bootrom.h"
// Teensy 4.1 pin assignments
//
@ -166,7 +175,8 @@
#define EMS_TOTAL_SIZE (16*1024*1024)
#define SD_BASE 0x280 // Must be a multiple of 2.
#define SD_BASE 0x280 // Must be a multiple of 8.
#define SD_CONFIG_BYTE 0
// --------------------------------------------------------------------------------------------------
@ -191,6 +201,9 @@ uint8_t spi_shift_out =0;
uint8_t sd_spi_datain =0;
uint32_t sd_spi_cs_n = 0x0;
uint32_t sd_spi_dataout =0;
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];
@ -199,6 +212,16 @@ DMAMEM uint8_t internal_RAM1[0x60000];
uint8_t psram_cs =0;
enum Region {
Unused,
Ram,
EmsWindow,
BootRom,
SdCard
};
Region memmap[512];
// --------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------
@ -282,6 +305,34 @@ void setup() {
//Serial.begin(9600);
// Populate 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);
i < ((BOOTROM_ADDR+sizeof(BOOTROM)) >> 11);
i++) {
memmap[i] = BootRom;
}
memmap[(BOOTROM_ADDR+sizeof(BOOTROM)) >> 11] = SdCard;
}
@ -507,239 +558,299 @@ inline void Internal_RAM_Write() {
// --------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------
inline void Mem_Read_Cycle() {
isa_address = ADDRESS_DATA_GPIO6_UNSCRAMBLE;
if ( (isa_address>=EMS_BASE_MEM) && (isa_address<EMS_BASE_MEM+0x10000) ) { // Expanded RAM page frame
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); }
__attribute__((always_inline))
inline void Mem_Read_Cycle()
{
isa_address = ADDRESS_DATA_GPIO6_UNSCRAMBLE;
Region region = memmap[isa_address >> 11];
switch (region) {
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); }
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
isa_data_out = PSRAM_Read(psram_address);
isa_data_out = PSRAM_Read(psram_address);
GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out; // Output data
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_LOW; // De-assert CHRDY
while ( (gpio9_int&0xF0) != 0xF0 ) { gpio9_int = GPIO9_DR; } // Wait here until cycle is complete
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH;
}
break;
/*
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
*/
else if (isa_address<0xA0000) { // "Conventional" RAM
case Ram:
isa_data_out = Internal_RAM_Read();
GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out;
// 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
// 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_MEM_Response_Array[(isa_address>>16)] == 2) {
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) {
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
// 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) {
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) {
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
gpio6_int = GPIO6_DR; // Read the data bus value currently on the ISA bus
data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
if (data_in == isa_data_out) {
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
}
else {
}
else {
XTMax_MEM_Response_Array[(isa_address>>16)] = 2;
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
}
}
while ( (gpio9_int&0xF0) != 0xF0 ) { gpio9_int = GPIO9_DR; } // Wait here until cycle is complete
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH;
}
return;
break;
case BootRom:
isa_data_out = BOOTROM[isa_address-BOOTROM_ADDR];
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_LOW;
while ( (gpio9_int&0xF0) != 0xF0 ) { gpio9_int = GPIO9_DR; } // Wait here until cycle is complete
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH;
break;
case SdCard:
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
// Receive a byte to the SD Card
sd_spi_dataout = 0xff; SD_SPI_Cycle(); isa_data_out = sd_spi_datain;
GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_LOW + CHRDY_OUT_LOW + trigger_out; // Output data
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_LOW; // De-assert CHRDY
while ( (gpio9_int&0xF0) != 0xF0 ) { gpio9_int = GPIO9_DR; } // Wait here until cycle is complete
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH;
break;
default:
break;
}
}
// --------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------
inline void Mem_Write_Cycle() {
isa_address = ADDRESS_DATA_GPIO6_UNSCRAMBLE;
if ( (isa_address>=EMS_BASE_MEM) && (isa_address<EMS_BASE_MEM+0x10000) ) { // Expanded RAM page frame
page_base_address = (isa_address & 0xFC000);
__attribute__((always_inline))
inline void Mem_Write_Cycle()
{
isa_address = ADDRESS_DATA_GPIO6_UNSCRAMBLE;
Region region = memmap[isa_address >> 11];
switch (region) {
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_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); }
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
delayNanoseconds(10); // Wait some time for buffers to switch from address to data
gpio6_int = GPIO6_DR;
data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
PSRAM_Write(psram_address , data_in);
PSRAM_Write(psram_address , data_in);
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_LOW + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH; // De-assert CHRDY
while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete
gpio6_int = GPIO6_DR;
gpio9_int = GPIO9_DR;
}
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;
break;
case Ram:
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;
while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete
gpio6_int = GPIO6_DR;
gpio9_int = GPIO9_DR;
}
Internal_RAM_Write();
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;
break;
case SdCard:
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
delayNanoseconds(10); // Wait some time for buffers to switch from address to data
gpio6_int = GPIO6_DR;
data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
// Send a byte to the SD Card
sd_spi_dataout = data_in; SD_SPI_Cycle();
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_LOW + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH; // De-assert CHRDY
while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete
gpio6_int = GPIO6_DR;
gpio6_int = GPIO6_DR;
gpio9_int = GPIO9_DR;
}
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;
}
else if (isa_address<0xA0000) { // XTMax stores the full 640 KB conventional memory
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;
while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete
gpio6_int = GPIO6_DR;
gpio9_int = GPIO9_DR;
}
Internal_RAM_Write();
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;
}
return;
}
// --------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------
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
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;
}
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;
break;
default:
break;
}
}
// --------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------
__attribute__((always_inline))
inline void IO_Read_Cycle()
{
isa_address = 0xFFFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
uint16_t base_address = isa_address&0x0FF8;
switch (base_address) {
case EMS_BASE_IO:
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;
}
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_LOW;
while ( (gpio9_int&0xF0) != 0xF0 ) { gpio9_int = GPIO9_DR; } // Wait here until cycle is complete
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH;
}
else if ((isa_address&0x0FFE)==SD_BASE ) { // Location of SD Card registers
// Both registers serve the same function (to allow use of Word I/O)
sd_spi_dataout = 0xff;
SD_SPI_Cycle();
isa_data_out = sd_spi_datain;
break;
case SD_BASE:
switch (isa_address) {
case SD_BASE+0: sd_spi_dataout = 0xff; SD_SPI_Cycle(); isa_data_out = sd_spi_datain; break;
case SD_BASE+1: isa_data_out = SD_CONFIG_BYTE; break;
case SD_BASE+2: isa_data_out = sd_scratch_register[0]; break;
case SD_BASE+3: isa_data_out = sd_scratch_register[1]; break;
case SD_BASE+4: isa_data_out = sd_scratch_register[2]; break;
case SD_BASE+5: isa_data_out = sd_scratch_register[3]; break;
case SD_BASE+6: isa_data_out = sd_scratch_register[4]; break;
case SD_BASE+7: isa_data_out = sd_timeout >= sd_requested_timeout; break;
default: isa_data_out = 0xff; 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_LOW;
while ( (gpio9_int&0xF0) != 0xF0 ) { gpio9_int = GPIO9_DR; } // Wait here until cycle is complete
GPIO8_DR = sd_pin_outputs + MUX_DATA_n_HIGH + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH;
}
return;
break;
}
}
// --------------------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------
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
__attribute__((always_inline))
inline void IO_Write_Cycle()
{
isa_address = 0xFFFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE;
uint16_t base_address = isa_address&0x0FF8;
switch (base_address) {
case EMS_BASE_IO:
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;
while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete
gpio6_int = GPIO6_DR;
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;
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;
}
else if ((isa_address&0x0FFC)==SD_BASE ) { // Location of SD Card registers
break;
case SD_BASE:
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 SD_BASE: // First two registers serve the same function (to allow use of Word I/O)
case SD_BASE+1: sd_spi_dataout = data_in; SD_SPI_Cycle(); break;
case SD_BASE+2: sd_spi_cs_n = data_in&0x1; break;
case SD_BASE+0: sd_spi_dataout = data_in; SD_SPI_Cycle(); break;
case SD_BASE+1: sd_spi_cs_n = data_in&0x1; break;
case SD_BASE+2: sd_scratch_register[0] = data_in; break;
case SD_BASE+3: sd_scratch_register[1] = data_in; break;
case SD_BASE+4: sd_scratch_register[2] = data_in; break;
case SD_BASE+5: sd_scratch_register[3] = data_in; break;
case SD_BASE+6: sd_scratch_register[4] = data_in; break;
case SD_BASE+7: sd_timeout = 0; sd_requested_timeout = data_in * 10; break;
}
//gpio9_int = GPIO9_DR;
while ( (gpio9_int&0xF0) != 0xF0 ) { // Wait here until cycle is complete
gpio6_int = GPIO6_DR;
gpio6_int = GPIO6_DR;
gpio9_int = GPIO9_DR;
}
}
sd_pin_outputs = (sd_spi_cs_n<<17); // SD_CS_n - SD_CLK - SD_MOSI
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;
}
return;
break;
}
}
@ -749,23 +860,22 @@ inline void IO_Write_Cycle() {
// Main loop
//
// -------------------------------------------------
void loop() {
// Give Teensy 4.1 a moment
//
//delay (1000);
void loop()
{
PSRAM_Configure();
while (1) {
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();
gpio6_int = GPIO6_DR;
gpio9_int = GPIO9_DR;
switch (gpio9_int&0x800000F0) {
case 0x000000E0: IO_Read_Cycle(); break; // ~AEN + ~IORD
case 0x000000D0: IO_Write_Cycle(); break; // ~AEN + ~IOWR
case 0x000000B0:
case 0x800000B0: Mem_Read_Cycle(); break; // ~MEMRD
case 0x00000070:
case 0x80000070: Mem_Write_Cycle(); break; // ~MEMWR
}
}
}
}

130
XTMax/Code/XTMax/bootrom.h Normal file
View File

@ -0,0 +1,130 @@
#define BOOTROM_ADDR 0xce000
unsigned char BOOTROM[] = {
85, 170, 4, 6, 80, 81, 82, 250, 184, 152, 5, 232, 0, 5, 184, 218,
5, 232, 250, 4, 140, 200, 232, 18, 5, 184, 145, 5, 232, 239, 4, 184,
0, 0, 232, 6, 5, 184, 149, 5, 232, 227, 4, 232, 228, 3, 115, 3,
233, 140, 0, 49, 192, 142, 192, 38, 161, 78, 0, 186, 131, 2, 239, 38,
161, 76, 0, 186, 133, 2, 239, 140, 200, 38, 163, 78, 0, 184, 197, 0,
38, 163, 76, 0, 184, 55, 6, 232, 180, 4, 184, 64, 0, 142, 192, 38,
160, 117, 0, 4, 128, 186, 130, 2, 238, 80, 232, 190, 4, 184, 149, 5,
232, 155, 4, 184, 82, 6, 232, 149, 4, 38, 254, 6, 117, 0, 38, 160,
117, 0, 48, 228, 232, 164, 4, 184, 149, 5, 232, 129, 4, 88, 49, 201,
142, 193, 60, 128, 117, 15, 140, 200, 38, 163, 6, 1, 184, 170, 1, 38,
163, 4, 1, 235, 13, 140, 200, 38, 163, 26, 1, 184, 170, 1, 38, 163,
24, 1, 140, 200, 38, 163, 98, 0, 184, 127, 3, 38, 163, 96, 0, 251,
90, 89, 88, 7, 203, 251, 85, 86, 80, 82, 186, 130, 2, 236, 90, 56,
194, 88, 116, 58, 137, 197, 137, 214, 156, 14, 184, 238, 0, 80, 186, 131,
2, 237, 80, 186, 133, 2, 237, 80, 137, 232, 137, 242, 250, 203, 251, 156,
80, 137, 240, 60, 128, 114, 19, 137, 232, 128, 252, 8, 117, 12, 6, 184,
64, 0, 142, 192, 38, 138, 22, 117, 0, 7, 88, 157, 235, 58, 128, 252,
25, 126, 5, 232, 122, 0, 235, 34, 128, 252, 1, 116, 10, 128, 252, 21,
116, 5, 190, 58, 1, 235, 3, 190, 72, 1, 86, 137, 222, 136, 227, 48,
255, 208, 227, 135, 222, 46, 255, 164, 92, 1, 140, 197, 190, 64, 0, 142,
198, 38, 136, 38, 116, 0, 142, 197, 137, 229, 139, 118, 8, 86, 115, 4,
157, 249, 235, 2, 157, 248, 94, 93, 251, 202, 2, 0, 100, 3, 186, 1,
206, 1, 97, 2, 37, 3, 144, 1, 144, 1, 144, 1, 64, 3, 100, 3,
144, 1, 144, 1, 86, 3, 100, 3, 144, 1, 144, 1, 100, 3, 100, 3,
144, 1, 144, 1, 100, 3, 102, 3, 144, 1, 144, 1, 144, 1, 100, 3,
80, 184, 109, 6, 232, 119, 3, 88, 80, 136, 224, 48, 228, 232, 139, 3,
184, 149, 5, 232, 104, 3, 88, 233, 201, 1, 0, 4, 255, 0, 0, 255,
255, 0, 200, 0, 0, 0, 0, 0, 63, 0, 6, 189, 64, 0, 142, 197,
48, 228, 38, 134, 38, 116, 0, 132, 228, 116, 1, 249, 7, 195, 132, 192,
117, 3, 233, 158, 1, 80, 48, 228, 137, 198, 83, 232, 227, 1, 137, 197,
1, 240, 137, 222, 131, 211, 0, 232, 10, 2, 91, 88, 115, 3, 233, 134,
1, 30, 83, 81, 82, 87, 80, 137, 193, 48, 237, 140, 200, 142, 216, 137,
223, 186, 129, 2, 176, 0, 238, 81, 137, 232, 137, 243, 177, 81, 232, 213,
2, 114, 60, 186, 135, 2, 176, 10, 238, 186, 128, 2, 236, 60, 254, 116,
10, 186, 135, 2, 236, 132, 192, 117, 38, 235, 238, 185, 0, 1, 86, 190,
0, 8, 252, 243, 165, 173, 94, 131, 197, 1, 131, 214, 0, 89, 226, 199,
186, 129, 2, 176, 1, 238, 88, 95, 90, 89, 91, 31, 233, 44, 1, 186,
129, 2, 176, 1, 238, 89, 88, 40, 200, 95, 90, 89, 91, 31, 233, 14,
1, 132, 192, 117, 3, 233, 11, 1, 80, 48, 228, 137, 198, 83, 232, 80,
1, 137, 197, 1, 240, 137, 222, 131, 211, 0, 232, 119, 1, 91, 88, 115,
3, 233, 243, 0, 30, 83, 81, 82, 87, 80, 137, 193, 48, 237, 137, 223,
140, 192, 142, 216, 140, 200, 142, 192, 186, 129, 2, 176, 0, 238, 81, 137,
232, 137, 243, 177, 88, 232, 62, 2, 114, 102, 186, 128, 2, 176, 254, 238,
185, 0, 1, 86, 137, 254, 191, 0, 8, 252, 243, 165, 137, 247, 94, 186,
135, 2, 176, 25, 238, 186, 128, 2, 236, 60, 255, 117, 10, 186, 135, 2,
236, 132, 192, 117, 59, 235, 238, 36, 31, 60, 5, 117, 51, 186, 135, 2,
176, 25, 238, 186, 128, 2, 236, 132, 192, 117, 10, 186, 135, 2, 236, 132,
192, 117, 29, 235, 238, 131, 197, 1, 131, 214, 0, 89, 226, 160, 186, 129,
2, 176, 1, 238, 140, 216, 142, 192, 88, 95, 90, 89, 91, 31, 235, 107,
186, 129, 2, 176, 1, 238, 89, 140, 216, 142, 192, 88, 40, 200, 95, 90,
89, 91, 31, 235, 74, 132, 192, 116, 74, 80, 48, 228, 137, 197, 83, 232,
143, 0, 1, 232, 131, 211, 0, 232, 186, 0, 91, 88, 114, 57, 235, 59,
182, 254, 6, 184, 64, 0, 142, 192, 38, 138, 22, 117, 0, 7, 181, 254,
177, 255, 49, 192, 248, 195, 80, 83, 232, 102, 0, 232, 150, 0, 91, 88,
114, 21, 235, 23, 235, 21, 180, 3, 232, 160, 0, 135, 209, 248, 195, 180,
170, 249, 195, 180, 1, 249, 195, 180, 4, 249, 195, 48, 228, 248, 195, 49,
192, 142, 216, 142, 192, 185, 0, 1, 191, 0, 124, 243, 171, 186, 130, 2,
236, 136, 194, 48, 246, 184, 1, 2, 185, 1, 0, 187, 0, 124, 205, 19,
129, 62, 254, 125, 85, 170, 117, 15, 184, 138, 6, 232, 96, 1, 49, 192,
142, 192, 234, 0, 124, 0, 0, 184, 164, 6, 232, 81, 1, 251, 244, 235,
253, 49, 192, 49, 219, 82, 81, 82, 136, 200, 36, 192, 209, 224, 209, 224,
136, 232, 185, 255, 0, 247, 225, 90, 136, 241, 48, 237, 1, 200, 177, 63,
247, 225, 89, 81, 48, 237, 128, 225, 63, 73, 1, 200, 131, 210, 0, 137,
211, 89, 90, 195, 81, 82, 232, 18, 0, 57, 211, 114, 10, 119, 4, 57,
200, 114, 4, 249, 90, 89, 195, 248, 90, 89, 195, 186, 250, 0, 185, 63,
197, 195, 80, 30, 83, 81, 82, 86, 140, 200, 142, 216, 186, 129, 2, 176,
1, 238, 185, 1, 0, 186, 160, 134, 180, 134, 205, 21, 186, 128, 2, 176,
255, 185, 10, 0, 238, 226, 253, 186, 129, 2, 176, 0, 238, 187, 10, 0,
190, 206, 4, 185, 1, 0, 180, 1, 232, 92, 0, 115, 15, 49, 201, 186,
32, 78, 180, 134, 205, 21, 75, 117, 231, 249, 235, 52, 190, 212, 4, 185,
5, 0, 180, 1, 232, 64, 0, 114, 39, 186, 135, 2, 176, 250, 238, 190,
218, 4, 185, 1, 0, 180, 1, 232, 45, 0, 190, 224, 4, 185, 1, 0,
180, 0, 232, 34, 0, 115, 9, 186, 135, 2, 236, 132, 192, 116, 224, 249,
94, 90, 89, 91, 31, 114, 8, 184, 245, 5, 232, 113, 0, 88, 195, 184,
24, 6, 232, 105, 0, 88, 195, 186, 128, 2, 176, 255, 238, 81, 185, 6,
0, 252, 172, 238, 226, 252, 185, 8, 0, 236, 60, 255, 225, 251, 89, 56,
224, 118, 3, 249, 235, 4, 248, 236, 226, 253, 176, 255, 238, 195, 64, 0,
0, 0, 0, 149, 72, 0, 0, 1, 170, 135, 119, 0, 0, 0, 0, 1,
105, 64, 0, 0, 0, 1, 186, 128, 2, 80, 176, 255, 238, 136, 200, 238,
136, 248, 238, 136, 216, 238, 88, 134, 224, 238, 134, 224, 238, 176, 1, 238,
185, 8, 0, 236, 60, 255, 225, 251, 132, 192, 116, 1, 249, 195, 156, 30,
83, 86, 137, 198, 140, 200, 142, 216, 180, 14, 49, 219, 252, 172, 8, 192,
116, 4, 205, 16, 235, 247, 94, 91, 31, 157, 195, 156, 30, 83, 81, 82,
86, 137, 194, 140, 200, 142, 216, 49, 219, 252, 137, 214, 177, 12, 211, 238,
131, 230, 15, 138, 132, 129, 5, 180, 14, 205, 16, 137, 214, 177, 8, 211,
238, 131, 230, 15, 138, 132, 129, 5, 180, 14, 205, 16, 137, 214, 177, 4,
211, 238, 131, 230, 15, 138, 132, 129, 5, 180, 14, 205, 16, 137, 214, 131,
230, 15, 138, 132, 129, 5, 180, 14, 205, 16, 94, 90, 89, 91, 31, 157,
195, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69,
70, 58, 0, 32, 0, 13, 10, 0, 66, 111, 111, 116, 82, 79, 77, 32,
102, 111, 114, 32, 88, 84, 77, 97, 120, 32, 118, 49, 46, 48, 13, 10,
67, 111, 112, 121, 114, 105, 103, 104, 116, 32, 40, 99, 41, 32, 50, 48,
50, 53, 32, 77, 97, 116, 116, 104, 105, 101, 117, 32, 66, 117, 99, 99,
104, 105, 97, 110, 101, 114, 105, 13, 10, 0, 82, 79, 77, 32, 66, 97,
115, 101, 32, 65, 100, 100, 114, 101, 115, 115, 32, 32, 32, 32, 32, 32,
32, 32, 61, 32, 0, 83, 68, 32, 67, 97, 114, 100, 32, 105, 110, 105,
116, 105, 97, 108, 105, 122, 101, 100, 32, 115, 117, 99, 99, 101, 115, 115,
102, 117, 108, 108, 121, 13, 10, 0, 83, 68, 32, 67, 97, 114, 100, 32,
102, 97, 105, 108, 101, 100, 32, 116, 111, 32, 105, 110, 105, 116, 105, 97,
108, 105, 122, 101, 13, 10, 0, 70, 105, 120, 101, 100, 32, 68, 105, 115,
107, 32, 73, 68, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 61,
32, 0, 84, 111, 116, 97, 108, 32, 70, 105, 120, 101, 100, 32, 68, 105,
115, 107, 32, 68, 114, 105, 118, 101, 115, 32, 61, 32, 0, 85, 110, 115,
117, 112, 112, 111, 114, 116, 101, 100, 32, 73, 78, 84, 49, 51, 104, 32,
70, 117, 110, 99, 116, 105, 111, 110, 32, 0, 66, 111, 111, 116, 105, 110,
103, 32, 102, 114, 111, 109, 32, 83, 68, 32, 67, 97, 114, 100, 46, 46,
46, 13, 10, 0, 78, 111, 116, 32, 98, 111, 111, 116, 97, 98, 108, 101,
13, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 189};

View File

@ -11,14 +11,31 @@ cpu 8086 ; ensure we remain compatible with 8086
;%define DEBUG_IO
;%define EXTRA_DEBUG
%define FIXED_DISK_0 (0)
%define FIXED_DISK_1 (1)
;
; The base I/O port for the XTMAX SD Card.
;
%define XTMAX_IO_BASE (0x280)
%define REG_DATA (XTMAX_IO_BASE+0)
%define REG_CS (XTMAX_IO_BASE+1) ; write-only
%define REG_CONFIG (XTMAX_IO_BASE+1) ; read-only
%define REG_SCRATCH_0 (XTMAX_IO_BASE+2) ; fixed disk id
%define REG_SCRATCH_1 (XTMAX_IO_BASE+3) ; BIOS INT13h segment
%define REG_SCRATCH_2 (XTMAX_IO_BASE+4) ; BIOS INT13h segment
%define REG_SCRATCH_3 (XTMAX_IO_BASE+5) ; BIOS INT13h offset
%define REG_SCRATCH_4 (XTMAX_IO_BASE+6) ; BIOS INT13h offset
%define REG_TIMEOUT (XTMAX_IO_BASE+7)
;
; Whether we will emulate the 1st or 2nd disk.
; Whether we will try/force using our own bootstrap code instead of falling back to BASIC.
;
%define DISK_NUMBER FIXED_DISK_0
%define USE_BOOTSTRAP
;%define FORCE_OWN_BOOTSTRAP
;
; Whether we are going to rename the BIOS's 1st disk to be the second disk.
; This is useful to allow booting from the second disk.
;
;%define TAKE_OVER_FIXED_DISK_0
;
; The properties of our emulated disk.
@ -30,22 +47,26 @@ cpu 8086 ; ensure we remain compatible with 8086
%define NUM_SECTORS (NUM_HEADS * (NUM_CYLINDERS - 1) * SECTORS_PER_TRACK)
%if NUM_HEADS > 255
%error NUM_HEADS is too large
%error NUM_HEADS_ is too large
%endif
%if NUM_HEADS > 16
%warning NUM_HEADS_ above 16 can cause compatibility issues
%endif
%if SECTORS_PER_TRACK > 63
%error SECTORS_PER_TRACK is too large
%error SECTORS_PER_TRACK_ is too large
%endif
%if NUM_CYLINDERS > 1024
%error NUM_CYLINDERS is too large
%error NUM_CYLINDERS_ is too large
%endif
beginning_of_rom:
%ifndef AS_COM_PROGRAM
;
; BIOS will look for the AA55 signature between C8000-DFFFF in 2KB increments.
; We choose an address in that range.
;
%define ROM_SEGMENT (0xc000)
org (ROM_SEGMENT << 4 | 0xe000)
%define ROM_SEGMENT (0xce00)
org 0
dw 0AA55h ; signature
db 4 ; size in blocks of 512 bytes
@ -61,6 +82,7 @@ entry:
%ifndef AS_COM_PROGRAM
push es
push ax
push cx
push dx
cli
%endif
@ -68,6 +90,17 @@ entry:
mov ax, welcome_msg
call print_string
mov ax, rom_base_msg
call print_string
mov ax, cs
call print_hex
mov ax, colon
call print_string
mov ax, beginning_of_rom
call print_hex
mov ax, newline
call print_string
;
; Initialize the SD Card.
;
@ -76,76 +109,66 @@ entry:
jc .skip
%endif
;
; Detecting 80186-compatible so we can use REP INSW/OUTSW.
; Based on https://www.rcollins.org/ftp/source/cpuid/cpuid.asm
;
.cpuid:
push sp
pop ax
cmp ax, sp ; if below 80286, these values will differ
jz .support_string_io ; nope, 80286 or higher
mov ax, ds:[0xffff] ; get original data
mov word ds:[0xffff], 0xaaaa ; write signature at test location
cmp byte ds:[0], 0xaa ; 8086 will write the 2nd byte at offset 0
mov ds:[0xffff], ax
je .test_v20
jmp .support_string_io ; we have an 80186/80188
.test_v20:
push ax ; save results
xor al, al ; force ZF
mov al, 0x40 ; multiplicand
mul al ; V20 doesn't affect ZF
pop ax ; restore results
jz .support_string_io ; we have an V20
xor dl, dl
jmp .store_string_io
.support_string_io:
mov dl, 1
mov ax, string_io_msg
call print_string
.store_string_io:
mov ax, 0x283 ; scratch register 0
xchg ax, dx
out dx, al ; save capability
%ifndef AS_COM_PROGRAM
;
; Install our BIOS INT13h hook into the interrupt vector table.
;
.install_13h_vector:
mov ax, old_13h_msg
call print_string
xor ax, ax ; INT vector segment
mov es, ax
mov ax, es:[0x13*4+2]
mov dx, 0x284 ; scratch register 1-2
mov dx, REG_SCRATCH_1
out dx, ax ; save segment
call print_hex
mov ax, colon
call print_string
mov ax, es:[0x13*4]
mov dx, 0x286 ; scratch register 3-4
mov dx, REG_SCRATCH_3
out dx, ax ; save offset
call print_hex
mov ax, newline
call print_string
mov ax, new_13h_msg
call print_string
mov ax, ROM_SEGMENT
mov ax, cs
mov es:[0x13*4+2], ax ; store segment
call print_hex
mov ax, colon
call print_string
mov ax, int13h_entry
mov es:[0x13*4], ax ; store offset
;
; Move fixed disk 0 to fixed disk 1.
;
%ifdef TAKE_OVER_FIXED_DISK_0
call swap_fixed_disk_parameters_tables
%endif
;
; Determine our fixed disk ID.
;
.identify_fixed_disk:
mov ax, disk_id_msg
call print_string
mov ax, 0x40 ; BIOS data area
mov es, ax
%ifndef TAKE_OVER_FIXED_DISK_0
mov al, es:[0x75] ; HDNUM
add al, 0x80
%else
mov al, 0x80
%endif
mov dx, REG_SCRATCH_0 ; save fixed disk id
out dx, al
push ax
call print_hex
mov ax, newline
call print_string
%if !(%isdef(USE_BOOTSTRAP) && %isdef(FORCE_OWN_BOOTSTRAP))
.update_bda:
;
; Increment the number of fixed disks in the BIOS Data Area.
;
mov ax, num_drives_msg
call print_string
inc byte es:[0x75] ; HDNUM
mov al, es:[0x75]
xor ah, ah
call print_hex
mov ax, newline
call print_string
%endif
pop ax
;
; Install our fixed disk parameter table.
@ -153,30 +176,37 @@ entry:
; For the 2nd disk, it is stored in the interrupt vector table, at vector 46h.
;
.install_fixed_disk_parameters_table:
mov ax, new_fdpt_msg
call print_string
mov ax, ROM_SEGMENT
mov es:[(0x41+DISK_NUMBER*5)*4+2], ax ; store segment
call print_hex
mov ax, colon
call print_string
xor cx, cx ; INT vector segment
mov es, cx
cmp al, 0x80
jne .second_disk
mov ax, cs
mov es:[0x41*4+2], ax ; store segment
mov ax, fixed_disk_parameters_table
mov es:[(0x41+DISK_NUMBER*5)*4], ax ; store offset
call print_hex
mov ax, newline
call print_string
mov es:[0x41*4+0], ax ; store offset
jmp .end_fdpt
.second_disk:
mov ax, cs
mov es:[0x46*4+2], ax ; store segment
mov ax, fixed_disk_parameters_table
mov es:[0x46*4+0], ax ; store offset
.end_fdpt:
%ifdef USE_BOOTSTRAP
;
; Increment the number of fixed disks in the BIOS Data Area.
; Install our BIOS INT18h hook into the interrupt vector table.
;
mov ax, 0x40 ; BIOS data area
mov es, ax
inc byte es:[0x75] ; HDNUM
.install_18h_vector:
mov ax, cs
mov es:[0x18*4+2], ax ; store segment
mov ax, int18h_entry
mov es:[0x18*4], ax ; store offset
%endif
.skip:
sti
pop dx
pop cx
pop ax
pop es
retf
@ -210,52 +240,94 @@ entry:
;
int13h_entry:
%ifdef EXTRA_DEBUG
push TEMP0
mov TEMP0, sp
mov TEMP0, [TEMP0+6] ; grab the flags for iret
push TEMP0
popf
pop TEMP0
call dump_regs
%endif
sti
push TEMP0
push TEMP1
cmp dl, 0x80+DISK_NUMBER ; is this our drive?
push ax
push dx
mov dx, REG_SCRATCH_0
in al, dx
pop dx
cmp dl, al ; is this our drive?
pop ax
je .check_function
;
; This is not an operation for the SD Card. Forward to the BIOS INT 13h handler.
;
.forward_to_bios:
%ifdef TAKE_OVER_FIXED_DISK_0
cmp dl, 0x81 ; is this the other fixed drive?
jne .no_fixed_disk_take_over
mov dl, 0x80
call swap_fixed_disk_parameters_tables
.no_fixed_disk_take_over:
%endif
mov TEMP0, ax ; save ax
mov TEMP1, dx ; save dx
pushf ; setup for iret from INT 13h handler
push cs ; setup for iret from INT 13h handler
mov ax, .return_common
mov ax, .return_from_int13h
push ax ; setup for iret from INT 13h handler
.simulate_int13h:
;
; Simulate INT 13h with the original vector.
;
pushf ; setup for iret below
mov dx, 0x284 ; scratch register 1-2
mov dx, REG_SCRATCH_1
%ifndef AS_COM_PROGRAM
in ax, dx
%else
mov ax, cs
%endif
push ax ; setup for iret below
mov dx, 0x286 ; scratch register 3-4
push ax ; setup for retf below
mov dx, REG_SCRATCH_3
%ifndef AS_COM_PROGRAM
in ax, dx
%else
mov ax, fake_int13h_entry
%endif
push ax ; setup for iret below
push ax ; setup for retf below
mov ax, TEMP0 ; restore ax
mov dx, TEMP1 ; restore dx
iret ; call the INT 13h handler
; will return at .return_common
cli ; INT inhibits interrupts
retf ; call the INT 13h handler
.return_from_int13h:
sti ; just in case
pushf
push ax
mov ax, TEMP1 ; original dx
cmp al, 0x80 ; is fixed fixed?
jb .skip_update_hdnum
%ifdef TAKE_OVER_FIXED_DISK_0
mov dl, 0x81
call swap_fixed_disk_parameters_tables
%endif
mov ax, TEMP0 ; original ax
cmp ah, 0x08 ; is read parameters?
jne .skip_update_hdnum
push es
mov ax, 0x40 ; BIOS data area
mov es, ax
mov dl, es:[0x75] ; HDNUM
pop es
.skip_update_hdnum:
pop ax
popf
jmp .return_common
;
; This is an operation for the SD Card. Use our own INT 13h logic.
;
.check_function:
cmp ah, 0x15 ; is valid function?
cmp ah, 0x19 ; is valid function?
jle .prepare_call
call func_unsupported
jmp .update_bda
@ -319,6 +391,7 @@ int13h_entry:
.return_with_flags:
pop TEMP1
pop TEMP0
sti ; workaround - MS-DOS does not properly propagate IF
%ifdef EXTRA_DEBUG
call dump_regs
%endif
@ -350,6 +423,10 @@ func_table:
dw func_unsupported ; diagnostics
dw func_10_is_ready ; diagnostics
dw func_15_read_size
dw func_unsupported ; detect_change
dw func_unsupported ; set_media_type
dw func_unsupported ; set_media_type
dw func_10_is_ready ; park_heads
func_unsupported:
%ifdef DEBUG
@ -440,6 +517,7 @@ func_02_read_sector:
jc error_sector_not_found
; TODO: (robustness) check buffer boundaries
.setup:
push ds
push bx
push cx
push dx
@ -447,9 +525,11 @@ func_02_read_sector:
push ax
mov cx, ax ; number of sectors to read
xor ch, ch
mov di, bx ; setup use of stosw
mov ax, cs
mov ds, ax
mov di, bx ; setup use of movsw
.assert_cs:
mov dx, 0x282 ; chip select port
mov dx, REG_CS
mov al, 0 ; assert chip select
out dx, al
.cmd17:
@ -468,46 +548,40 @@ func_02_read_sector:
mov ax, wait_msg
call print_string
%endif
mov dx, 0x280 ; data port
mov cx, 50000 ; timeout (50ms)
jmp .receive_token_no_delay
mov dx, REG_TIMEOUT
mov al, 10 ; 100 ms
out dx, al
.receive_token:
call delay_us
.receive_token_no_delay:
mov dx, REG_DATA
in al, dx
cmp al, 0xfe
loopne .receive_token
jne .error
je .got_token
mov dx, REG_TIMEOUT
in al, dx
test al, al
jnz .error
jmp .receive_token
.got_token:
%ifdef DEBUG_IO
mov ax, sd_token_msg
call print_string
%endif
mov cx, 256 ; block size (in words)
push dx
mov dx, 0x283 ; scratch register 0
in al, dx
pop dx
test al, al ; supports insw?
push si
mov si, end_of_rom ; virtual buffer
cld
jz .receive_block
.receive_block_fast:
cpu 186
rep insw
cpu 8086
jmp .receive_crc
.receive_block:
in ax, dx
stosw
loop .receive_block
rep movsw
.receive_crc:
in ax, dx ; discard CRC
lodsw ; discard CRC
pop si
add TEMP_LO, 1 ; next block
adc TEMP_HI, 0 ; carry
pop cx ; number of sectors left to read
loop .cmd17
.success:
.deassert_cs1:
mov dx, 0x282 ; chip select port
mov dx, REG_CS
mov al, 1 ; deassert chip select
out dx, al
.return1:
@ -516,10 +590,11 @@ cpu 8086
pop dx
pop cx
pop bx
pop ds
jmp succeeded
.error:
.deassert_cs2:
mov dx, 0x282 ; chip select port
mov dx, REG_CS
mov al, 1 ; deassert chip select
out dx, al
.return2:
@ -530,6 +605,7 @@ cpu 8086
pop dx
pop cx
pop bx
pop ds
jmp error_drive_not_ready
;
@ -576,9 +652,11 @@ func_03_write_sector:
xor ch, ch
mov di, bx ; destination address
mov ax, es
mov ds, ax
mov ds, ax ; save es and setup for movsw
mov ax, cs
mov es, ax
.assert_cs:
mov dx, 0x282 ; chip select port
mov dx, REG_CS
mov al, 0 ; assert chip select
out dx, al
.cmd24:
@ -593,41 +671,36 @@ func_03_write_sector:
mov cl, 0x58 ; CMD24
call send_sd_read_write_cmd
jc .error
mov dx, 0x280 ; data port
mov dx, REG_DATA
mov al, 0xfe ; send token
out dx, al
mov cx, 256 ; block size (in words)
xchg di, si ; save si (aka TEMP1)
push dx
mov dx, 0x283 ; scratch register 0
in al, dx
pop dx
test al, al ; supports outsw?
push si ; save si (aka TEMP1)
mov si, di
mov di, end_of_rom ; virtual buffer
cld
jz .send_block
.send_block_fast:
cpu 186
rep outsw
cpu 8086
jmp .end_send_block
.send_block:
lodsw
out dx, ax
loop .send_block
.end_send_block:
xchg si, di ; restore si (aka TEMP1)
rep movsw
mov di, si
pop si ; restore si (aka TEMP1)
%ifdef DEBUG_IO
mov ax, wait_msg
call print_string
%endif
mov cx, 50000 ; timeout (50ms)
jmp .receive_status_no_delay
mov dx, REG_TIMEOUT
mov al, 25 ; 250 ms
out dx, al
.receive_status:
call delay_us
.receive_status_no_delay:
mov dx, REG_DATA
in al, dx
cmp al, 0xff
loope .receive_status
jne .got_status
mov dx, REG_TIMEOUT
in al, dx
test al, al
jnz .error
jmp .receive_status
.got_status:
%ifdef DEBUG_IO
push ax
mov ax, sd_status_msg
@ -647,15 +720,20 @@ cpu 8086
mov ax, wait_msg
call print_string
%endif
mov cx, 50000 ; timeout (50ms)
jmp .receive_finish_no_delay
mov dx, REG_TIMEOUT
mov al, 25 ; 250 ms
out dx, al
.receive_finish:
call delay_us
.receive_finish_no_delay:
mov dx, REG_DATA
in al, dx
test al, al
loope .receive_finish
jz .error
jnz .got_finish
mov dx, REG_TIMEOUT
in al, dx
test al, al
jnz .error
jmp .receive_finish
.got_finish:
%ifdef DEBUG_IO
mov ax, sd_idle_msg
call print_string
@ -663,13 +741,20 @@ cpu 8086
add TEMP_LO, 1 ; next block
adc TEMP_HI, 0 ; carry
pop cx ; number of sectors left to write
%ifndef DEBUG_IO
loop .cmd24
%else
dec cx
jnz .cmd24
%endif
.success:
.deassert_cs1:
mov dx, 0x282 ; chip select port
mov dx, REG_CS
mov al, 1 ; deassert chip select
out dx, al
.return1:
mov ax, ds
mov es, ax ; restore es
pop ax
pop di
pop dx
@ -679,11 +764,13 @@ cpu 8086
jmp succeeded
.error:
.deassert_cs2:
mov dx, 0x282 ; chip select port
mov dx, REG_CS
mov al, 1 ; deassert chip select
out dx, al
.return2:
pop cx ; number of sectors not written successfully
mov ax, ds
mov es, ax ; restore es
pop ax
sub al, cl ; number of sectors written successfully
pop di
@ -749,6 +836,7 @@ func_08_read_params:
mov es, ax
mov dl, es:[0x75] ; HDNUM
pop es
; the last cylinder is reserved on fixed disks
mov ch, ((NUM_CYLINDERS - 2) & 0xff)
mov cl, (((NUM_CYLINDERS - 2) & 0x300) >> 2) | SECTORS_PER_TRACK
@ -836,10 +924,83 @@ succeeded:
clc
ret
%ifdef USE_BOOTSTRAP
;
; INT 18h entry point.
;
int18h_entry:
xor ax, ax
mov ds, ax
mov es, ax
.clear_memory:
mov cx, 256
mov di, 0x7c00
rep stosw
.read_boot_sector:
mov dx, REG_SCRATCH_0
in al, dx
mov dl, al
xor dh, dh
mov ax, 0x201 ; read 1 sector
mov cx, 1 ; sector 1
mov bx, 0x7c00
int 0x13
.test_signature:
cmp word [0x7c00+510], 0xaa55
jne .no_boot
%if %isdef(USE_BOOTSTRAP) && %isdef(FORCE_OWN_BOOTSTRAP)
.update_bda:
;
; Increment the number of fixed disks in the BIOS Data Area, since we did not do it earlier.
;
mov ax, num_drives_msg
call print_string
mov ax, 0x40 ; BIOS data area
mov es, ax
inc byte es:[0x75] ; HDNUM
mov al, es:[0x75]
call print_hex
mov ax, newline
call print_string
%endif
.jump_to_boot:
mov ax, boot_msg
call print_string
xor ax, ax
mov es, ax
jmp 0:0x7c00
.no_boot:
mov ax, no_boot_msg
call print_string
sti
.loop:
hlt
jmp .loop
%endif
;
; Disk utilities
;
%ifdef TAKE_OVER_FIXED_DISK_0
swap_fixed_disk_parameters_tables:
push es
push ax
push bx
xor ax, ax ; INT vector segment
mov es, ax
mov ax, es:[0x41*4+2]
xchg es:[0x46*4+2], ax
mov es:[0x41*4+2], ax
mov ax, es:[0x41*4+0]
xchg es:[0x46*4+0], ax
mov es:[0x41*4+0], ax
pop bx
pop ax
pop es
ret
%endif
;
; Compute LBA address based on CHS address
; in: CH = cylinder number (low 8 bits)
@ -931,28 +1092,30 @@ init_sd:
push cx
push dx
push si
%ifndef AS_COM_PROGRAM
mov ax, ROM_SEGMENT
mov ax, cs
mov ds, ax
%endif
mov dx, 0x282 ; chip select port
mov dx, REG_CS
mov al, 1 ; deassert chip select
.power_up_delay:
out dx, al
xor cx, cx
mov dx, 1000 ; microseconds
mov cx, 0x0001
mov dx, 0x86a0 ; 0x186a0 = 100 ms
mov ah, 0x86 ; wait
int 0x15
mov dx, 0x280 ; data port
.dummy_cycles:
mov dx, REG_DATA
mov al, 0xff
mov cx, 80 ; send 80 clock cycles
mov cx, 10 ; send 80 clock cycles
.synchronize:
out dx, al
loop .synchronize
.assert_cs:
mov dx, 0x282 ; chip select port
mov dx, REG_CS
mov al, 0 ; assert chip select
out dx, al
.cmd0:
mov bx, 10 ; retries
.retry_cmd0:
%ifdef DEBUG_IO
mov ax, send_cmd0_msg
call print_string
@ -961,7 +1124,16 @@ init_sd:
mov cx, 1 ; response is 1 byte
mov ah, 1 ; expect idle state
call send_sd_init_cmd
jc .exit
jnc .cmd8
.delay_retry_cmd0:
xor cx, cx
mov dx, 20000 ; microseconds
mov ah, 0x86 ; wait
int 0x15
dec bx
jnz .retry_cmd0
stc
jmp .exit
.cmd8:
%ifdef DEBUG_IO
mov ax, send_cmd8_msg
@ -973,7 +1145,9 @@ init_sd:
call send_sd_init_cmd
jc .exit
.acmd41:
mov bx, 100 ; retries
mov dx, REG_TIMEOUT
mov al, 250 ; 2.5 s
out dx, al
.retry_acmd41:
%ifdef DEBUG_IO
mov ax, send_acmd41_msg
@ -983,22 +1157,19 @@ init_sd:
mov cx, 1 ; response is 1 byte
mov ah, 1 ; expect idle state
call send_sd_init_cmd
; TODO: (older cards) on error, try CMD1
; TODO: (older cards): handle v1 vs v2
mov si, acmd41
mov cx, 1 ; response is 1 byte
mov ah, 0 ; expect ready state
call send_sd_init_cmd
jnc .exit
pushf
xor cx, cx
mov dx, 1000 ; microseconds
mov ah, 0x86 ; wait
int 0x15
popf
dec bx
jnz .retry_acmd41
; TODO: (older cards) send CMD16 to set block size
mov dx, REG_TIMEOUT
in al, dx
test al, al
jz .retry_acmd41
stc
.exit:
; TODO: (older cards): retrieve SDHC flag
pop si
pop dx
pop cx
@ -1029,7 +1200,7 @@ init_sd:
; FL = <TRASH>
;
send_sd_init_cmd:
mov dx, 0x280 ; data port
mov dx, REG_DATA
.settle_before:
mov al, 0xff
out dx, al
@ -1078,21 +1249,25 @@ acmd41 db 0x69, 0x40, 0x00, 0x00, 0x00, 0x01
; FL = <TRASH>
;
send_sd_read_write_cmd:
mov dx, 0x280 ; data port
mov dx, XTMAX_IO_BASE+0 ; data port
push ax
.settle_before:
mov al, 0xff
out dx, al
.send_cmd:
mov al, cl ; command byte
mov ah, bh ; address byte 1
out dx, ax
pop ax ; address byte 3
xchg al, bl ; address byte 2
out dx, ax
xchg al, bl ; address byte 4
mov ah, 0x1 ; crc (dummy)
out dx, ax
out dx, al
mov al, bh ; address byte 1
out dx, al
mov al, bl ; address byte 2
out dx, al
pop ax
xchg al, ah ; address byte 3
out dx, al
xchg al, ah ; address byte 4
out dx, al
mov al, 0x1 ; crc (dummy)
out dx, al
mov cx, 8 ; retries
.receive_r1:
in al, dx
@ -1108,21 +1283,6 @@ send_sd_read_write_cmd:
; General utilities
;
;
; Wait 1 microseconds.
; out: AX = <TRASH>
; FL = <TRASH>
delay_us:
push cx
push dx
xor cx, cx
mov dx, 1 ; microseconds
mov ah, 0x86 ; wait
int 0x15
pop dx
pop cx
ret
%include "utils.inc"
%ifdef DEBUG
@ -1147,16 +1307,16 @@ debug_handler:
welcome_msg db 'BootROM for XTMax v1.0', 0xD, 0xA
db 'Copyright (c) 2025 Matthieu Bucchianeri', 0xD, 0xA, 0
string_io_msg db 'CPU supports INS/OUTS instructions', 0xD, 0xA, 0
old_13h_msg db 'Old INT13h Vector = ', 0
new_13h_msg db 'New INT13h Vector = ', 0
new_fdpt_msg db 'New Fixed Disk Parameter Table = ', 0
rom_base_msg db 'ROM Base Address = ', 0
init_ok_msg db 'SD Card initialized successfully', 0xD, 0xA, 0
init_error_msg db 'SD Card failed to initialize', 0xD, 0xA, 0
disk_id_msg db 'Fixed Disk ID = ', 0
num_drives_msg db 'Total Fixed Disk Drives = ', 0
unsupported_msg db 'Unsupported INT13h Function ', 0
colon db ':', 0
space db ' ', 0
newline db 0xD, 0xA, 0
%ifdef USE_BOOTSTRAP
boot_msg db 'Booting from SD Card...', 0xD, 0xA, 0
no_boot_msg db 'Not bootable', 0xD, 0xA, 0
%endif
%ifdef DEBUG
handler_msg db 'INT13h Function ', 0
@ -1182,3 +1342,8 @@ sd_idle_msg db 'Received idle', 0xD, 0xA, 0
times 2047-($-$$) db 0
db 0 ; will be used to complete the checksum.
%endif
;
; The virtual buffer for I/O follows the ROM immediately.
;
end_of_rom:

View File

@ -1,2 +1,3 @@
..\Driver_Build_Tools\NASM\nasm.exe -f bin -o bootrom.com -DAS_COM_PROGRAM .\bootrom.asm
..\Driver_Build_Tools\NASM\nasm.exe -f bin -o bootrom .\bootrom.asm & python checksum.py
..\Driver_Build_Tools\NASM\nasm.exe -f bin -o bootrom .\bootrom.asm & python checksum.py & python generate_header.py
..\Driver_Build_Tools\NASM\nasm.exe -f bin -o xtmdiags.com .\diags.asm

View File

@ -1,23 +1,6 @@
# https://stackoverflow.com/questions/53808694/how-do-i-format-a-python-list-as-an-initialized-c-array
def to_c_array(values, ctype="float", name="table", formatter=str, colcount=8):
# apply formatting to each element
values = [formatter(v) for v in values]
# split into rows with up to `colcount` elements per row
rows = [values[i:i+colcount] for i in range(0, len(values), colcount)]
# separate elements with commas, separate rows with newlines
body = ',\n '.join([', '.join(r) for r in rows])
# assemble components into the complete string
return '{} {}[] = {{\n {}}};'.format(ctype, name, body)
with open("bootrom", "rb") as f:
b = bytearray(f.read())
# compute the checksum and store a byte to
b[-1] = 256 - sum(b[0:-1]) & 0xff
with open("bootrom", "wb") as f:
f.write(b)
with open("../../Code/XTMax/bootrom.h", "w") as f:
f.write("#define BOOTROM_ADDR 0xCE000\n")
f.write(to_c_array(b, ctype="unsigned char", name="BOOTROM", colcount=16))

View File

@ -0,0 +1,352 @@
org 0x100
;
; The base I/O port for the XTMAX SD Card.
;
%define XTMAX_IO_BASE (0x280)
%define REG_SCRATCH_0 (XTMAX_IO_BASE+2) ; fixed disk id
%define REG_SCRATCH_1 (XTMAX_IO_BASE+3) ; BIOS INT13h segment
%define REG_SCRATCH_2 (XTMAX_IO_BASE+4) ; BIOS INT13h segment
%define REG_SCRATCH_3 (XTMAX_IO_BASE+5) ; BIOS INT13h offset
%define REG_SCRATCH_4 (XTMAX_IO_BASE+6) ; BIOS INT13h offset
entry:
mov ax, welcome_msg
call print_string
;
; Inspect the INT13h and the HDNUM
;
mov ax, current_13h_msg
call print_string
xor ax, ax ; INT vector segment
mov es, ax
mov ax, es:[0x13*4+2]
call print_hex
mov ax, colon
call print_string
mov ax, es:[0x13*4]
call print_hex
mov ax, newline
call print_string
mov ax, saved_13h_msg
call print_string
mov dx, REG_SCRATCH_1
in ax, dx
call print_hex
mov ax, colon
call print_string
mov dx, REG_SCRATCH_3
in ax, dx
call print_hex
mov ax, newline
call print_string
mov ax, hdnum_msg
call print_string
mov ax, 0x40 ; BIOS data area
mov es, ax
mov al, es:[0x75] ; HDNUM
call print_hex_byte
mov ax, newline
call print_string
mov ax, disk_id_msg
call print_string
mov dx, REG_SCRATCH_0
in al, dx
xor ah, ah
call print_hex_byte
mov ax, newline
call print_string
mov ax, newline
call print_string
;
; Inspect the Fixed Disk Parameters Tables
;
mov ax, disk80_fdpt_msg
call print_string
xor ax, ax ; INT vector segment
mov es, ax
mov ax, es:[0x41*4+2]
mov bx, ax
call print_hex
mov ax, colon
call print_string
mov ax, es:[0x41*4]
mov si, ax
call print_hex
mov ax, newline
call print_string
mov ax, space
call print_string
mov ax, space
call print_string
mov es, bx
mov cx, 18
.dump_disk80_fdpt:
mov al, es:[si]
inc si
call print_hex_byte
mov ax, space
call print_string
loop .dump_disk80_fdpt
mov ax, newline
call print_string
mov ax, disk81_fdpt_msg
call print_string
xor ax, ax ; INT vector segment
mov es, ax
mov ax, es:[0x46*4+2]
mov bx, ax
call print_hex
mov ax, colon
call print_string
mov ax, es:[0x46*4]
mov si, ax
call print_hex
mov ax, newline
call print_string
mov ax, space
call print_string
mov ax, space
call print_string
mov es, bx
mov cx, 18
.dump_disk81_fdpt:
mov al, es:[si]
inc si
call print_hex_byte
mov ax, space
call print_string
loop .dump_disk81_fdpt
mov ax, newline
call print_string
mov ax, newline
call print_string
;
; Invoke Read Parameters on the fixed disks.
;
mov ax, parm_disk80_msg
call print_string
xor ax, ax
xor bx, bx
xor cx, cx
xor dx, dx
xor si, si
xor di, di
xor bp, bp
mov dl, 0x80
mov ah, 0x08
call dump_regs
int 0x13
call dump_regs
mov ax, newline
call print_string
mov ax, parm_disk81_msg
call print_string
xor ax, ax
xor bx, bx
xor cx, cx
xor dx, dx
xor si, si
xor di, di
xor bp, bp
mov dl, 0x81
mov ah, 0x08
call dump_regs
int 0x13
call dump_regs
; wait for kbd
mov ah, 0x01
int 0x21
mov ax, newline
call print_string
;
; Read First Sector on the fixed disks.
;
xor ax, ax
mov cx, 256
mov di, buf_read
rep stosw
mov ax, read_disk80_msg
call print_string
xor ax, ax
xor bx, bx
xor cx, cx
xor dx, dx
xor si, si
xor di, di
xor bp, bp
mov dl, 0x80
mov ah, 0x02
mov bx, ds
mov es, bx
mov bx, buf_read
mov ch, 0
mov cl, 1
mov dh, 0
mov al, 1
call dump_regs
int 0x13
call dump_regs
mov ax, newline
call print_string
mov cx, 16
mov si, buf_read
.dump_disk80_sector_1:
lodsb
call print_hex_byte
mov ax, space
call print_string
loop .dump_disk80_sector_1
mov ax, newline
call print_string
mov ax, dotdotdot
call print_string
mov cx, 16
add si, 512-16-16
.dump_disk80_sector_2:
lodsb
call print_hex_byte
mov ax, space
call print_string
loop .dump_disk80_sector_2
mov ax, newline
call print_string
mov ax, newline
call print_string
xor ax, ax
mov cx, 256
mov di, buf_read
rep stosw
mov ax, read_disk81_msg
call print_string
xor ax, ax
xor bx, bx
xor cx, cx
xor dx, dx
xor si, si
xor di, di
xor bp, bp
mov dl, 0x81
mov ah, 0x02
mov bx, ds
mov es, bx
mov bx, buf_read
mov ch, 0
mov cl, 1
mov dh, 0
mov al, 1
call dump_regs
int 0x13
call dump_regs
mov ax, newline
call print_string
mov cx, 16
mov si, buf_read
.dump_disk81_sector_1:
lodsb
call print_hex_byte
mov ax, space
call print_string
loop .dump_disk81_sector_1
mov ax, newline
call print_string
mov ax, dotdotdot
call print_string
mov cx, 16
add si, 512-16-16
.dump_disk81_sector_2:
lodsb
call print_hex_byte
mov ax, space
call print_string
loop .dump_disk81_sector_2
mov ax, newline
call print_string
;
; DOS exit program.
;
mov ah, 0x4c
xor al, al
int 0x21
buf_read times 512 db 0
;
; General utilities
;
%define AS_COM_PROGRAM
%include "utils.inc"
;
; Display an 8-bit value in hex.
; in: AL = value
; out: AX = <TRASH>
;
print_hex_byte:
pushf
push ds
push bx
push cx
push dx
push si
mov dl, al
xor ah, ah
mov ax, cs
mov ds, ax
xor bx, bx
cld
.nibble1:
mov si, dx
mov cl, 4
shr si, cl
and si, 0xf
mov al, [hex_map+si]
mov ah, 0xe
int 0x10
.nibble2:
mov si, dx
and si, 0xf
mov al, [hex_map+si]
mov ah, 0xe
int 0x10
pop si
pop dx
pop cx
pop bx
pop ds
popf
ret
;
; Strings
;
welcome_msg db 'XTMax BootROM diagnostics', 0xD, 0xA, 0xD, 0xA, 0
current_13h_msg db 'Current INT13h Vector = ', 0
saved_13h_msg db 'Saved INT13h Vector = ', 0
hdnum_msg db 'BIOS Data Area HDNUM = ', 0
disk_id_msg db 'XTMax Fixed Disk ID = ', 0
disk80_fdpt_msg db 'Fixed Disk 80h Parameters Table = ', 0
disk81_fdpt_msg db 'Fixed Disk 81h Parameters Table = ', 0
parm_disk80_msg db 'Call Fixed Disk 80h Read Parameters', 0xD, 0xA, 0
parm_disk81_msg db 'Call Fixed Disk 81h Read Parameters', 0xD, 0xA, 0
read_disk80_msg db 'Read First Sector on Fixed Disk 80h', 0xD, 0xA, 0
read_disk81_msg db 'Read First Sector on Fixed Disk 81h', 0xD, 0xA, 0
dotdotdot db '[...]', 0xD, 0xA, 0

View File

@ -0,0 +1,27 @@
segment = None
with open("bootrom.asm", "r") as f:
for line in f:
if line.startswith('%define ROM_SEGMENT'):
segment = int(line[19:].strip('() \n'), 16)
break
with open("bootrom", "rb") as f:
bitstream = bytearray(f.read())
# https://stackoverflow.com/questions/53808694/how-do-i-format-a-python-list-as-an-initialized-c-array
def to_c_array(values, ctype="float", name="table", formatter=str, colcount=8):
# apply formatting to each element
values = [formatter(v) for v in values]
# split into rows with up to `colcount` elements per row
rows = [values[i:i+colcount] for i in range(0, len(values), colcount)]
# separate elements with commas, separate rows with newlines
body = ',\n '.join([', '.join(r) for r in rows])
# assemble components into the complete string
return '{} {}[] = {{\n {}}};'.format(ctype, name, body)
with open("../../Code/XTMax/bootrom.h", "w") as f:
f.write("#define BOOTROM_ADDR {}\n".format(hex(segment << 4)))
f.write(to_c_array(bitstream, ctype="unsigned char", name="BOOTROM", colcount=16))

View File

@ -8,6 +8,7 @@
xor ax, ax
lahf
sti
mov ax, 0x1122
mov bx, 0x3344
mov cx, 0x5566
@ -114,6 +115,8 @@ do_int13h:
; dump registers
%ifdef DUMP_REGS
popf
pushf
call dump_regs
pop ax
call print_hex
@ -145,6 +148,11 @@ fake_int13h_entry:
mov al, ah
xor ah, ah
call print_hex
mov ax, drive_msg
call print_string
mov ax, dx
xor ah, ah
call print_hex
mov ax, newline
call print_string
pop ax
@ -162,6 +170,7 @@ buf_write db 1, 2, 3, 4, 5, 6, 7, 8
buf_read times 1024 db 0
fake_handler_msg db 'BIOS INT13h Function ', 0
drive_msg db ' Drive ', 0
test_success_msg db 'Call succeeded ', 0
test_failed_msg db 'Call failed ', 0

View File

@ -9,10 +9,8 @@ print_string:
push bx
push si
mov si, ax
%ifndef AS_COM_PROGRAM
mov ax, ROM_SEGMENT
mov ax, cs
mov ds, ax
%endif
mov ah, 0xe
xor bx, bx
cld
@ -42,10 +40,8 @@ print_hex:
push dx
push si
mov dx, ax
%ifndef AS_COM_PROGRAM
mov ax, ROM_SEGMENT
mov ax, cs
mov ds, ax
%endif
xor bx, bx
cld
.nibble1:
@ -130,10 +126,19 @@ dump_regs:
call print_hex
mov ax, space
call print_string
pushf
pop ax
call print_hex
mov ax, space
call print_string
mov ax, newline
call print_string
pop ax
ret
registers_msg db ' AX BX CX DX DS SI ES DI BP', 0xD, 0xA, 0
registers_msg db ' AX BX CX DX DS SI ES DI BP FLAGS', 0xD, 0xA, 0
%endif
colon db ':', 0
space db ' ', 0
newline db 0xD, 0xA, 0

View File

@ -365,14 +365,8 @@ PUBLIC void Initialize (rh_init_t far *rh)
WORD brkadr, reboot[2]; int status, i;
/* The version number is sneakily stored in the device header! */
cdprintf("SD Card driver V%c.%c for XTMax (%s)\n based on SD pport device driver (C) 2014 by Dan Marks\n based on TU58 by Robert Armstrong\n",
header.name[6], header.name[7],
#ifdef USE186
"80186+"
#else
"8086"
#endif
);
cdprintf("SD Card driver V%c.%c for XTMax\n based on SD pport device driver (C) 2014 by Dan Marks\n based on TU58 by Robert Armstrong\n",
header.name[6], header.name[7]);
/* Parse the options from the CONFIG.SYS file, if any... */
if (!parse_options((char far *) rh->bpbtbl)) {

View File

@ -129,7 +129,7 @@ _header DD -1 ; link to the next device
DW DGROUP:STRATEGY ; address of the strategy routine
DW DGROUP:INTERRUPT; " " " interrupt "
DB 1 ; number of drives
DB 'SDCDv12' ; DOS doesn't really use these bytes
DB 'SDCDv13' ; DOS doesn't really use these bytes
; The geometry (sectors/track, tracks/cylinder) defined in the BPB is rather
; arbitrary in the case of the TU58, but there are things to watch out for.

View File

@ -5,7 +5,7 @@ ASM=tasm -mx
DEPS=cprint.c driver.c sd.c sdmm.c cprint.h diskio.h driver.h integer.h sd.h standard.h
all: xtsd.sys xtsd186.sys
all: xtsd.sys
.asm.obj:
$(ASM) $*
@ -17,13 +17,6 @@ xtsd.sys: header.obj $(DEPS)
$(CC) driver.c
tlink -t -m -s -n header cprint sd sdmm driver, $@
xtsd186.sys: header.obj $(DEPS)
$(CC) -1 -DUSE186 cprint.c
$(CC) -1 -DUSE186 sd.c
$(CC) -1 -DUSE186 sdmm.c
$(CC) -1 -DUSE186 driver.c
tlink -t -m -s -n header cprint sd sdmm driver, $@
clean:
del *.obj
del *.map

View File

@ -27,8 +27,9 @@
/* Platform dependent macros and functions needed to be modified */
/*-------------------------------------------------------------------------*/
DWORD VIRT_BUFFER=0xCE000000+2048;
WORD DATAPORT=0x280;
WORD CONTROLPORT=0x282;
WORD CONTROLPORT=0x280+1;
#if 1
#define TOUTCHR(x)
@ -177,30 +178,17 @@ void xmit_mmc (
// NOTE: Callers always use buffer sizes multiple of two.
bc >>= 1;
#ifndef USE186
_asm {
mov cx,bc
mov dx,DATAPORT
push ds
push es
les di,VIRT_BUFFER
lds si,dword ptr buff
}
repeat:
_asm {
lodsw
out dx, ax
loop repeat
cld
rep movsw
pop es
pop ds
}
#else
_asm {
mov cx,bc
mov dx,DATAPORT
push ds
lds si,dword ptr buff
rep outsw
pop ds
}
#endif
}
@ -218,30 +206,17 @@ void rcvr_mmc (
// NOTE: Callers always use buffer sizes multiple of two.
bc >>= 1;
#ifndef USE186
_asm {
mov cx,bc
mov dx,DATAPORT
push ds
push es
les di,dword ptr buff
}
repeat:
_asm {
in ax, dx
stosw
loop repeat
lds si,VIRT_BUFFER
cld
rep movsw
pop es
pop ds
}
#else
_asm {
mov cx,bc
mov dx,DATAPORT
push es
les di,dword ptr buff
rep insw
pop es
}
#endif
}
/*-----------------------------------------------------------------------*/
@ -254,14 +229,13 @@ int wait_ready (void) /* 1:OK, 0:Timeout */
BYTE d;
UINT tmr;
for (tmr = 5000; tmr; tmr--) { /* Wait for ready in timeout of 500ms */
outp(DATAPORT+7, 50);
do { /* Wait for ready in timeout of 500ms */
d = inp(DATAPORT);
if (d == 0xFF) break;
dly_us(100);
}
} while(!inp(DATAPORT+7));
return tmr ? 1 : 0;
return d == 0xFF;
}
@ -310,11 +284,11 @@ int rcvr_datablock ( /* 1:OK, 0:Failed */
UINT tmr;
for (tmr = 1000; tmr; tmr--) { /* Wait for data packet in timeout of 100ms */
outp(DATAPORT+7, 10);
do { /* Wait for data packet in timeout of 100ms */
d = inp(DATAPORT);
if (d != 0xFF) break;
dly_us(100);
}
} while(!inp(DATAPORT+7));
if (d != 0xFE) {
return 0; /* If not valid data token, return with error */
}

Binary file not shown.

Binary file not shown.