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:
parent
ec79bbdbc9
commit
fe8385da08
@ -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
130
XTMax/Code/XTMax/bootrom.h
Normal 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};
|
||||
@ -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:
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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))
|
||||
|
||||
352
XTMax/Drivers/BootROM/diags.asm
Normal file
352
XTMax/Drivers/BootROM/diags.asm
Normal 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
|
||||
27
XTMax/Drivers/BootROM/generate_header.py
Normal file
27
XTMax/Drivers/BootROM/generate_header.py
Normal 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))
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)) {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
Loading…
x
Reference in New Issue
Block a user