From 422a4306f22493edf345c379954b605165632f7b Mon Sep 17 00:00:00 2001 From: Matthieu Bucchianeri <69611560+mbucchia@users.noreply.github.com> Date: Sun, 19 Jan 2025 19:04:05 -0800 Subject: [PATCH] Improvements to the SD Card and EMS drivers. (#31) * Refactor SD driver the IO to XTMax. * Refactor the EMS driver to support 8MB. --- XTMax/Code/XTMax/XTMax.ino | 128 ++++++++-------- XTMax/Drivers/LTEMM.EXE | Bin 9449 -> 0 bytes XTMax/Drivers/LTEMM/.gitignore | 1 + XTMax/Drivers/LTEMM/.vscode/tasks.json | 2 +- XTMax/Drivers/LTEMM/LTEMM.ASM | 196 +++++++++++-------------- XTMax/Drivers/LTEMM/LTEMM.EXE | Bin 9449 -> 0 bytes XTMax/Drivers/LTEMM/LTEMM.INC | 15 +- XTMax/Drivers/LTEMM/MAKEFILE | 4 +- XTMax/Drivers/LTEMM/README.TXT | 6 +- XTMax/Drivers/SD.SYS | Bin 7902 -> 0 bytes XTMax/Drivers/SD286.SYS | Bin 7717 -> 0 bytes XTMax/Drivers/SDPP/DISKIO.H | 2 - XTMax/Drivers/SDPP/DRIVER.C | 18 +-- XTMax/Drivers/SDPP/MAKEFILE | 14 +- XTMax/Drivers/SDPP/README.TXT | 57 +------ XTMax/Drivers/SDPP/SDMM.C | 57 +++---- XTMax/Drivers/XTEMM.EXE | Bin 0 -> 16837 bytes XTMax/Drivers/XTSD.SYS | Bin 0 -> 7630 bytes XTMax/Drivers/XTSD186.SYS | Bin 0 -> 7451 bytes 19 files changed, 201 insertions(+), 299 deletions(-) delete mode 100644 XTMax/Drivers/LTEMM.EXE delete mode 100644 XTMax/Drivers/LTEMM/LTEMM.EXE delete mode 100644 XTMax/Drivers/SD.SYS delete mode 100644 XTMax/Drivers/SD286.SYS create mode 100644 XTMax/Drivers/XTEMM.EXE create mode 100644 XTMax/Drivers/XTSD.SYS create mode 100644 XTMax/Drivers/XTSD186.SYS diff --git a/XTMax/Code/XTMax/XTMax.ino b/XTMax/Code/XTMax/XTMax.ino index 0cc1ed6..8c40a0f 100644 --- a/XTMax/Code/XTMax/XTMax.ino +++ b/XTMax/Code/XTMax/XTMax.ino @@ -2,7 +2,8 @@ // // File Name : XTMax.ino // Used on : -// Author : Ted Fried, MicroCore Labs +// Authors : Ted Fried, MicroCore Labs +// Matthieu Bucchianeri // Creation : 9/7/2024 // // Description: @@ -34,6 +35,10 @@ // Revision 6 12/14/2024 // - Made SD LPT base a # define // +// Revision 7 01/12/2024 +// - Refactor SD card I/O +// - Add support for 16-bit EMS page offsets. +// //------------------------------------------------------------------------ // // Copyright (c) 2024 Ted Fried @@ -152,7 +157,12 @@ #define PSRAM_RESET_VALUE 0x01000000 #define PSRAM_CLK_HIGH 0x02000000 -#define SD_LPT_BASE 0x378 +#define EMS_BASE_IO 0x260 // Must be a multiple of 8. +#define EMS_BASE_MEM 0xD0000 + +#define EMS_TOTAL_SIZE (8*1024*1024) + +#define SD_BASE 0x280 // Must be a multiple of 2. @@ -171,16 +181,10 @@ uint32_t databit_out = 0; uint8_t data_in = 0; uint8_t isa_data_out = 0; -uint8_t lpt_data = 0; -uint8_t lpt_status = 0x6F; -uint8_t lpt_control = 0xEC; uint8_t nibble_in =0; uint8_t nibble_out =0; uint8_t read_byte =0; -uint8_t reg_0x260 =0; -uint8_t reg_0x261 =0; -uint8_t reg_0x262 =0; -uint8_t reg_0x263 =0; +uint16_t ems_frame_pointer[4] = {0, 0, 0, 0}; uint8_t spi_shift_out =0; uint8_t sd_spi_datain =0; uint32_t sd_spi_cs_n = 0x0; @@ -386,6 +390,9 @@ inline void PSRAM_Configure() { // -------------------------------------------------------------------------------------------------- inline uint8_t PSRAM_Read(uint32_t address_in) { + if (address_in >= EMS_TOTAL_SIZE) { + return 0xff; + } // Send Command = Quad Read = 0x0B // @@ -423,15 +430,17 @@ inline uint8_t PSRAM_Read(uint32_t address_in) { GPIO9_DR = PSRAM_RESET_VALUE; // Drive CLK=0 , CS_n=1 GPIO9_GDIR = 0x3F000000; // Change Data[3:0] to outputs quickly -return read_byte; - } + return read_byte; +} // -------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------- -inline uint8_t PSRAM_Write(uint32_t address_in , int8_t local_data) { - +inline void PSRAM_Write(uint32_t address_in , int8_t local_data) { + if (address_in >= EMS_TOTAL_SIZE) { + return; + } // Send Command = Quad Write = 0x02 // @@ -457,9 +466,7 @@ inline uint8_t PSRAM_Write(uint32_t address_in , int8_t local_data) { nibble_out = local_data; PSRAM_Write_Clk_Cycle(); GPIO9_DR = PSRAM_RESET_VALUE; // Drive CLK=0 , CS_n=1 - -return read_byte; - } +} // -------------------------------------------------------------------------------------------------- @@ -489,14 +496,14 @@ inline void Mem_Read_Cycle() { isa_address = ADDRESS_DATA_GPIO6_UNSCRAMBLE; - if ( (isa_address>=0xE0000) && (isa_address<0xF0000) ) { // Expanded RAM page frame + if ( (isa_address>=EMS_BASE_MEM) && (isa_address=0xE0000) && (isa_address<0xF0000) ) { // Expanded RAM page frame + if ( (isa_address>=EMS_BASE_MEM) && (isa_address> 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; @@ -638,12 +647,12 @@ inline void IO_Read_Cycle() { } - else if ((isa_address&0x0FFC)==SD_LPT_BASE ) { // Location of Parallel Port + else if ((isa_address&0x0FFE)==SD_BASE ) { // Location of SD Card registers - switch (isa_address) { - case SD_LPT_BASE: sd_spi_dataout = 0xff; SD_SPI_Cycle(); isa_data_out = sd_spi_datain; break; - - } + // 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; 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; @@ -664,7 +673,7 @@ inline void IO_Write_Cycle() { isa_address = 0xFFFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE; - if ((isa_address&0x0FFC)==0x260 ) { // Location of 16 KB Expanded Memory page frame pointers + if ((isa_address&0x0FF8)==EMS_BASE_IO ) { // Location of 16 KB Expanded Memory page frame pointers 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; @@ -676,10 +685,14 @@ inline void IO_Write_Cycle() { data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE; switch (isa_address) { - case 0x260: reg_0x260 = data_in; break; - case 0x261: reg_0x261 = data_in; break; - case 0x262: reg_0x262 = data_in; break; - case 0x263: reg_0x263 = data_in; 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; @@ -687,7 +700,7 @@ inline void IO_Write_Cycle() { } - else if ((isa_address&0x0FFC)==SD_LPT_BASE ) { // Location of Parallel Port + else if ((isa_address&0x0FFC)==SD_BASE ) { // Location of SD Card registers GPIO7_DR = GPIO7_DATA_OUT_UNSCRAMBLE + MUX_ADDR_n_HIGH + CHRDY_OUT_LOW + trigger_out; GPIO8_DR = sd_pin_outputs + MUX_DATA_n_LOW + CHRDY_OE_n_HIGH + DATA_OE_n_HIGH; @@ -696,8 +709,9 @@ inline void IO_Write_Cycle() { data_in = 0xFF & ADDRESS_DATA_GPIO6_UNSCRAMBLE; switch (isa_address) { - case SD_LPT_BASE : sd_spi_dataout = data_in; SD_SPI_Cycle(); break; - case (SD_LPT_BASE+1): sd_spi_cs_n = data_in&0x1; break; + 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; } //gpio9_int = GPIO9_DR; @@ -708,10 +722,6 @@ inline void IO_Write_Cycle() { sd_pin_outputs = (sd_spi_cs_n<<17); // SD_CS_n - SD_CLK - SD_MOSI - //trigger_out = ((lpt_data&0x1)<<28); // SD_MOSI - //trigger_out = ((lpt_data&0x2)<<27); // SD_CLK - //trigger_out = ((lpt_data&0x4)<<26); // SD_CS_n - 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; } diff --git a/XTMax/Drivers/LTEMM.EXE b/XTMax/Drivers/LTEMM.EXE deleted file mode 100644 index c8d56d4e604d2b7205e1078c0dbe96b2262b9d14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9449 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 binary. - MOV pageofs,al - JMP getpr5 -getpr7: CMP AL,'q' ;set quiet mode JNZ getpr1 OR CL,4 @@ -3056,7 +3020,7 @@ instmsg PROC NEAR mov cl,4 shl ax,cl ; Multiply to 16 MOV DI,OFFSET totmem - CALL dbinasc + CALL dbinasc5 MOV SI,OFFSET install_msg CALL strdsp POP DI CX BX AX @@ -3105,10 +3069,9 @@ ramch14: ADD DI,SIZE phys_page_struct ADD SI,0400H MOV DX,BX ;disable physical pages --- - MOV AL,DIS_EMS - OUT DX,AL -; JJP ADD BX,4000h - INC BX ; lo-tech cards registers are sequential from base address + MOV AX,DIS_EMS + OUT DX,AX + ADD BX,2 ;each port is a word LOOP ramch14 MOV SI,OFFSET pagemsg ;display page test msg.. CALL strdsp @@ -3117,19 +3080,14 @@ ramch14: and al,0feh OUT I8042+1,AL MOV DI,OFFSET log_page - MOV DX,emsio - MOV AL,pageofs ;get EMS logical page start no. - xor ah,ah + XOR AX,AX MOV CX,PAGE_MAX - sub cx,ax - jng ramch16 - mov ah,al XOR BX,BX ramch9: PUSH CX - MOV AL,AH -; JJP OR AL,80h - OUT DX,AL + MOV DX,emsio + OUT DX,AX + MOV DX,AX CALL imgchk ; checks the page is RAM jc ramch17 test byte ptr sysflg,8 ;supress memory test @@ -3154,13 +3112,13 @@ ramch17: ADD DI,LOG_SIZE ramch8: POP CX - INC AH + INC AX LOOP ramch9 ramch16: MOV total_pages,BX MOV un_alloc_pages,BX - MOV AL,DIS_EMS - OUT DX,AL + MOV AX,DIS_EMS + OUT DX,AX IN AL,I8042+1 ;enable system memory parity.. AND AL,0FBH or AL,1 @@ -3185,14 +3143,13 @@ imgchk PROC NEAR PUSH AX CX SI DI DS PUSH CS ;set ES <- CS.. POP ES - test ah,3 + test dx,3 jnz imgchk2 IN AL,I8042+1 or AL,2 OUT I8042+1,AL imgchk2: - MOV AL,AH - CBW + MOV AX,DX MOV DI,OFFSET tstpage CALL dbinasc ;change binary -> ascii. MOV SI,OFFSET tstpage ;display message.. @@ -3309,7 +3266,20 @@ spagets5: spagets2: stc jmp spagets5 -spagetst endp +spagetst endp +;-------------------------------------------------------------------- +; Change data BYNARY -> ASCII (DEC) 5 digits +; input +; AX : binary data +; output +; ES:DI : ascii data (DEC) +;-------------------------------------------------------------------- +dbinasc5: + PUSH AX BX CX DX SI + MOV SI,DI + MOV CX,5 + MOV BX,10000 + JMP SHORT dbinas0 ;-------------------------------------------------------------------- ; Change data BYNARY -> ASCII (DEC) ; input @@ -3322,12 +3292,13 @@ dbinasc: MOV SI,DI MOV CX,4 MOV BX,1000 +dbinas0: XOR DX,DX dbinas1: DIV BX OR AL,AL JNZ dbinas2 - CMP CL,4 + CMP SI,DI JZ dbinas4 CMP BYTE PTR [SI],' ' JNZ dbinas2 @@ -3557,16 +3528,20 @@ info: ; EMM driver initial routine work data area ;-------------------------------------------------------------------- start_msg db CR,LF - DB 'LTEMM: Lo-tech EMM Driver for XTMax ' -msg_ver db 'r01' - DB CR,LF,'$' + DB 'XTEMM: EMM Driver for XTMax r02',CR,LF + db ' Based on Lo-tech EMM Driver for the Lo-tech 2MB EMS board.',CR,LF + db ' Based on modifications by Michael Karcher.',CR,LF + db ' Based on original works Copyright (c) 1988, Alex Tsourikov.',CR,LF + db ' All rights reserved.',CR,LF + db 'Using EMS ' +msg_ver db '4.0',CR,LF,'$' install_msg label byte page_msg DB 'Page frame specification: Frame Segment at ' segadr DB '0000',CR,LF total_pg DB '0000 pages found on EMS board at ' pioadr DB '0000',CR,LF db 'Installation completed - ' -totmem db '0000K RAM Available.',CR,LF,LF,'$' +totmem db '00000K RAM Available.',CR,LF,LF,'$' hard_w_err DB 'No EMS board found.',CR,LF,'$' nopage_err DB 'No EMS memory found.',CR,LF,'$' notinst DB 'Installation failed - No EMS available.',CR,LF,LF,'$' @@ -3575,25 +3550,24 @@ tstpage DB '0000',CR,'$' info_msg db CR,LF db 'Expanded Memory Manager for the XTMax expansion board.',CR,LF db CR,LF - db 'Based on Lo-tech EMM Driver for the Lo-tech 2MB EMS board..',CR,LF + db 'Based on Lo-tech EMM Driver for the Lo-tech 2MB EMS board.',CR,LF + db 'Based on modifications by Michael Karcher.',CR,LF db 'Based on original works Copyright (c) 1988, Alex Tsourikov.',CR,LF db 'All rights reserved.',CR,LF db CR,LF db 'http://www.lo-tech.co.uk/wiki/2MB-EMS-Board',CR,LF db 'Syntax: DEVICE=LTEMM.EXE [/switches]',CR,LF db CR,LF - db ' /p:nnnn - Page frame address(E000)',CR,LF + db ' /p:nnnn - Page frame address(D000)',CR,LF db ' /i:nnn - EMS i/o port base address(260)',CR,LF db ' /h:nnn - Maximal number of handles(64)',CR,LF db ' /d:nn - Depth of contest saves(5)',CR,LF -; db ' /f:nnn - First page number(0)',CR,LF db ' /n - Bypass memory test',CR,LF db ' /x - Perform long memory test',CR,LF db ' /3 - Use only EMS 3.2 functions',CR,LF db ' /q - Quiet mode',CR,LF db CR,LF db 'Defaults in parentheses.',CR,LF,'$' -pageofs DB 0 ;logical page no. offset data sysflg DB 0 ;system option flag chkchr DW 55AAH code ENDS diff --git a/XTMax/Drivers/LTEMM/LTEMM.EXE b/XTMax/Drivers/LTEMM/LTEMM.EXE deleted file mode 100644 index c8d56d4e604d2b7205e1078c0dbe96b2262b9d14..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9449 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 VwjFBVFTn+Cmc3K>Vc{o*{{t$^+baM7 diff --git a/XTMax/Drivers/SDPP/DISKIO.H b/XTMax/Drivers/SDPP/DISKIO.H index 0580725..11f822f 100644 --- a/XTMax/Drivers/SDPP/DISKIO.H +++ b/XTMax/Drivers/SDPP/DISKIO.H @@ -24,8 +24,6 @@ typedef enum { RES_PARERR /* 4: Invalid Parameter */ } DRESULT; -void setportbase(BYTE val); /* set the port base */ - /*---------------------------------------*/ /* Prototypes for disk control functions */ #define DOSFAR far diff --git a/XTMax/Drivers/SDPP/DRIVER.C b/XTMax/Drivers/SDPP/DRIVER.C index dddd357..8413779 100644 --- a/XTMax/Drivers/SDPP/DRIVER.C +++ b/XTMax/Drivers/SDPP/DRIVER.C @@ -1,6 +1,7 @@ /* driver.c - MSDOS device driver functions */ /* */ /* Copyright (C) 1994 by Robert Armstrong */ +/* Copyright (C) 2024 by Ted Fried, Matthieu Bucchianeri */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ @@ -55,9 +56,6 @@ BOOLEAN InitNeeded = TRUE; /* TRUE if we need to (re) initialize */ WORD RebootVector[2]; /* previous INT 19H vector contents */ extern DWORD partitionoffset; -extern BYTE sd_card_check; -extern BYTE portbase; - BYTE partition_number; /* fmemcpy */ @@ -369,8 +367,8 @@ PUBLIC void Initialize (rh_init_t far *rh) /* 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 USE286 - "80286+" +#ifdef USE186 + "80186+" #else "8086" #endif @@ -485,9 +483,6 @@ PRIVATE BOOLEAN parse_options (char far *p) switch (*p++) { case 'd', 'D': Debug = TRUE; - break; - case 'k', 'K': - sd_card_check = 1; break; case 'p', 'P': if ((p=option_value(p,&temp)) == NULL) return FALSE; @@ -495,13 +490,6 @@ PRIVATE BOOLEAN parse_options (char far *p) cdprintf("SD: Invalid partition number %x\n",temp); else partition_number = temp; - break; - case 'b', 'B': - if ((p=option_value(p,&temp)) == NULL) return FALSE; - if ((temp < 1) || (temp > 5)) - cdprintf("SD: Invalid port base index %x\n",temp); - else - portbase = temp; break; default: return FALSE; diff --git a/XTMax/Drivers/SDPP/MAKEFILE b/XTMax/Drivers/SDPP/MAKEFILE index 37ed1c3..cca5661 100644 --- a/XTMax/Drivers/SDPP/MAKEFILE +++ b/XTMax/Drivers/SDPP/MAKEFILE @@ -5,23 +5,23 @@ 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: sd.sys sd286.sys +all: xtsd.sys xtsd186.sys .asm.obj: $(ASM) $* -sd.sys: header.obj $(DEPS) +xtsd.sys: header.obj $(DEPS) $(CC) cprint.c $(CC) sd.c $(CC) sdmm.c $(CC) driver.c tlink -t -m -s -n header cprint sd sdmm driver, $@ -sd286.sys: header.obj $(DEPS) - $(CC) -1 -DUSE286 cprint.c - $(CC) -1 -DUSE286 sd.c - $(CC) -1 -DUSE286 sdmm.c - $(CC) -1 -DUSE286 driver.c +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: diff --git a/XTMax/Drivers/SDPP/README.TXT b/XTMax/Drivers/SDPP/README.TXT index c0dd791..c2ad4ef 100644 --- a/XTMax/Drivers/SDPP/README.TXT +++ b/XTMax/Drivers/SDPP/README.TXT @@ -1,72 +1,23 @@ +SD card driver for XTMax -SD card driver for parallel port +This driver is based on SDPP cloned from https://github.com/nilseuropa/sdpp. -I wrote this to simplify data transfer between my IBM PC and my laptop, because my laptop does -not have a 360k floppy drive but does have an SD card slot. - -WARNING: I take **no responsibility** for any damage to your computer, parallel port, or SD -card, or any data. You use this driver at your own risk. It is highly recommended you use -an expendable parallel port card with your expendable SD card, and your expendable data. -It is recommended that you use a level converter IC with between your 5 volt parallel port -outputs and the SD card 3.3 volt inputs. This project is intended as a fun hack for hobbyists -and enthusiasts and not for serious work. - -This driver is made available under the GNU General Public License version 2. It incorporates +The original driver is made available under the GNU General Public License version 2. It incorporates modified code from ELM Chan Fat FS (http://elm-chan.org/fsw/ff/00index_e.html). Usage: In your config.sys file -DEVICE=SD.SYS /d /k /p= /b= +DEVICE=SD.SYS /d /p= Loads and installs the SD card driver. /d = debugging mode (displays copious debugging messsages) -/k = use card detect signal to inform dos that card is attached /p = partition number (1-4) to partition in MBR to use. Default: first available. -/b = port base index of parallel port, one of - 1=0x3BC, 2=0x378, 3=0x278, 4=0x3E8, 5=0x2E8 - Default: 0x378 For best results, format your SD card with a FAT16 partition which is less than 32 MB in size. NOTE: Many versions of DOS don't know how to handle FAT32, and many can't have FAT16 with a partition size greater than 32 MB. Therefore, if you want to play with this, make your parition on the card FAT16 and less than 32 MB. This assures the best compatibility. You can have multiple copies of the driver loaded if there are multiple partitions on your SD card you want to use simultaneously. - -I have used Adafruit's microSD adapter - (http://www.adafruit.com/products/254?gclid=CLH7l4iEkrwCFQPNOgod7BkAQA) -if you want a relatively simple way to interface your PC parallel port to -the SD card. The adapter provides the 3.3 volts needed to power the SD card, as well -as a the level shifting between the 5 volt parallel port output and the 3.3 volt input. -If you directly connect a 5 volt output to a 3.3 volt input, you risk latching up the -3.3 volt input and damaging the card or computer from exceesive current. -Some have used series resistors instead of the level converters, but I found this -to not be that reliable and still may have this problem. Also, some SD cards MISO/DO -outputs are unable to drive a TTL input of some parallel ports, so you may need to add -a buffer between the two as well. I have found quite a bit of variability in the drive -current required for the inputs of various parallel ports. - -The driver uses the very slow serial peripheral interface (SPI) mode of the SD card. The -speed, which depends on your PC speed, could be as slow as 10 kilobytes/second. This is -not a replacement for your hard drive. Your parallel port should be configured for standard -mode (not bidirectional) if applicable. - -The connections between the parallel port and the SD card are as follows: - -Parallel port SD card - -PIN 25 signal GND GND (Vss) -+3.3V Vdd (power) -PIN 2 signal D0 CMD / MOSI / DI (SPI data in) -PIN 3 signal D1 SCLK / CLK (SPI clock) -PIN 4 signal D2 DAT3 / CS (SPI chip select) -PIN 13 signal SELECT DAT0 / MISO / DO (SPI data out) -PIN 11 signal BUSY Card detect (if you SD card slot has one) - -For similar setups, look up parallel port to JTAG adapters which are used for in circuit -programming and debugging. - -Good luck and be careful! - diff --git a/XTMax/Drivers/SDPP/SDMM.C b/XTMax/Drivers/SDPP/SDMM.C index c0d286c..a9408b3 100644 --- a/XTMax/Drivers/SDPP/SDMM.C +++ b/XTMax/Drivers/SDPP/SDMM.C @@ -3,6 +3,7 @@ /-------------------------------------------------------------------------/ / / Copyright (C) 2013, ChaN, all right reserved. +/ Copyright (C) 2024, Ted Fried, Matthieu Bucchianeri / / * This software is a free software and there is NO WARRANTY. / * No restriction on use. You can use, modify and redistribute it for @@ -26,15 +27,8 @@ /* Platform dependent macros and functions needed to be modified */ /*-------------------------------------------------------------------------*/ -static WORD portbases[5] = {0x3BC,0x378,0x278,0x3E8,0x2E8}; - -BYTE sd_card_check = 0; -BYTE portbase = 2; - -WORD DATAPORT=0x378; -WORD CONTROLPORT=0x379; - -#define VAR_INIT() {CONTROLPORT=DATAPORT+1;} +WORD DATAPORT=0x280; +WORD CONTROLPORT=0x282; #if 1 #define TOUTCHR(x) @@ -71,13 +65,6 @@ static BYTE toutword(WORD x) #endif -void setportbase(BYTE val) -{ - if ((val >= 1) && (val <= (sizeof(portbases)/sizeof(portbases[0])) )) - DATAPORT = portbases[val-1]; - VAR_INIT(); -} - static void dly_us (UINT n) { @@ -187,7 +174,10 @@ void xmit_mmc ( UINT bc /* Number of bytes to send */ ) { -#ifndef USE286 + // NOTE: Callers always use buffer sizes multiple of two. + bc >>= 1; + +#ifndef USE186 _asm { mov cx,bc mov dx,DATAPORT @@ -196,8 +186,8 @@ void xmit_mmc ( } repeat: _asm { - lodsb - out dx, al + lodsw + out dx, ax loop repeat pop ds } @@ -207,7 +197,7 @@ void xmit_mmc ( mov dx,DATAPORT push ds lds si,dword ptr buff - rep outsb + rep outsw pop ds } #endif @@ -225,7 +215,10 @@ void rcvr_mmc ( UINT bc /* Number of bytes to receive */ ) { -#ifndef USE286 + // NOTE: Callers always use buffer sizes multiple of two. + bc >>= 1; + +#ifndef USE186 _asm { mov cx,bc mov dx,DATAPORT @@ -234,8 +227,8 @@ void rcvr_mmc ( } repeat: _asm { - in al, dx - stosb + in ax, dx + stosw loop repeat pop es } @@ -245,7 +238,7 @@ void rcvr_mmc ( mov dx,DATAPORT push es les di,dword ptr buff - rep insb + rep insw pop es } #endif @@ -350,7 +343,7 @@ int xmit_datablock ( /* 1:OK, 0:Failed */ if (!wait_ready()) return 0; d = token; - xmit_mmc(&d, 1); /* Xmit a token */ + outp(DATAPORT, d); /* Xmit a token */ if (token != 0xFD) { /* Is it data token? */ xmit_mmc(buff, 512); /* Xmit the 512 byte data block to MMC */ (void)inp(DATAPORT); (void)inp(DATAPORT); /* Xmit dummy CRC (0xFF,0xFF) */ @@ -448,11 +441,6 @@ DSTATUS disk_status ( ) { if (drv) return STA_NOINIT; - if ((sd_card_check) && (inp(CONTROLPORT) & 0x80)) - { - Stat = STA_NOINIT; - return STA_NOINIT; - } return Stat; } @@ -461,11 +449,6 @@ DRESULT disk_result ( ) { if (drv) return RES_NOTRDY; - if ((sd_card_check) && (inp(CONTROLPORT) & 0x80)) - { - Stat = STA_NOINIT; - return RES_NOTRDY; - } return RES_OK; } @@ -482,11 +465,7 @@ DSTATUS disk_initialize ( UINT tmr; DSTATUS s; - setportbase(portbase); - if (drv) return RES_NOTRDY; - if ((sd_card_check) && (inp(CONTROLPORT) & 0x80)) - return RES_NOTRDY; ty = 0; for (n = 5; n; n--) { diff --git a/XTMax/Drivers/XTEMM.EXE b/XTMax/Drivers/XTEMM.EXE new file mode 100644 index 0000000000000000000000000000000000000000..2ed2c45a873d03702d99f4762448361e2b5d9d3c GIT binary patch literal 16837 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 SJ%5s*dO{c-)Cb`^)c*kKR%>(s literal 0 HcmV?d00001