diff -Naur spediv_beta_p1/divide.c spediv_v0.1/divide.c --- spediv_beta_p1/divide.c 2005-06-20 00:09:13.000000000 +0200 +++ spediv_v0.1/divide.c 2005-06-25 21:57:21.000000000 +0200 @@ -39,6 +39,46 @@ #include "interf.h" #define DISK divide_drive[drive] +#define DISK2 divide_drive[drive^1] + +#define STATUS_SET_ERR 0x01 // error +#define STATUS_SET_DRQ 0x08 // data request +#define STATUS_SET_DSC 0x10 // data seek complete +#define STATUS_SET_DF 0x20 // device fault +#define STATUS_SET_DRDY 0x40 // drive ready +#define STATUS_SET_BSY 0x80 // busy + +#define STATUS_CLR_ERR 0xFE +#define STATUS_CLR_DRQ 0xF7 +#define STATUS_CLR_DSC 0xEF +#define STATUS_CLR_DF 0xDF +#define STATUS_CLR_DRDY 0xBF +#define STATUS_CLR_BSY 0x7F + +#define ERROR_SET_MED 0x01 // media error +#define ERROR_SET_NM 0x02 // no media +#define ERROR_SET_ABRT 0x04 // abort +#define ERROR_SET_MCR 0x08 // media change request +#define ERROR_SET_IDNF 0x10 // ID not founf +#define ERROR_SET_MC 0x20 // media changed +#define ERROR_SET_WP 0x40 // write protect +#define ERROR_SET_UNC 0x40 // uncorrectable data +#define ERROR_SET_ICRC 0x80 // interface crc error + +#define ERROR_CLR_MED 0xFE +#define ERROR_CLR_NM 0xFD +#define ERROR_CLR_ABRT 0xFB +#define ERROR_CLR_MCR 0xF7 +#define ERROR_CLR_IDNF 0xEF +#define ERROR_CLR_MC 0xDF +#define ERROR_CLR_WP 0xBF +#define ERROR_CLR_UNC 0xBF +#define ERROR_CLR_ICRC 0x7F + + +// DEMFIR image will be used if this variable is NULL +char *divide_image_path=NULL; +int divide_image_changed=0; // DEMFIR operating system for divide (http://demfir.sourceforge.net) extern unsigned char demfir_imag[]; @@ -62,22 +102,6 @@ // if should be done automapping int divide_automap=0; -// IDE registers (Read/Write) -int divide_port_AF; // chs/lba -int divide_port_B3; // chs/lba -int divide_port_B7; // chs/lba -int divide_port_BB; // chs/lba -int divide_port_A3; // data -int divide_port_AB; // sector cnt - -// IDE registers (Write) -int divide_out_port_A7; // features -int divide_out_port_BF; // command - -// IDE registers (Read) -int divide_in_port_A7; // error -int divide_in_port_BF; // status - #define DIVIDE_MAX_SEC_NR 96 // 96*512 = 48K .. in 48K mode spectrum this should be enough // active drive (0='A:', 1='B:') @@ -85,7 +109,7 @@ struct divide_drive_struct { char *path; // image path - int c,h,s; // C/H/S geometry of disk (not used yet) + int c,h,s; // C/H/S geometry of disk int len; // size of image (readed from identify file) int ptr; // head ptr (not used) @@ -107,6 +131,22 @@ int cmd; // pending command (read sector/write sector) +// IDE registers (Read/Write) + int port_AF; // chs/lba + int port_B3; // chs/lba + int port_B7; // chs/lba + int port_BB; // chs/lba + int port_A3; // data + int port_AB; // sector cnt + +// IDE registers (Write) + int out_port_A7; // features + int out_port_BF; // command + +// IDE registers (Read) + int in_port_A7; // error + int in_port_BF; // status + }; struct divide_drive_struct divide_drive[2]; @@ -125,9 +165,37 @@ return (s+DISK.s*(h+c*DISK.h)-1); } +void divide_eeprom_save() { + int i,fd; + + if (!divide_image_path || !divide_image_changed) return; + if ((fd=open(divide_image_path, O_WRONLY))!=-1) { + i=write(fd, divide_eeprom, 0x2000); + close(fd); + if (i!=0x2000) { + printf("WARNING!!! EEPROM image is propably corrupted :( I cannot write 8KB.\n"); + } + } else printf("No such file.\n"); + divide_image_changed=0; +} + +void divide_eeprom_load() { + int i,fd; + + if (!divide_image_path) return; + if ((fd=open(divide_image_path, O_RDONLY))!=-1) { + i=read(fd, divide_eeprom, 0x2000); + close(fd); + if (i!=0x2000) { + printf("WARNING!!! EEPROM image is propably corrupted, check it first.\n"); + exit(0); + } + } else printf("No such file.\n"); + divide_image_changed=0; +} // initialize variables void divide_init() { - int i,j; + int i,j,drive; // make copy of original spectrum memory (to recover it after unmaping divide memory) memcpy(orig_rom, PRNM(proc).mem, 16384); @@ -135,29 +203,47 @@ // load EEPROM memory and clear RAM memory for(i = 0; i < 0x2000; i++) divide_eeprom[i] = demfir_imag[i]; + if (divide_image_path==NULL) + printf("No EEPROM image defined. Using default DEMFIR image.\n"); + else { + printf("Using file %s to load EEPROM image.\n", divide_image_path); + divide_eeprom_load(); + } + for(i = 0; i < 0x2000; i++) for (j=0;j<4;j++) divide_ram[j][i] = 0; // set default values - divide_port_A3=0; - divide_port_AB=0; - divide_port_AF=0; - divide_port_B3=0; - divide_port_B7=0; - divide_port_BB=0; - - divide_out_port_A7=0; - divide_out_port_BF=0; - - divide_in_port_A7=0; - divide_in_port_BF=0; - divide_drive[0].path=NULL; - divide_drive[0].mbr_fd=-1; - divide_drive[0].partition_fd=-1; - divide_drive[1].path=NULL; - divide_drive[1].mbr_fd=-1; - divide_drive[1].partition_fd=-1; + + for (drive=0; drive<2; drive++) { + DISK.port_A3=0; + DISK.port_AB=0; + DISK.port_AF=0; + DISK.port_B3=0; + DISK.port_B7=0; + DISK.port_BB=0; + + DISK.out_port_A7=0; + DISK.out_port_BF=0; + + DISK.in_port_A7=0; + DISK.in_port_BF=0; + DISK.path=NULL; + DISK.mbr_fd=-1; + DISK.partition_fd=-1; + } +} + +void divide_exit() { + divide_detach_drive(1); + divide_detach_drive(0); + + if (divide_image_path!=NULL) { + printf("Using file %s to save EEPROM image.\n", divide_image_path); + divide_eeprom_save(); + } +// else printf("No EEPROM image defined.\n"); } // divide images are directories in fact @@ -237,8 +323,14 @@ free(DISK.path); DISK.path=NULL; } - if (DISK.mbr_fd!=-1) close(DISK.mbr_fd); - if (DISK.partition_fd!=-1) close(DISK.partition_fd); + if (DISK.mbr_fd!=-1) { + close(DISK.mbr_fd); + DISK.mbr_fd=-1; + } + if (DISK.partition_fd!=-1) { + close(DISK.partition_fd); + DISK.partition_fd=-1; + } if (!drive) put_msg("Image successfully detached from drive 'A:'."); else @@ -276,13 +368,10 @@ // readed whole buffer? if (DISK.buffer_ptr >= DISK.buffer_len) - divide_in_port_BF = 0x40; - else - divide_in_port_BF = 0x08; + DISK.in_port_BF &= STATUS_CLR_DRQ; + return data; } else { - divide_in_port_A7 = 0x04; - divide_in_port_BF = 0x01; DISK.buffer_ptr = 0; DISK.buffer_len = 0; DISK.cmd = 0; @@ -291,31 +380,25 @@ return 0; break; case 0xA7: // error register - data = divide_in_port_A7; - divide_in_port_A7 = 0; - return data; + return DISK.in_port_A7; break; case 0xAB: // sector count register - data = divide_port_AB; - divide_port_AB = 0; - return data; + return DISK.port_AB; break; case 0xBF: // status register - data = divide_in_port_BF; - divide_in_port_BF = 0; - return data; + return DISK.in_port_BF; break; case 0xBB: // drive/head register - return divide_port_BB; + return DISK.port_BB; break; case 0xB7: // cylinder register high - return divide_port_B7; + return DISK.port_B7; break; case 0xB3: // cylinder register low - return divide_port_B3; + return DISK.port_B3; break; case 0xAF: // sector number register - return divide_port_AF; + return DISK.port_AF; break; default: // unknown divide port? // printf(" unknown port #%02X\n", portl); @@ -329,11 +412,11 @@ int i,drive; int lba; long size; - + drive = divide_active_drive; switch (portl) { case 0xE3: // divide_control_register - // this port contains CONMEM, MAPRAM, x, x, x, x, RAM_BANK (2 bytes) + // this port contains CONMEM, MAPRAM, x, x, x, x, RAM_BANK (2 bits) divide_conmem = (data >> 7) & 1; // MAPRAM cannot be cleared (1->0) if ((data & 64)) { @@ -344,70 +427,93 @@ break; case 0xBB: // drive/head register divide_active_drive = ((data >> 4) & 1); - divide_port_BB = data; + drive = divide_active_drive; + DISK.port_BB = data; + DISK2.port_BB = data; break; case 0xB7: // cylinder register high - divide_port_B7 = data; + DISK.port_B7 = data; + DISK2.port_B7 = data; break; case 0xB3: // cylinder register low - divide_port_B3 = data; + DISK.port_B3 = data; + DISK2.port_B3 = data; break; case 0xAF: // sector number register - divide_port_AF = data; + DISK.port_AF = data; + DISK2.port_AF = data; break; case 0xAB: // sector count register - divide_port_AB = data; + DISK.port_AB = data; + DISK2.port_AB = data; break; case 0xBF: // command register switch (data) { - // silently ignore these commands case 0x00: // nop + DISK.in_port_A7 |= ERROR_SET_ABRT; + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ); + DISK.in_port_BF |= (STATUS_SET_DRDY | STATUS_SET_ERR); + break; + // silently return success result for these commands case 0x40: // read verify sectors with rerty case 0x41: // read verify sectors without rerty - case 0x94: // standby immediate - case 0x95: // idle immediate - case 0x96: // standby - case 0x97: // idle - case 0x98: // check power mode - case 0x99: // set sleep mode + case 0xE0: // standby immediate + case 0xE1: // idle immediate + case 0xE2: // standby + case 0xE3: // idle + case 0xE5: // check power mode + case 0xE6: // set sleep mode case 0xE7: // flush cache + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ & STATUS_CLR_ERR); + DISK.in_port_BF |= (STATUS_SET_DRDY); break; case 0x91: // initialise drive parameters if ((DISK.mbr_fd == -1) || (DISK.partition_fd == -1)) { - // error? - divide_in_port_BF &= 56; - divide_in_port_BF |= 21; + // error + DISK.in_port_A7 |= ERROR_SET_ABRT; + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DRQ); + DISK.in_port_BF |= (STATUS_SET_DF | STATUS_SET_ERR); break; } // recalculate new geometry to fit CHS configuration - size = DISK.h * DISK.s * DISK.c; - DISK.h = (divide_port_BB&15)+1; - DISK.s = divide_port_AB; - DISK.c = size / (DISK.h * DISK.s); + size = DISK.identify[112] + (DISK.identify[113] << 16); + if (size>16514064) size=16,514,064; + + DISK.h = (DISK.port_BB&15)+1; + DISK.s = DISK.port_AB; + if ( (DISK.h * DISK.s) == 0 ) + DISK.c = size / (DISK.h * DISK.s); + else + DISK.c = 0; + if (DISK.c>65535) DISK.c=65535; + DISK.identify[108] = DISK.c & 0xFF; DISK.identify[109] = DISK.c >> 8; + DISK.identify[110] = DISK.h & 0xFF; DISK.identify[111] = DISK.h >> 8; + DISK.identify[112] = DISK.s & 0xFF; DISK.identify[113] = DISK.s >> 8; - divide_in_port_BF &= 0x56; + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ & STATUS_CLR_ERR); break; case 0xA1: // identify drive (ATAPI) case 0xEC: // identify drive (ATA) if ((DISK.mbr_fd == -1) || (DISK.partition_fd == -1)) { - divide_in_port_BF &= 56; - divide_in_port_BF |= 21; + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DRDY & STATUS_CLR_DRQ); + DISK.in_port_BF |= (STATUS_SET_DF | STATUS_SET_ERR); break; } memcpy(DISK.buffer, DISK.identify, 512); DISK.buffer_ptr = 0; DISK.buffer_len = 512; - divide_in_port_BF &= 0x16; - divide_in_port_BF |= 0x48; DISK.cmd=DIVIDE_READ_BUFF; + + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_ERR); + DISK.in_port_BF |= (STATUS_SET_DRDY | STATUS_SET_DRQ); break; case 0x20: // read sectors with retry @@ -418,23 +524,25 @@ case 0xC8: // read DMA with retry case 0xC9: // read DMA without retry - if ((DISK.mbr_fd == -1) || (DISK.partition_fd == -1) || (divide_port_AB>DIVIDE_MAX_SEC_NR)) { - divide_in_port_BF&=56; - divide_in_port_BF|=21; + if ((DISK.mbr_fd == -1) || (DISK.partition_fd == -1) || (DISK.port_AB>DIVIDE_MAX_SEC_NR)) { + DISK.in_port_A7 &= (ERROR_CLR_MC & ERROR_CLR_MCR); + DISK.in_port_A7 |= (ERROR_SET_UNC | ERROR_SET_IDNF | ERROR_SET_ABRT | ERROR_SET_NM); + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ); + DISK.in_port_BF |= (STATUS_SET_DRDY | STATUS_SET_ERR); break; } // LBA or CHS? - if (divide_port_BB & 0x40) - lba = ((divide_port_BB & 0x0F) << 24) | (divide_port_B7 << 16) | (divide_port_B3 << 8) | divide_port_AF; + if (DISK.port_BB & 0x40) + lba = ((DISK.port_BB & 0x0F) << 24) | (DISK.port_B7 << 16) | (DISK.port_B3 << 8) | DISK.port_AF; else - lba=chs2lba(drive, (divide_port_B7 << 8) | divide_port_B3, divide_port_BB & 0x0F, divide_port_AF); + lba=chs2lba(drive, (DISK.port_B7 << 8) | DISK.port_B3, DISK.port_BB & 0x0F, DISK.port_AF); DISK.buffer_ptr = 0; DISK.buffer_len = 0; // send port_AB sectors - for (i=0; iDIVIDE_MAX_SEC_NR)) { + DISK.in_port_A7 &= (ERROR_CLR_WP & ERROR_CLR_MC & ERROR_CLR_MCR); + DISK.in_port_A7 |= (ERROR_SET_IDNF | ERROR_SET_ABRT | ERROR_SET_NM); + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_DRQ); + DISK.in_port_BF |= (STATUS_SET_DRDY | STATUS_SET_ERR); + break; + } DISK.buffer_ptr = 0; DISK.buffer_len = 0; DISK.cmd = DIVIDE_WRITE_BUFF; - divide_in_port_BF &= 0x16; - divide_in_port_BF |= 0x48; + DISK.in_port_BF &= (STATUS_CLR_BSY & STATUS_CLR_DF & STATUS_CLR_ERR); + DISK.in_port_BF |= (STATUS_SET_DRDY | STATUS_SET_DRQ); break; default: // printf(" unknown command #%02X\n", data); @@ -467,23 +582,23 @@ } break; case 0xA3: // data register - if (DISK.mbr_fd==-1 || DISK.partition_fd==-1 || divide_port_AB>DIVIDE_MAX_SEC_NR) { + if (DISK.mbr_fd==-1 || DISK.partition_fd==-1 || DISK.port_AB>DIVIDE_MAX_SEC_NR) { break; } if (DISK.cmd!=DIVIDE_WRITE_BUFF) break; // store a byte into buffer - memcpy(DISK.buffer + DISK.buffer_len, &data, 1); + *(DISK.buffer + DISK.buffer_len)=data; DISK.buffer_len++; // if is stored whole sector write it to disk if (DISK.buffer_len == 512) { // LBA or CHS? - if (divide_port_BB & 0x40) - lba = ((divide_port_BB & 0x0F) << 24) | (divide_port_B7 << 16) | (divide_port_B3 << 8) | divide_port_AF; + if (DISK.port_BB & 0x40) + lba = ((DISK.port_BB & 0x0F) << 24) | (DISK.port_B7 << 16) | (DISK.port_B3 << 8) | DISK.port_AF; else - lba = chs2lba(drive, (divide_port_B7 << 8) | divide_port_B3, divide_port_BB & 0x0F, divide_port_AF); + lba = chs2lba(drive, (DISK.port_B7 << 8) | DISK.port_B3, DISK.port_BB & 0x0F, DISK.port_AF); // write sector to disk if (lba < DISK.mbr_len) { @@ -494,13 +609,13 @@ write(DISK.partition_fd, DISK.buffer + DISK.buffer_ptr, 512); } DISK.buffer_ptr += 512; - divide_port_AB--; + DISK.port_AB--; lba++; } // we are done with writing? - if (!divide_port_AB) { + if (!DISK.port_AB) { DISK.cmd=0; - divide_in_port_BF=0x04; + DISK.in_port_BF &= STATUS_CLR_DRQ; } break; default: @@ -601,6 +716,7 @@ *ptr=val; // we have to make this change in divide memory too (not really mapped, only copied) divide_eeprom[addr]=val; + divide_image_changed=1; break; } *ptr=val; diff -Naur spediv_beta_p1/divide.h spediv_v0.1/divide.h --- spediv_beta_p1/divide.h 2005-06-17 11:55:33.000000000 +0200 +++ spediv_v0.1/divide.h 2005-06-21 00:38:18.000000000 +0200 @@ -22,6 +22,7 @@ #define DIVIDE_H void divide_init(); +void divide_exit(); void divide_attach_drive(int drive, char *path); void divide_detach_drive(int drive); diff -Naur spediv_beta_p1/spconf.c spediv_v0.1/spconf.c --- spediv_beta_p1/spconf.c 2005-06-16 16:14:34.000000000 +0200 +++ spediv_v0.1/spconf.c 2005-06-25 21:41:42.000000000 +0200 @@ -18,6 +18,12 @@ * */ +/* + * modifications by dusky@hq.alert.sk see README and README.divIDE + * original SPECTEMU readme was moved to README.SPECTEMU + * + */ + #include "spconf_p.h" #include "spver.h" #include "misc.h" @@ -38,6 +44,10 @@ extern const char *spcf_keynames_ascii[]; extern const char *spcf_keynames_misc[]; +#ifdef HAVE_DIVIDE +extern char *divide_image_path; +#endif + char *spcf_init_snapshot = NULL; int spcf_init_snapshot_type; char *spcf_init_tapefile = NULL; @@ -176,6 +186,9 @@ {"autoStop", SA_BOOL, &spt_auto_stop, NULL, 1 }, {"loadImmed", SA_BOOL, &load_immed, NULL, 1 }, {"pause", SA_BOOL, &sp_paused, NULL, 1 }, +#ifdef HAVE_DIVIDE + {"divideImage", SA_STR, ÷_image_path, NULL, 1 }, +#endif {NULL, 0, NULL, NULL, 0 } }; diff -Naur spediv_beta_p1/spkey.c spediv_v0.1/spkey.c --- spediv_beta_p1/spkey.c 2005-06-16 20:15:33.000000000 +0200 +++ spediv_v0.1/spkey.c 2005-06-25 21:40:57.000000000 +0200 @@ -770,9 +770,11 @@ " Ctrl-o F6 Pause/unpause tape \n" " Ctrl-s F7 Stop tape \n" " Ctrl-i F8 Generate NMI \n" +#ifdef HAVE_DIVIDE " Ctrl-a F11 Select drive A [divIDE] \n" " Ctrl-z F12 Select drive B [divIDE] \n" " Ctrl-g Switch ON/OFF JP2 jumper [divIDE] \n" +#endif " Ctrl-f Fast \n" " Ctrl-n Normal speed \n" " Ctrl-b Pause/Unpause emulator \n" @@ -863,8 +865,7 @@ case 'c': case SK_F10: #ifdef HAVE_DIVIDE - divide_detach_drive(1); - divide_detach_drive(0); + divide_exit(); #endif exit(0); case 'p':