diff --git a/src/Makefile.local b/src/Makefile.local index d34961a..a082c33 100644 --- a/src/Makefile.local +++ b/src/Makefile.local @@ -10,7 +10,7 @@ # settings, so we can avoid changing the main one for all of # our local setups. # -# Version: @(#)Makefile.local 1.0.2 2018/02/22 +# Version: @(#)Makefile.local 1.0.3 2018/03/21 # # Author: Fred N. van Kempen, # @@ -70,6 +70,8 @@ STUFF := # -DENABLE_KEYBOARD_LOG=N sets logging level at N. # -DENABLE_PCI_LOG=N sets logging level at N. # -DENABLE_CDROM_LOG=N sets logging level at N. +# -DENABLE_CDROM_IMAGE_LOG=N sets logging level at N. +# -DENABLE_CDROM_IOCTL_LOG=N sets logging level at N. # -DENABLE_HDD_LOG=N sets logging level at N. # -DENABLE_IDE_LOG=N sets logging level at N. # -DENABLE_FDC_LOG=N sets logging level at N. diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index 7f3572b..27138b1 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)cdrom.c 1.0.9 2018/03/20 + * Version: @(#)cdrom.c 1.0.10 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -37,6 +37,7 @@ * Boston, MA 02111-1307 * USA. */ +#include #include #include #include @@ -811,6 +812,7 @@ uint32_t cdrom_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, void cdrom_update_request_length(uint8_t id, int len, int block_len) { cdrom_t *dev = cdrom[id]; + uint32_t min_len = 0; int bt; dev->max_transfer_len = dev->request_length; @@ -822,11 +824,24 @@ void cdrom_update_request_length(uint8_t id, int len, int block_len) case 0xa8: case 0xb9: case 0xbe: - if (dev->max_transfer_len < block_len) - dev->max_transfer_len = block_len; + /* Make sure total length is not bigger than sum + * of the lengths of all the requested blocks. */ bt = (dev->requested_blocks * block_len); if (len > bt) len = bt; + + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; + } + } + default: dev->packet_len = len; break; @@ -837,8 +852,10 @@ void cdrom_update_request_length(uint8_t id, int len, int block_len) /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ if (!dev->max_transfer_len) dev->max_transfer_len = 65534; - if (len <= dev->max_transfer_len) - dev->max_transfer_len = len; + + if ((len <= dev->max_transfer_len) && (len >= min_len)) { + dev->request_length = dev->max_transfer_len = len; + } } @@ -859,8 +876,8 @@ static double cdrom_seek_time(uint8_t id) diff -= MIN_SEEK; - return cdrom_speeds[cdrom_drives[id].speed_idx].seek1 + - ((cdrom_speeds[cdrom_drives[id].speed_idx].seek2 * ((double) diff)) / sd); + return cdrom_speeds[dev->cur_speed].seek1 + + ((cdrom_speeds[dev->cur_speed].seek2 * ((double) diff)) / sd); } static double cdrom_bus_speed(uint8_t id) @@ -879,6 +896,17 @@ static double cdrom_bus_speed(uint8_t id) return 3333333.333333333333333; /* 3.3 MB/s PIO-0 speed */ } +static void cdrom_command_bus(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 1LL * CDROM_TIME; + cdrom_set_callback(id); +} + static void cdrom_command_common(uint8_t id) { cdrom_t *dev = cdrom[id]; @@ -889,6 +917,9 @@ static void cdrom_command_common(uint8_t id) dev->phase = 1; dev->pos = 0; dev->callback = 0LL; + + cdrom_log("CD-ROM %i: Current speed: %ix\n", id, dev->cur_speed); + if (dev->packet_status == CDROM_PHASE_COMPLETE) { cdrom_phase_callback(id); dev->callback = 0LL; @@ -901,6 +932,7 @@ static void cdrom_command_common(uint8_t id) period = cdrom_seek_time(id) * ((double) TIMER_USEC); dev->callback += ((int64_t) period); cdrom_set_callback(id); + cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", id, (int64_t)cdrom_seek_time(id)); return; case 0x08: case 0x28: @@ -908,6 +940,7 @@ static void cdrom_command_common(uint8_t id) /* Seek time is in us. */ period = cdrom_seek_time(id) * ((double) TIMER_USEC); dev->callback += ((int64_t) period); + cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", id, (int64_t)cdrom_seek_time(id)); case 0x25: case 0x42: case 0x43: @@ -918,7 +951,7 @@ static void cdrom_command_common(uint8_t id) case 0xb8: case 0xb9: case 0xbe: - bytes_per_second = (1000000.0 / 12000.0) * 2048.0; /* Account for seek time. */ + bytes_per_second = 176.0 * 1024.0; bytes_per_second *= (double)cdrom_speeds[dev->cur_speed].speed; break; default: @@ -931,8 +964,10 @@ static void cdrom_command_common(uint8_t id) } period = 1000000.0 / bytes_per_second; - dusec = (double) TIMER_USEC; - dusec = dusec * period * (double) (dev->packet_len); + cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", id, (int64_t)period); + period = period * (double) (dev->packet_len); + cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", id, (int64_t)period); + dusec = period * ((double) TIMER_USEC); dev->callback += ((int64_t) dusec); } cdrom_set_callback(id); @@ -2459,7 +2494,7 @@ cdrom_readtoc_fallback: max_len |= cdb[8]; msf = (cdb[1] >> 1) & 1; - cdrom_buf_alloc(id, 65536); + cdrom_buf_alloc(id, 32); cdrom_log("CD-ROM %i: Getting page %i (%s)\n", id, cdb[3], msf ? "MSF" : "LBA"); if ((cdrom_drives[id].handler->pass_through) && (cdb[3] != 1)) { @@ -2549,6 +2584,13 @@ cdrom_readtoc_fallback: len = MIN(len, max_len); cdrom_set_buf_len(id, BufLen, &len); + cdrom_log("CD-ROM %i: Read subchannel:", id); + for (i = 0; i < 32; i += 8) { + cdrom_log("[%02X] %02X %02X %02X %02X %02X %02X %02X %02X\n", i, + cdbufferb[i], cdbufferb[i + 1], cdbufferb[i + 2], cdbufferb[i + 3], + cdbufferb[i + 4], cdbufferb[i + 5], cdbufferb[i + 6], cdbufferb[i + 7]); + } + cdrom_data_command_finish(id, len, len, len, 0); break; @@ -3009,19 +3051,10 @@ int cdrom_read_from_dma(uint8_t id) ret = cdrom_phase_data_out(id); - if (ret || (cdrom_drives[id].bus_type == CDROM_BUS_SCSI)) { - cdrom_buf_free(id); - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->status = READY_STAT; - dev->phase = 3; - ui_sb_update_icon(SB_CDROM | id, 0); - cdrom_irq_raise(id); - if (ret) - return 1; - else - return 0; - } else - return 0; + if (ret) + return 1; + + return 0; } int cdrom_write_to_ide_dma(uint8_t channel) @@ -3063,6 +3096,7 @@ int cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) int cdrom_write_to_dma(uint8_t id) { cdrom_t *dev = cdrom[id]; + int32_t *BufLen = &SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].BufferLength; int ret = 0; if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) { @@ -3071,25 +3105,22 @@ int cdrom_write_to_dma(uint8_t id) } else ret = cdrom_write_to_ide_dma(cdrom_drives[id].ide_channel); - if (ret || (cdrom_drives[id].bus_type == CDROM_BUS_SCSI)) { - cdrom_buf_free(id); - dev->packet_status = CDROM_PHASE_COMPLETE; - dev->status = READY_STAT; - dev->phase = 3; - ui_sb_update_icon(SB_CDROM | id, 0); - cdrom_irq_raise(id); - if (ret) - return 1; - else - return 0; - } else - return 0; + if (cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + cdrom_log("CD-ROM %i: SCSI Output data length: %i\n", id, *BufLen); + else + cdrom_log("CD-ROM %i: ATAPI Output data length: %i\n", id, dev->packet_len); + + if (ret) + return 1; + + return 0; } /* If the result is 1, issue an IRQ, otherwise not. */ void cdrom_phase_callback(uint8_t id) { cdrom_t *dev = cdrom[id]; + int ret; switch(dev->packet_status) { case CDROM_PHASE_IDLE: @@ -3130,7 +3161,16 @@ void cdrom_phase_callback(uint8_t id) return; case CDROM_PHASE_DATA_IN_DMA: cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", id); - cdrom_write_to_dma(id); + ret = cdrom_write_to_dma(id); + + if (ret || (cdrom_drives[id].bus_type == CDROM_BUS_SCSI)) { + cdrom_log("CD-ROM %i: DMA data in phase done\n"); + cdrom_buf_free(id); + cdrom_command_complete(id); + } else { + cdrom_log("CD-ROM %i: DMA data in phase failure\n"); + cdrom_command_bus(id); + } return; case CDROM_PHASE_ERROR: cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", id); diff --git a/src/cdrom/cdrom_dosbox.cpp b/src/cdrom/cdrom_dosbox.cpp index e1a15e3..467741a 100644 --- a/src/cdrom/cdrom_dosbox.cpp +++ b/src/cdrom/cdrom_dosbox.cpp @@ -8,7 +8,7 @@ * * CD-ROM image file handling module. * - * Version: @(#)cdrom_dosbox.cpp 1.0.5 2018/03/19 + * Version: @(#)cdrom_dosbox.cpp 1.0.6 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -380,27 +380,27 @@ bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) ifstream in; in.open(cuefile, ios::in); if (in.fail()) return false; - int last_attr = 0x00; - +// int last_attr = 0x00; + while(!in.eof()) { // get next line char buf[MAX_LINE_LENGTH]; in.getline(buf, MAX_LINE_LENGTH); if (in.fail() && !in.eof()) return false; // probably a binary file istringstream line(buf); - + string command; GetCueKeyword(command, line); - + if (command == "TRACK") { if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); else success = true; - + track.start = 0; track.skip = 0; currPregap = 0; prestart = 0; - + line >> track.number; track.track_number = track.number; string type; @@ -435,6 +435,7 @@ bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) track.attr = DATA_TRACK; track.mode2 = true; } else if (type == "MODE2/2352") { + track.form = 1; /* Assume this is XA Mode 2 Form 1. */ track.sectorSize = RAW_SECTOR_SIZE; track.attr = DATA_TRACK; track.mode2 = true; @@ -451,7 +452,7 @@ bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) track.attr = DATA_TRACK; track.mode2 = true; } else success = false; - last_attr = track.attr; +// last_attr = track.attr; canAddTrack = true; } @@ -469,7 +470,7 @@ bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); else success = true; canAddTrack = false; - + string filename; GetCueString(filename, line); GetRealFileName(filename, pathname); @@ -499,13 +500,13 @@ bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) } // add last track if (!AddTrack(track, shift, prestart, totalPregap, currPregap)) return false; - + // add leadout track track.number++; track.track_number = 0xAA; // track.attr = 0;//sync with load iso - // track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ - track.attr = last_attr | 0x02; + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + // track.attr = last_attr | 0x02; track.start = 0; track.length = 0; track.file = NULL; @@ -522,7 +523,7 @@ bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t pres if (prestart > curr.start) return false; skip = curr.start - prestart; } else skip = 0; - + // first track (track number must be 1) if (tracks.empty()) { if (curr.number != 1) return false; @@ -532,14 +533,14 @@ bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t pres tracks.push_back(curr); return true; } - + Track &prev = *(tracks.end() - 1); - + // current track consumes data from the same file as the previous if (prev.file == curr.file) { curr.start += shift; prev.length = curr.start + totalPregap - prev.start - skip; - curr.skip += prev.skip + (prev.length * prev.sectorSize) + (skip * curr.sectorSize); + curr.skip += prev.skip + (prev.length * prev.sectorSize) + (skip * curr.sectorSize); totalPregap += currPregap; curr.start += totalPregap; // current track uses a different file as the previous track @@ -547,13 +548,13 @@ bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t pres uint64_t tmp = prev.file->getLength() - ((uint64_t) prev.skip); prev.length = tmp / ((uint64_t) prev.sectorSize); if (tmp % prev.sectorSize != 0) prev.length++; // padding - + curr.start += prev.start + prev.length + currPregap; curr.skip = skip * curr.sectorSize; shift += prev.start + prev.length; totalPregap = currPregap; } - + // error checks if (curr.number <= 1) return false; if (prev.number + 1 != curr.number) return false; @@ -562,7 +563,7 @@ bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t pres /* curr.length is unsigned, so... --FvK */ if (curr.length < 0) return false; #endif - + tracks.push_back(curr); return true; } @@ -628,7 +629,7 @@ bool CDROM_Interface_Image::GetCueKeyword(string &keyword, istream &in) { in >> keyword; for(Bitu i = 0; i < keyword.size(); i++) keyword[i] = toupper(keyword[i]); - + return true; } @@ -639,7 +640,7 @@ bool CDROM_Interface_Image::GetCueFrame(uint64_t &frames, istream &in) int min, sec, fr; bool success = sscanf(msf.c_str(), "%d:%d:%d", &min, &sec, &fr) == 3; frames = MSF_TO_FRAMES(min, sec, fr); - + return success; } diff --git a/src/cdrom/cdrom_image.cpp b/src/cdrom/cdrom_image.cpp index 2cfc61d..5a67633 100644 --- a/src/cdrom/cdrom_image.cpp +++ b/src/cdrom/cdrom_image.cpp @@ -8,7 +8,7 @@ * * CD-ROM image support. * - * Version: @(#)cdrom_image.cpp 1.0.6 2018/03/20 + * Version: @(#)cdrom_image.cpp 1.0.7 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -801,10 +801,14 @@ read_mode2_xa_form2: return 0; } - if (mode2) - goto read_mode2_non_xa; - else - goto read_mode1; + if (mode2 && (form == 1)) + goto read_mode2_xa_form1; + else if (!mode2) + goto read_mode1; + else { + cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", id); + return 0; + } } else { if (mode2) if (form == 1) diff --git a/src/config.c b/src/config.c index 5fe5add..46b1059 100644 --- a/src/config.c +++ b/src/config.c @@ -270,7 +270,7 @@ config_read(wchar_t *fn) while (1) { memset(buff, 0x00, sizeof(buff)); fgetws(buff, sizeof_w(buff), f); - if (feof(f)) break; + if (ferror(f) || feof(f)) break; /* Make sure there are no stray newlines or hard-returns in there. */ if (buff[wcslen(buff)-1] == L'\n') buff[wcslen(buff)-1] = L'\0'; @@ -2104,7 +2104,9 @@ config_save(void) save_floppy_drives(); /* Floppy drives */ save_other_removable_devices(); /* Other removable devices */ - config_write(cfg_path); + /* Not if we are running readonly! */ + if (config_ro) + config_write(cfg_path); } diff --git a/src/disk/zip.c b/src/disk/zip.c index 5f04492..717014d 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -1,2550 +1,2614 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Implementation of the Iomega ZIP drive with SCSI(-like) - * commands, for both ATAPI and SCSI usage. - * - * Version: @(#)zip.c 1.0.7 2018/03/20 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * - * Copyright 2018 Miran Grca. - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. - */ -#include -#include -#include -#include -#include -#include -#define HAVE_STDARG_H -#include "../emu.h" -#include "../config.h" -#include "../timer.h" -#include "../device.h" -#include "../intel_piix.h" -#include "../scsi/scsi.h" -#include "../nvr.h" -#include "../disk/hdc.h" -#include "../disk/hdc_ide.h" -#include "../plat.h" -#include "../ui.h" -#include "zip.h" - - -/* Bits of 'status' */ -#define ERR_STAT 0x01 -#define DRQ_STAT 0x08 /* Data request */ -#define DSC_STAT 0x10 -#define SERVICE_STAT 0x10 -#define READY_STAT 0x40 -#define BUSY_STAT 0x80 - -/* Bits of 'error' */ -#define ABRT_ERR 0x04 /* Command aborted */ -#define MCR_ERR 0x08 /* Media change request */ - -zip_t zip[ZIP_NUM]; -zip_drive_t zip_drives[ZIP_NUM]; -uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; -uint8_t scsi_zip_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, - { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; - - -/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ -static const uint8_t zip_command_flags[0x100] = -{ - IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ - IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ - 0, - IMPLEMENTED | ALLOW_UA, /* 0x03 */ - IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ - 0, - IMPLEMENTED, /* 0x06 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x08 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x0A */ - 0, - IMPLEMENTED, /* 0x0C */ - IMPLEMENTED | ATAPI_ONLY, /* 0x0D */ - 0, 0, 0, 0, - IMPLEMENTED | ALLOW_UA, /* 0x12 */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ - 0, - IMPLEMENTED, /* 0x15 */ - IMPLEMENTED | SCSI_ONLY, /* 0x16 */ - IMPLEMENTED | SCSI_ONLY, /* 0x17 */ - 0, 0, - IMPLEMENTED, - IMPLEMENTED | CHECK_READY, /* 0x1B */ - 0, - IMPLEMENTED, /* 0x1D */ - IMPLEMENTED | CHECK_READY, /* 0x1E */ - 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x25 */ - 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x28 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0x2A */ - 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0x2E */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, - IMPLEMENTED | CHECK_READY, /* 0x41 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0x55 */ - 0, 0, 0, 0, - IMPLEMENTED, /* 0x5A */ - 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xA8 */ - 0, - IMPLEMENTED | CHECK_READY, /* 0xAA */ - 0, 0, 0, - IMPLEMENTED | CHECK_READY, /* 0xAE */ - IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - IMPLEMENTED, /* 0xBD */ - 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x02LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); -uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x05LL) | (1LL << 0x08LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); - - -static const mode_sense_pages_t zip_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; - -static const mode_sense_pages_t zip_250_mode_sense_pages_default = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; - -static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; - -static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; - -static const mode_sense_pages_t zip_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, - { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } -} }; - -static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = -{ { - { 0, 0 }, - { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0, 0 }, - { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } -} }; - -static mode_sense_pages_t zip_mode_sense_pages_saved[ZIP_NUM]; - - -#ifdef ENABLE_ZIP_LOG -int zip_do_log = ENABLE_ZIP_LOG; -#endif - - -static void -zip_log(const char *format, ...) -{ -#ifdef ENABLE_ZIP_LOG - va_list ap; - - if (zip_do_log) - { - va_start(ap, format); - pclog_ex(format, ap); - va_end(ap); - } -#endif -} - - -int find_zip_for_channel(uint8_t channel) -{ - uint8_t i = 0; - - for (i = 0; i < ZIP_NUM; i++) { - if (((zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) && (zip_drives[i].ide_channel == channel)) - return i; - } - return 0xff; -} - -void zip_init(int id, int cdb_len_setting); - -int zip_load(uint8_t id, wchar_t *fn) -{ - int read_only = zip_drives[id].ui_writeprot; - int size = 0; - - zip_drives[id].f = plat_fopen(fn, zip_drives[id].ui_writeprot ? L"rb" : L"rb+"); - if (!zip_drives[id].ui_writeprot && !zip_drives[id].f) { - zip_drives[id].f = plat_fopen(fn, L"rb"); - read_only = 1; - } - if (zip_drives[id].f) { - fseek(zip_drives[id].f, 0, SEEK_END); - size = ftell(zip_drives[id].f); - - if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { - /* This is a ZDI image. */ - size -= 0x1000; - zip_drives[id].base = 0x1000; - } else - zip_drives[id].base = 0; - - if (zip_drives[id].is_250) { - if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - zip_drives[id].medium_size = 0; - zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } else { - if (size != (ZIP_SECTORS << 9)) { - zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", ZIP_SECTORS << 9); - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - zip_drives[id].medium_size = 0; - zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ - return 0; - } - } - - zip_drives[id].medium_size = size >> 9; - - fseek(zip_drives[id].f, zip_drives[id].base, SEEK_SET); - - memcpy(zip_drives[id].image_path, fn, sizeof(zip_drives[id].image_path)); - - zip_drives[id].read_only = read_only; - - return 1; - } - - return 0; -} - -void zip_disk_reload(uint8_t id) -{ - int ret = 0; - - if (wcslen(zip_drives[id].prev_image_path) == 0) - return; - else - ret = zip_load(id, zip_drives[id].prev_image_path); - - if (ret) - zip[id].unit_attention = 1; -} - -void zip_close(uint8_t id) -{ - if (zip_drives[id].f) { - fclose(zip_drives[id].f); - zip_drives[id].f = NULL; - - memcpy(zip_drives[id].prev_image_path, zip_drives[id].image_path, sizeof(zip_drives[id].prev_image_path)); - memset(zip_drives[id].image_path, 0, sizeof(zip_drives[id].image_path)); - - zip_drives[id].medium_size = 0; - } -} - -void build_atapi_zip_map(void) -{ - uint8_t i = 0; - - memset(atapi_zip_drives, 0xff, 8); - - for (i = 0; i < 8; i++) { - atapi_zip_drives[i] = find_zip_for_channel(i); - if (atapi_zip_drives[i] != 0xff) - zip_init(atapi_zip_drives[i], 12); - } -} - -int find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t i = 0; - - for (i = 0; i < ZIP_NUM; i++) { - if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id) && (zip_drives[i].scsi_device_lun == scsi_lun)) - return i; - } - return 0xff; -} - -void build_scsi_zip_map(void) -{ - uint8_t i = 0; - uint8_t j = 0; - - for (i = 0; i < 16; i++) - memset(scsi_zip_drives[i], 0xff, 8); - - for (i = 0; i < 16; i++) { - for (j = 0; j < 8; j++) { - scsi_zip_drives[i][j] = find_zip_for_scsi_id(i, j); - if (scsi_zip_drives[i][j] != 0xff) - zip_init(scsi_zip_drives[i][j], 12); - } - } -} - -void zip_set_callback(uint8_t id) -{ - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) - ide_set_callback(zip_drives[id].ide_channel, zip[id].callback); -} - -void zip_set_cdb_len(int id, int cdb_len) -{ - zip[id].cdb_len = cdb_len; -} - -void zip_reset_cdb_len(int id) -{ - zip[id].cdb_len = zip[id].cdb_len_setting ? 16 : 12; -} - -void zip_set_signature(int id) -{ - if (id >= ZIP_NUM) - return; - zip[id].phase = 1; - zip[id].request_length = 0xEB14; -} - -void zip_init(int id, int cdb_len_setting) -{ - if (id >= ZIP_NUM) - return; - memset(&(zip[id]), 0, sizeof(zip_t)); - zip[id].requested_blocks = 1; - if (cdb_len_setting <= 1) - zip[id].cdb_len_setting = cdb_len_setting; - zip_reset_cdb_len(id); - zip[id].sense[0] = 0xf0; - zip[id].sense[7] = 10; - zip_drives[id].bus_mode = 0; - if (zip_drives[id].bus_type >= ZIP_BUS_ATAPI_PIO_AND_DMA) - zip_drives[id].bus_mode |= 2; - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - zip_drives[id].bus_mode |= 1; - zip_log("ZIP %i: Bus type %i, bus mode %i\n", id, zip_drives[id].bus_type, zip_drives[id].bus_mode); - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - zip_set_signature(id); - zip[id].status = READY_STAT | DSC_STAT; - zip[id].pos = 0; - zip[id].packet_status = 0xff; - zip_sense_key = zip_asc = zip_ascq = zip[id].unit_attention = 0; - zip[id].cdb_len_setting = 0; - zip[id].cdb_len = 12; -} - -int zip_supports_pio(int id) -{ - return (zip_drives[id].bus_mode & 1); -} - -int zip_supports_dma(int id) -{ - return (zip_drives[id].bus_mode & 2); -} - -/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ -int zip_current_mode(int id) -{ - if (!zip_supports_pio(id) && !zip_supports_dma(id)) - return 0; - if (zip_supports_pio(id) && !zip_supports_dma(id)) { - zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", id); - return 1; - } - if (!zip_supports_pio(id) && zip_supports_dma(id)) - return 2; - if (zip_supports_pio(id) && zip_supports_dma(id)) { - zip_log("ZIP %i: Drive supports both, setting to %s\n", id, (zip[id].features & 1) ? "DMA" : "PIO", id); - return (zip[id].features & 1) ? 2 : 1; - } - - return 0; -} - -/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ -int zip_ZIP_PHASE_to_scsi(uint8_t id) -{ - if (zip[id].status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; -} - -/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ -int zip_atapi_phase_to_scsi(uint8_t id) -{ - if (zip[id].status & 8) { - switch (zip[id].phase & 3) { - case 0: - return 0; - case 1: - return 2; - case 2: - return 1; - case 3: - return 7; - } - } else { - if ((zip[id].phase & 3) == 3) - return 3; - else - return 4; - } - - return 0; -} - -int zip_lba_to_msf_accurate(int lba) -{ - int temp_pos; - int m, s, f; - - temp_pos = lba + 150; - f = temp_pos % 75; - temp_pos -= f; - temp_pos /= 75; - s = temp_pos % 60; - temp_pos -= s; - temp_pos /= 60; - m = temp_pos; - - return ((m << 16) | (s << 8) | f); -} - -void zip_mode_sense_load(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - int i; - memset(&zip_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); - for (i = 0; i < 0x3f; i++) { - if (zip_drives[id].is_250) { - if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default_scsi.pages[i], zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default.pages[i], zip_250_mode_sense_pages_default.pages[i][1] + 2); - } - } else { - if (zip_mode_sense_pages_default.pages[i][1] != 0) { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default_scsi.pages[i], zip_mode_sense_pages_default_scsi.pages[i][1] + 2); - else - memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default.pages[i], zip_mode_sense_pages_default.pages[i][1] + 2); - } - } - } - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); - else - swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); - f = plat_fopen(nvr_path(file_name), L"rb"); - if (f) - fclose(f); -} - -void zip_mode_sense_save(uint8_t id) -{ - FILE *f; - wchar_t file_name[512]; - memset(file_name, 0, 512 * sizeof(wchar_t)); - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); - else - swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); - f = plat_fopen(nvr_path(file_name), L"wb"); - if (f) - fclose(f); -} - -static void zip_command_complete(uint8_t id); - -uint8_t zip_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - -int zip_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) -{ - int size = 0; - - if (zip_drives[id].is_250) - size = zip_drives[id].medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ - else - size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ - memset(buffer, 0, 8); - buffer[0] = (size >> 24) & 0xff; - buffer[1] = (size >> 16) & 0xff; - buffer[2] = (size >> 8) & 0xff; - buffer[3] = size & 0xff; - buffer[6] = 2; /* 512 = 0x0200 */ - *len = 8; - - return 1; -} - -/*SCSI Mode Sense 6/10*/ -uint8_t zip_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) -{ - switch (page_control) { - case 0: - case 3: - if (zip_drives[id].is_250 && (page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) - return 0x60; - return zip_mode_sense_pages_saved[id].pages[page][pos]; - break; - case 1: - if (zip_drives[id].is_250) - return zip_250_mode_sense_pages_changeable.pages[page][pos]; - else - return zip_mode_sense_pages_changeable.pages[page][pos]; - break; - case 2: - if (zip_drives[id].is_250) { - if ((page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) - return 0x60; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - return zip_250_mode_sense_pages_default_scsi.pages[page][pos]; - else - return zip_250_mode_sense_pages_default.pages[page][pos]; - } else { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - return zip_mode_sense_pages_default_scsi.pages[page][pos]; - else - return zip_mode_sense_pages_default.pages[page][pos]; - } - break; - } - - return 0; -} - -uint32_t zip_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) -{ - uint64_t page_flags; - uint8_t page_control = (type >> 6) & 3; - - if (zip_drives[id].is_250) - page_flags = zip_250_mode_sense_page_flags; - else - page_flags = zip_mode_sense_page_flags; - - int i = 0; - int j = 0; - - uint8_t msplen; - - type &= 0x3f; - - if (block_descriptor_len) { - if (zip_drives[id].is_250) { - buf[pos++] = ((zip_drives[id].medium_size >> 24) & 0xff); - buf[pos++] = ((zip_drives[id].medium_size >> 16) & 0xff); - buf[pos++] = ((zip_drives[id].medium_size >> 8) & 0xff); - buf[pos++] = ( zip_drives[id].medium_size & 0xff); - } else { - buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); - buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); - buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); - buf[pos++] = ( ZIP_SECTORS & 0xff); - } - buf[pos++] = 0; /* Reserved. */ - buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ - buf[pos++] = 2; - buf[pos++] = 0; - } - - for (i = 0; i < 0x40; i++) { - if ((type == GPMODE_ALL_PAGES) || (type == i)) { - if (page_flags & (1LL << zip[id].current_page_code)) { - buf[pos++] = zip_mode_sense_read(id, page_control, i, 0); - msplen = zip_mode_sense_read(id, page_control, i, 1); - buf[pos++] = msplen; - zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); - for (j = 0; j < msplen; j++) - buf[pos++] = zip_mode_sense_read(id, page_control, i, 2 + j); - } - } - } - - return pos; -} - -void zip_update_request_length(uint8_t id, int len, int block_len) -{ - uint32_t bt; - - if (!zip[id].request_length) - zip[id].max_transfer_len = 65534; - else - zip[id].max_transfer_len = zip[id].request_length; - - /* For media access commands, make sure the requested DRQ length matches the block length. */ - switch (zip[id].current_cdb[0]) { - case 0x08: - case 0x28: - case 0xa8: - if (zip[id].max_transfer_len < block_len) - zip[id].max_transfer_len = block_len; - bt = (zip[id].requested_blocks * block_len); - if (len > bt) - len = bt; - default: - zip[id].packet_len = len; - break; - } - /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ - if ((zip[id].max_transfer_len & 1) && (zip[id].max_transfer_len < len)) - zip[id].max_transfer_len &= 0xfffe; - /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ - if (len <= zip[id].max_transfer_len) - zip[id].max_transfer_len = len; - return; -} - -static void zip_command_common(uint8_t id) -{ - double bytes_per_second, period; - double dusec; - - bytes_per_second = 0.0; - zip[id].status = BUSY_STAT; - zip[id].phase = 1; - zip[id].pos = 0; - if (zip[id].packet_status == ZIP_PHASE_COMPLETE) { - zip_phase_callback(id); - zip[id].callback = 0LL; - } else { - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - zip[id].callback = -1LL; /* Speed depends on SCSI controller */ - return; - } else if (zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) { - if (zip_current_mode(id) == 2) - bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ - else - bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ - } else - bytes_per_second = 3333333.333333333333333; /* 3.3 MB/s PIO-0 speed */ - - period = 1000000.0 / bytes_per_second; - dusec = (double) TIMER_USEC; - dusec = dusec * period * (double) (zip[id].packet_len); - zip[id].callback = ((int64_t) dusec); - } - - zip_set_callback(id); -} - -static void zip_command_complete(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip_command_common(id); -} - -static void zip_command_read(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_DATA_IN; - zip_command_common(id); - zip[id].total_read = 0; -} - -static void zip_command_read_dma(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_DATA_IN_DMA; - zip_command_common(id); - zip[id].total_read = 0; -} - -static void zip_command_write(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_DATA_OUT; - zip_command_common(id); -} - -static void zip_command_write_dma(uint8_t id) -{ - zip[id].packet_status = ZIP_PHASE_DATA_OUT_DMA; - zip_command_common(id); -} - -/* id = Current ZIP device ID; - len = Total transfer length; - block_len = Length of a single block (why does it matter?!); - alloc_len = Allocated transfer length; - direction = Transfer direction (0 = read from host, 1 = write to host). */ -static void zip_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) -{ - zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, zip[id].current_cdb[0], len, block_len, alloc_len, direction, zip[id].request_length); - zip[id].pos=0; - if (alloc_len >= 0) { - if (alloc_len < len) { - len = alloc_len; - } - } - - if ((len == 0) || (zip_current_mode(id) == 0)) { - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { - zip[id].packet_len = 0; - } - zip_command_complete(id); - } - else { - if (zip_current_mode(id) == 2) { - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { - zip[id].packet_len = alloc_len; - } - - if (direction == 0) - zip_command_read_dma(id); - else - zip_command_write_dma(id); - } - else { - zip_update_request_length(id, len, block_len); - if (direction == 0) - zip_command_read(id); - else - zip_command_write(id); - } - } - - zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, zip[id].packet_status, zip[id].request_length, zip[id].packet_len, zip[id].pos, zip[id].phase); -} - -static void zip_sense_clear(int id, int command) -{ - zip[id].previous_command = command; - zip_sense_key = zip_asc = zip_ascq = 0; -} - -static void zip_set_phase(uint8_t id, uint8_t phase) -{ - uint8_t scsi_id = zip_drives[id].scsi_device_id; - uint8_t scsi_lun = zip_drives[id].scsi_device_lun; - - if (zip_drives[id].bus_type != ZIP_BUS_SCSI) - return; - - SCSIDevices[scsi_id][scsi_lun].Phase = phase; -} - -static void zip_cmd_error(uint8_t id) -{ - zip_set_phase(id, SCSI_PHASE_STATUS); - zip[id].error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; - if (zip[id].unit_attention) - zip[id].error |= MCR_ERR; - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip[id].pos = 0; - zip[id].packet_status = 0x80; - zip[id].callback = 50LL * ZIP_TIME; - zip_set_callback(id); - zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", id, zip[id].current_cdb[0], zip_sense_key, zip_asc, zip_ascq); -} - -static void zip_unit_attention(uint8_t id) -{ - zip_set_phase(id, SCSI_PHASE_STATUS); - zip[id].error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; - if (zip[id].unit_attention) - zip[id].error |= MCR_ERR; - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip[id].pos = 0; - zip[id].packet_status = 0x80; - zip[id].callback = 50LL * ZIP_TIME; - zip_set_callback(id); - zip_log("ZIP %i: UNIT ATTENTION\n", id); -} - -static void zip_not_ready(uint8_t id) -{ - zip_sense_key = SENSE_NOT_READY; - zip_asc = ASC_MEDIUM_NOT_PRESENT; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_write_protected(uint8_t id) -{ - zip_sense_key = SENSE_UNIT_ATTENTION; - zip_asc = ASC_WRITE_PROTECTED; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_invalid_lun(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_LUN; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_illegal_opcode(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_ILLEGAL_OPCODE; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_lba_out_of_range(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_LBA_OUT_OF_RANGE; - zip_ascq = 0; - zip_cmd_error(id); -} - -static void zip_invalid_field(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; - zip_ascq = 0; - zip_cmd_error(id); - zip[id].status = 0x53; -} - -static void zip_invalid_field_pl(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; - zip_ascq = 0; - zip_cmd_error(id); - zip[id].status = 0x53; -} - -static void zip_data_phase_error(uint8_t id) -{ - zip_sense_key = SENSE_ILLEGAL_REQUEST; - zip_asc = ASC_DATA_PHASE_ERROR; - zip_ascq = 0; - zip_cmd_error(id); -} - -#define zipbufferb zip[id].buffer - -int zip_blocks(uint8_t id, uint32_t *len, int first_batch, int out) -{ - zip[id].data_pos = 0; - - *len = 0; - - if (!zip[id].sector_len) { - zip_command_complete(id); - return -1; - } - - *len = zip[id].requested_blocks << 9; - - if (zip[id].sector_pos >= zip_drives[id].medium_size) { - zip_log("ZIP %i: Trying to %s beyond the end of disk\n", id, out ? "write" : "read"); - zip_lba_out_of_range(id); - return 0; - } - - zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); - - fseek(zip_drives[id].f, zip_drives[id].base + (zip[id].sector_pos << 9), SEEK_SET); - if (out) - fwrite(zipbufferb, 1, *len, zip_drives[id].f); - else - fread(zipbufferb, 1, *len, zip_drives[id].f); - +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Iomega ZIP drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)zip.c 1.0.8 2018/03/21 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2018 Miran Grca. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../emu.h" +#include "../config.h" +#include "../timer.h" +#include "../device.h" +#include "../intel_piix.h" +#include "../scsi/scsi.h" +#include "../nvr.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../plat.h" +#include "../ui.h" +#include "zip.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +zip_t zip[ZIP_NUM]; +zip_drive_t zip_drives[ZIP_NUM]; +uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +uint8_t scsi_zip_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +static const uint8_t zip_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ + 0, + IMPLEMENTED, /* 0x06 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x0A */ + 0, + IMPLEMENTED, /* 0x0C */ + IMPLEMENTED | ATAPI_ONLY, /* 0x0D */ + 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, + IMPLEMENTED, /* 0x15 */ + IMPLEMENTED | SCSI_ONLY, /* 0x16 */ + IMPLEMENTED | SCSI_ONLY, /* 0x17 */ + 0, 0, + IMPLEMENTED, + IMPLEMENTED | CHECK_READY, /* 0x1B */ + 0, + IMPLEMENTED, /* 0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, + IMPLEMENTED | ATAPI_ONLY, /* 0x23 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x2A */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + IMPLEMENTED | CHECK_READY, /* 0x41 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0xAA */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0xBD */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x02LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); +uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | (1LL << 0x05LL) | (1LL << 0x08LL) | (1LL << 0x2FLL) | (1LL << GPMODE_ALL_PAGES); + + +static const mode_sense_pages_t zip_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static const mode_sense_pages_t zip_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static mode_sense_pages_t zip_mode_sense_pages_saved[ZIP_NUM]; + + +#ifdef ENABLE_ZIP_LOG +int zip_do_log = ENABLE_ZIP_LOG; +#endif + + +static void +zip_log(const char *format, ...) +{ +#ifdef ENABLE_ZIP_LOG + va_list ap; + + if (zip_do_log) + { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +int find_zip_for_channel(uint8_t channel) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if (((zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_ONLY) || (zip_drives[i].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) && (zip_drives[i].ide_channel == channel)) + return i; + } + return 0xff; +} + +void zip_init(int id, int cdb_len_setting); + +int zip_load(uint8_t id, wchar_t *fn) +{ + int read_only = zip_drives[id].ui_writeprot; + int size = 0; + + zip_drives[id].f = plat_fopen(fn, zip_drives[id].ui_writeprot ? L"rb" : L"rb+"); + if (!zip_drives[id].ui_writeprot && !zip_drives[id].f) { + zip_drives[id].f = plat_fopen(fn, L"rb"); + read_only = 1; + } + if (zip_drives[id].f) { + fseek(zip_drives[id].f, 0, SEEK_END); + size = ftell(zip_drives[id].f); + + if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { + /* This is a ZDI image. */ + size -= 0x1000; + zip_drives[id].base = 0x1000; + } else + zip_drives[id].base = 0; + + if (zip_drives[id].is_250) { + if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + zip_drives[id].medium_size = 0; + zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; + } + } else { + if (size != (ZIP_SECTORS << 9)) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", ZIP_SECTORS << 9); + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + zip_drives[id].medium_size = 0; + zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; + } + } + + zip_drives[id].medium_size = size >> 9; + + fseek(zip_drives[id].f, zip_drives[id].base, SEEK_SET); + + memcpy(zip_drives[id].image_path, fn, sizeof(zip_drives[id].image_path)); + + zip_drives[id].read_only = read_only; + + return 1; + } + + return 0; +} + +void zip_disk_reload(uint8_t id) +{ + int ret = 0; + + if (wcslen(zip_drives[id].prev_image_path) == 0) + return; + else + ret = zip_load(id, zip_drives[id].prev_image_path); + + if (ret) + zip[id].unit_attention = 1; +} + +void zip_close(uint8_t id) +{ + if (zip_drives[id].f) { + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + + memcpy(zip_drives[id].prev_image_path, zip_drives[id].image_path, sizeof(zip_drives[id].prev_image_path)); + memset(zip_drives[id].image_path, 0, sizeof(zip_drives[id].image_path)); + + zip_drives[id].medium_size = 0; + } +} + +void build_atapi_zip_map(void) +{ + uint8_t i = 0; + + memset(atapi_zip_drives, 0xff, 8); + + for (i = 0; i < 8; i++) { + atapi_zip_drives[i] = find_zip_for_channel(i); + if (atapi_zip_drives[i] != 0xff) + zip_init(atapi_zip_drives[i], 12); + } +} + +int find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id) && (zip_drives[i].scsi_device_lun == scsi_lun)) + return i; + } + return 0xff; +} + +void build_scsi_zip_map(void) +{ + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_zip_drives[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + scsi_zip_drives[i][j] = find_zip_for_scsi_id(i, j); + if (scsi_zip_drives[i][j] != 0xff) + zip_init(scsi_zip_drives[i][j], 12); + } + } +} + +void zip_set_callback(uint8_t id) +{ + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + ide_set_callback(zip_drives[id].ide_channel, zip[id].callback); +} + +void zip_set_cdb_len(int id, int cdb_len) +{ + zip[id].cdb_len = cdb_len; +} + +void zip_reset_cdb_len(int id) +{ + zip[id].cdb_len = zip[id].cdb_len_setting ? 16 : 12; +} + +void zip_set_signature(int id) +{ + if (id >= ZIP_NUM) + return; + zip[id].phase = 1; + zip[id].request_length = 0xEB14; +} + +void zip_init(int id, int cdb_len_setting) +{ + if (id >= ZIP_NUM) + return; + memset(&(zip[id]), 0, sizeof(zip_t)); + zip[id].requested_blocks = 1; + if (cdb_len_setting <= 1) + zip[id].cdb_len_setting = cdb_len_setting; + zip_reset_cdb_len(id); + zip[id].sense[0] = 0xf0; + zip[id].sense[7] = 10; + zip_drives[id].bus_mode = 0; + if (zip_drives[id].bus_type >= ZIP_BUS_ATAPI_PIO_AND_DMA) + zip_drives[id].bus_mode |= 2; + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + zip_drives[id].bus_mode |= 1; + zip_log("ZIP %i: Bus type %i, bus mode %i\n", id, zip_drives[id].bus_type, zip_drives[id].bus_mode); + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + zip_set_signature(id); + zip[id].status = READY_STAT | DSC_STAT; + zip[id].pos = 0; + zip[id].packet_status = 0xff; + zip_sense_key = zip_asc = zip_ascq = zip[id].unit_attention = 0; + zip[id].cdb_len_setting = 0; + zip[id].cdb_len = 12; +} + +int zip_supports_pio(int id) +{ + return (zip_drives[id].bus_mode & 1); +} + +int zip_supports_dma(int id) +{ + return (zip_drives[id].bus_mode & 2); +} + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +int zip_current_mode(int id) +{ + if (!zip_supports_pio(id) && !zip_supports_dma(id)) + return 0; + if (zip_supports_pio(id) && !zip_supports_dma(id)) { + zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", id); + return 1; + } + if (!zip_supports_pio(id) && zip_supports_dma(id)) + return 2; + if (zip_supports_pio(id) && zip_supports_dma(id)) { + zip_log("ZIP %i: Drive supports both, setting to %s\n", id, (zip[id].features & 1) ? "DMA" : "PIO", id); + return (zip[id].features & 1) ? 2 : 1; + } + + return 0; +} + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int zip_ZIP_PHASE_to_scsi(uint8_t id) +{ + if (zip[id].status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int zip_atapi_phase_to_scsi(uint8_t id) +{ + if (zip[id].status & 8) { + switch (zip[id].phase & 3) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } else { + if ((zip[id].phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; +} + +int zip_lba_to_msf_accurate(int lba) +{ + int temp_pos; + int m, s, f; + + temp_pos = lba + 150; + f = temp_pos % 75; + temp_pos -= f; + temp_pos /= 75; + s = temp_pos % 60; + temp_pos -= s; + temp_pos /= 60; + m = temp_pos; + + return ((m << 16) | (s << 8) | f); +} + +void zip_mode_sense_load(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + int i; + memset(&zip_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (zip_drives[id].is_250) { + if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default_scsi.pages[i], zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default.pages[i], zip_250_mode_sense_pages_default.pages[i][1] + 2); + } + } else { + if (zip_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default_scsi.pages[i], zip_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default.pages[i], zip_mode_sense_pages_default.pages[i][1] + 2); + } + } + } + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) + fclose(f); +} + +void zip_mode_sense_save(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) + fclose(f); +} + +static void zip_command_complete(uint8_t id); + +uint8_t zip_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +int zip_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + if (zip_drives[id].is_250) + size = zip_drives[id].medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + else + size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + +/*SCSI Mode Sense 6/10*/ +uint8_t zip_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + if (zip_drives[id].is_250 && (page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) + return 0x60; + return zip_mode_sense_pages_saved[id].pages[page][pos]; + break; + case 1: + if (zip_drives[id].is_250) + return zip_250_mode_sense_pages_changeable.pages[page][pos]; + else + return zip_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (zip_drives[id].is_250) { + if ((page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) + return 0x60; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + return zip_250_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_250_mode_sense_pages_default.pages[page][pos]; + } else { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + return zip_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_mode_sense_pages_default.pages[page][pos]; + } + break; + } + + return 0; +} + +uint32_t zip_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint64_t page_flags; + uint8_t page_control = (type >> 6) & 3; + + if (zip_drives[id].is_250) + page_flags = zip_250_mode_sense_page_flags; + else + page_flags = zip_mode_sense_page_flags; + + int i = 0; + int j = 0; + + uint8_t msplen; + + type &= 0x3f; + + if (block_descriptor_len) { + if (zip_drives[id].is_250) { + buf[pos++] = ((zip_drives[id].medium_size >> 24) & 0xff); + buf[pos++] = ((zip_drives[id].medium_size >> 16) & 0xff); + buf[pos++] = ((zip_drives[id].medium_size >> 8) & 0xff); + buf[pos++] = ( zip_drives[id].medium_size & 0xff); + } else { + buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); + buf[pos++] = ( ZIP_SECTORS & 0xff); + } + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (page_flags & (1LL << zip[id].current_page_code)) { + buf[pos++] = zip_mode_sense_read(id, page_control, i, 0); + msplen = zip_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = zip_mode_sense_read(id, page_control, i, 2 + j); + } + } + } + + return pos; +} + +void zip_update_request_length(uint8_t id, int len, int block_len) +{ + uint32_t bt; + + if (!zip[id].request_length) + zip[id].max_transfer_len = 65534; + else + zip[id].max_transfer_len = zip[id].request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (zip[id].current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + if (zip[id].max_transfer_len < block_len) + zip[id].max_transfer_len = block_len; + bt = (zip[id].requested_blocks * block_len); + if (len > bt) + len = bt; + default: + zip[id].packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((zip[id].max_transfer_len & 1) && (zip[id].max_transfer_len < len)) + zip[id].max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (len <= zip[id].max_transfer_len) + zip[id].max_transfer_len = len; + return; +} + +static void zip_command_common(uint8_t id) +{ + double bytes_per_second, period; + double dusec; + + bytes_per_second = 0.0; + zip[id].status = BUSY_STAT; + zip[id].phase = 1; + zip[id].pos = 0; + if (zip[id].packet_status == ZIP_PHASE_COMPLETE) { + zip_phase_callback(id); + zip[id].callback = 0LL; + } else { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zip[id].callback = -1LL; /* Speed depends on SCSI controller */ + return; + } else if (zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) { + if (zip_current_mode(id) == 2) + bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ + } else + bytes_per_second = 3333333.333333333333333; /* 3.3 MB/s PIO-0 speed */ + + period = 1000000.0 / bytes_per_second; + dusec = (double) TIMER_USEC; + dusec = dusec * period * (double) (zip[id].packet_len); + zip[id].callback = ((int64_t) dusec); + } + + zip_set_callback(id); +} + +static void zip_command_complete(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip_command_common(id); +} + +static void zip_command_read(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_DATA_IN; + zip_command_common(id); + zip[id].total_read = 0; +} + +static void zip_command_read_dma(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_DATA_IN_DMA; + zip_command_common(id); + zip[id].total_read = 0; +} + +static void zip_command_write(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_DATA_OUT; + zip_command_common(id); +} + +static void zip_command_write_dma(uint8_t id) +{ + zip[id].packet_status = ZIP_PHASE_DATA_OUT_DMA; + zip_command_common(id); +} + +/* id = Current ZIP device ID; + len = Total transfer length; + block_len = Length of a single block (why does it matter?!); + alloc_len = Allocated transfer length; + direction = Transfer direction (0 = read from host, 1 = write to host). */ +static void zip_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +{ + zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, zip[id].current_cdb[0], len, block_len, alloc_len, direction, zip[id].request_length); + zip[id].pos=0; + if (alloc_len >= 0) { + if (alloc_len < len) { + len = alloc_len; + } + } + + if ((len == 0) || (zip_current_mode(id) == 0)) { + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { + zip[id].packet_len = 0; + } + zip_command_complete(id); + } + else { + if (zip_current_mode(id) == 2) { + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) { + zip[id].packet_len = alloc_len; + } + + if (direction == 0) + zip_command_read_dma(id); + else + zip_command_write_dma(id); + } + else { + zip_update_request_length(id, len, block_len); + if (direction == 0) + zip_command_read(id); + else + zip_command_write(id); + } + } + + zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", id, zip[id].packet_status, zip[id].request_length, zip[id].packet_len, zip[id].pos, zip[id].phase); +} + +static void zip_sense_clear(int id, int command) +{ + zip[id].previous_command = command; + zip_sense_key = zip_asc = zip_ascq = 0; +} + +static void zip_set_phase(uint8_t id, uint8_t phase) +{ + uint8_t scsi_id = zip_drives[id].scsi_device_id; + uint8_t scsi_lun = zip_drives[id].scsi_device_lun; + + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; +} + +static void zip_cmd_error(uint8_t id) +{ + zip_set_phase(id, SCSI_PHASE_STATUS); + zip[id].error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; + if (zip[id].unit_attention) + zip[id].error |= MCR_ERR; + zip[id].status = READY_STAT | ERR_STAT; + zip[id].phase = 3; + zip[id].pos = 0; + zip[id].packet_status = 0x80; + zip[id].callback = 50LL * ZIP_TIME; + zip_set_callback(id); + zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", id, zip[id].current_cdb[0], zip_sense_key, zip_asc, zip_ascq); +} + +static void zip_unit_attention(uint8_t id) +{ + zip_set_phase(id, SCSI_PHASE_STATUS); + zip[id].error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (zip[id].unit_attention) + zip[id].error |= MCR_ERR; + zip[id].status = READY_STAT | ERR_STAT; + zip[id].phase = 3; + zip[id].pos = 0; + zip[id].packet_status = 0x80; + zip[id].callback = 50LL * ZIP_TIME; + zip_set_callback(id); + zip_log("ZIP %i: UNIT ATTENTION\n", id); +} + +static void zip_not_ready(uint8_t id) +{ + zip_sense_key = SENSE_NOT_READY; + zip_asc = ASC_MEDIUM_NOT_PRESENT; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_write_protected(uint8_t id) +{ + zip_sense_key = SENSE_UNIT_ATTENTION; + zip_asc = ASC_WRITE_PROTECTED; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_invalid_lun(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_LUN; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_illegal_opcode(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_ILLEGAL_OPCODE; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_lba_out_of_range(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_LBA_OUT_OF_RANGE; + zip_ascq = 0; + zip_cmd_error(id); +} + +static void zip_invalid_field(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; + zip_ascq = 0; + zip_cmd_error(id); + zip[id].status = 0x53; +} + +static void zip_invalid_field_pl(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + zip_ascq = 0; + zip_cmd_error(id); + zip[id].status = 0x53; +} + +static void zip_data_phase_error(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_DATA_PHASE_ERROR; + zip_ascq = 0; + zip_cmd_error(id); +} + +#define zipbufferb zip[id].buffer + +int zip_blocks(uint8_t id, uint32_t *len, int first_batch, int out) +{ + zip[id].data_pos = 0; + + *len = 0; + + if (!zip[id].sector_len) { + zip_command_complete(id); + return -1; + } + + *len = zip[id].requested_blocks << 9; + + if (zip[id].sector_pos >= zip_drives[id].medium_size) { + zip_log("ZIP %i: Trying to %s beyond the end of disk\n", id, out ? "write" : "read"); + zip_lba_out_of_range(id); + return 0; + } + + zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); fseek(zip_drives[id].f, zip_drives[id].base + (zip[id].sector_pos << 9), SEEK_SET); + if (out) + fwrite(zipbufferb, 1, *len, zip_drives[id].f); + else + fread(zipbufferb, 1, *len, zip_drives[id].f); + zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); - - zip[id].sector_pos += zip[id].requested_blocks; - zip[id].sector_len -= zip[id].requested_blocks; - - return 1; -} - -void zip_insert(uint8_t id) -{ - zip[id].unit_attention = 1; -} - -/*SCSI Sense Initialization*/ -void zip_sense_code_ok(uint8_t id) -{ - zip_sense_key = SENSE_NONE; - zip_asc = 0; - zip_ascq = 0; -} - -int zip_pre_execution_check(uint8_t id, uint8_t *cdb) -{ - int ready = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (((zip[id].request_length >> 5) & 7) != zip_drives[id].scsi_device_lun) { - zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((zip[id].request_length >> 5) & 7)); - zip_invalid_lun(id); - return 0; - } - } - - if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { - zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? "SCSI" : ((zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) ? "ATAPI PIO/DMA" : "ATAPI PIO")); - - zip_illegal_opcode(id); - return 0; - } - - if ((zip_drives[id].bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { - zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); - zip_illegal_opcode(id); - return 0; - } - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { - zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); - zip_illegal_opcode(id); - return 0; - } - - ready = (zip_drives[id].f != NULL); - - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - if (!ready && zip[id].unit_attention) - zip[id].unit_attention = 0; - - /* If the UNIT ATTENTION condition is set and the command does not allow - execution under it, error out and report the condition. */ - if (zip[id].unit_attention == 1) { - /* Only increment the unit attention phase if the command can not pass through it. */ - if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { - /* zip_log("ZIP %i: Unit attention now 2\n", id); */ - zip[id].unit_attention = 2; - zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); - zip_unit_attention(id); - return 0; - } - } - else if (zip[id].unit_attention == 2) { - if (cdb[0] != GPCMD_REQUEST_SENSE) { - /* zip_log("ZIP %i: Unit attention now 0\n", id); */ - zip[id].unit_attention = 0; - } - } - - /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* - the UNIT ATTENTION condition if it's set. */ - if (cdb[0] != GPCMD_REQUEST_SENSE) - zip_sense_clear(id, cdb[0]); - - /* Next it's time for NOT READY. */ - if (!ready) - zip[id].media_status = MEC_MEDIA_REMOVAL; - else - zip[id].media_status = (zip[id].unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; - - if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { - zip_log("ZIP %i: Not ready (%02X)\n", id, cdb[0]); - zip_not_ready(id); - return 0; - } - - zip_log("ZIP %i: Continuing with command %02X\n", id, cdb[0]); - - return 1; -} - -void zip_clear_callback(uint8_t channel) -{ - uint8_t id = atapi_zip_drives[channel]; - - if (id < ZIP_NUM) - { - zip[id].callback = 0LL; - zip_set_callback(id); - } -} - -static void zip_seek(uint8_t id, uint32_t pos) -{ - /* zip_log("ZIP %i: Seek %08X\n", id, pos); */ - zip[id].sector_pos = pos; -} - -static void zip_rezero(uint8_t id) -{ - zip[id].sector_pos = zip[id].sector_len = 0; - zip_seek(id, 0); -} - -void zip_reset(uint8_t id) -{ - zip_rezero(id); - zip[id].status = 0; - zip[id].callback = 0LL; - zip_set_callback(id); - zip[id].packet_status = 0xff; - zip[id].unit_attention = 0; -} - -void zip_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) -{ - /*Will return 18 bytes of 0*/ - if (alloc_length != 0) { - memset(buffer, 0, alloc_length); - if (!desc) - memcpy(buffer, zip[id].sense, alloc_length); - else { - buffer[1] = zip_sense_key; - buffer[2] = zip_asc; - buffer[3] = zip_ascq; - } - } - - buffer[0] = desc ? 0x72 : 0x70; - - if (zip[id].unit_attention && (zip_sense_key == 0)) { - buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; - buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; - buffer[desc ? 3 : 13]=0; - } - - zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); - - if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { - /* If the last remaining sense is unit attention, clear - that condition. */ - zip[id].unit_attention = 0; - } - - /* Clear the sense stuff as per the spec. */ - zip_sense_clear(id, GPCMD_REQUEST_SENSE); -} - -void zip_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) -{ - int ready = 0; - - ready = (zip_drives[id].f != NULL); - - if (!ready && zip[id].unit_attention) { - /* If the drive is not ready, there is no reason to keep the - UNIT ATTENTION condition present, as we only use it to mark - disc changes. */ - zip[id].unit_attention = 0; - } - - /* Do *NOT* advance the unit attention phase. */ - - zip_request_sense(id, buffer, alloc_length, 0); -} - -void zip_set_buf_len(uint8_t id, int32_t *BufLen, uint32_t *src_len) -{ - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (*BufLen == -1) - *BufLen = *src_len; - else { - *BufLen = MIN(*src_len, *BufLen); - *src_len = *BufLen; - } - zip_log("ZIP %i: Actual transfer length: %i\n", id, *BufLen); - } -} - -void zip_buf_alloc(uint8_t id, uint32_t len) -{ - zip_log("ZIP %i: Allocated buffer length: %i\n", id, len); - zipbufferb = (uint8_t *) malloc(len); -} - -void zip_buf_free(uint8_t id) -{ - if (zipbufferb) { - zip_log("ZIP %i: Freeing buffer...\n", id); - free(zipbufferb); - zipbufferb = NULL; - } -} - -void zip_command(uint8_t id, uint8_t *cdb) -{ - uint32_t len; - int pos=0; - uint32_t max_len; - unsigned idx = 0; - unsigned size_idx; - unsigned preamble_len; - uint32_t alloc_length; - int block_desc = 0; - int ret; - int32_t blen = 0; - int32_t *BufLen; - uint32_t i = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; - zip[id].status &= ~ERR_STAT; - } else { - BufLen = &blen; - zip[id].error = 0; - } - - zip[id].packet_len = 0; - zip[id].request_pos = 0; - - zip[id].data_pos = 0; - - memcpy(zip[id].current_cdb, cdb, zip[id].cdb_len); - - if (cdb[0] != 0) { - zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", id, cdb[0], zip_sense_key, zip_asc, zip_ascq, zip[id].unit_attention); - zip_log("ZIP %i: Request length: %04X\n", id, zip[id].request_length); - - zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", id, - cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], - cdb[8], cdb[9], cdb[10], cdb[11]); - } - - zip[id].sector_len = 0; - - zip_set_phase(id, SCSI_PHASE_STATUS); - - /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ - if (zip_pre_execution_check(id, cdb) == 0) - return; - - switch (cdb[0]) { - case GPCMD_SEND_DIAGNOSTIC: - if (!(cdb[1] & (1 << 2))) { - zip_invalid_field(id); - return; - } - case GPCMD_SCSI_RESERVE: - case GPCMD_SCSI_RELEASE: - case GPCMD_TEST_UNIT_READY: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_FORMAT_UNIT: - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); - return; - } - - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_IOMEGA_SENSE: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; - zip_buf_alloc(id, 256); - zip_set_buf_len(id, BufLen, &max_len); - memset(zipbufferb, 0, 256); - if (cdb[2] == 1) { - /* This page is related to disk health status - setting - this page to 0 makes disk health read as "marginal". */ - zipbufferb[0] = 0x58; - zipbufferb[1] = 0x00; - for (i = 0x00; i < 0x58; i++) - zipbufferb[i + 0x02] = 0xff; - } else if (cdb[2] == 2) { - zipbufferb[0] = 0x3d; - zipbufferb[1] = 0x00; - for (i = 0x00; i < 0x13; i++) - zipbufferb[i + 0x02] = 0x00; - zipbufferb[0x15] = 0x00; - if (zip_drives[id].read_only) - zipbufferb[0x15] |= 0x02; - for (i = 0x00; i < 0x27; i++) - zipbufferb[i + 0x16] = 0x00; - } else { - zip_invalid_field(id); - zip_buf_free(id); - return; - } - zip_data_command_finish(id, 18, 18, cdb[4], 0); - break; - - case GPCMD_REZERO_UNIT: - zip[id].sector_pos = zip[id].sector_len = 0; - zip_seek(id, 0); - zip_set_phase(id, SCSI_PHASE_STATUS); - break; - - case GPCMD_REQUEST_SENSE: - /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE - should forget about the not ready, and report unit attention straight away. */ - zip_set_phase(id, SCSI_PHASE_DATA_IN); - max_len = cdb[4]; - zip_buf_alloc(id, 256); - zip_set_buf_len(id, BufLen, &max_len); - len = (cdb[1] & 1) ? 8 : 18; - zip_request_sense(id, zipbufferb, max_len, cdb[1] & 1); - zip_data_command_finish(id, len, len, cdb[4], 0); - break; - - case GPCMD_SET_SPEED: - case GPCMD_SET_SPEED_ALT: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_MECHANISM_STATUS: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; - - zip_buf_alloc(id, 8); - - zip_set_buf_len(id, BufLen, &len); - - memset(zipbufferb, 0, 8); - zipbufferb[5] = 1; - - zip_data_command_finish(id, 8, 8, len, 0); - break; - - case GPCMD_READ_6: - case GPCMD_READ_10: - case GPCMD_READ_12: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - alloc_length = 512; - - switch(cdb[0]) { - case GPCMD_READ_6: - zip[id].sector_len = cdb[4]; - zip[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_READ_10: - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_READ_12: - zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - ret = zip_blocks(id, &alloc_length, 1, 0); - if (ret <= 0) { - zip_buf_free(id); - return; - } - - zip[id].requested_blocks = max_len; - zip[id].packet_len = alloc_length; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, alloc_length, 512, alloc_length, 0); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - if (!(cdb[1] & 2)) { - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - } - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - alloc_length = 512; - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); - return; - } - - switch(cdb[0]) { - case GPCMD_VERIFY_6: - case GPCMD_WRITE_6: - zip[id].sector_len = cdb[4]; - zip[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); - break; - case GPCMD_VERIFY_10: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); - break; - case GPCMD_VERIFY_12: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); - zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); - break; - } - - if (zip_drives[id].is_250) { - if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) - { - zip_lba_out_of_range(id); - return; - } - } else { - if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) - { - zip_lba_out_of_range(id); - return; - } - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - zip[id].requested_blocks = max_len; - zip[id].packet_len = max_len << 9; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_WRITE_SAME_10: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - alloc_length = 512; - - if ((cdb[1] & 6) == 6) - { - zip_invalid_field(id); - return; - } - - if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) - { - zip_write_protected(id); - return; - } - - zip[id].sector_len = (cdb[7] << 8) | cdb[8]; - zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; - - if (zip_drives[id].is_250) { - if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) - { - zip_lba_out_of_range(id); - return; - } - } else { - if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) - { - zip_lba_out_of_range(id); - return; - } - } - - if (!zip[id].sector_len) { - zip_set_phase(id, SCSI_PHASE_STATUS); - /* zip_log("ZIP %i: All done - callback set\n", id); */ - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].callback = 20LL * ZIP_TIME; - zip_set_callback(id); - break; - } - - max_len = zip[id].sector_len; - zip[id].requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT - matter anyway, this step should be identical and only the way the read dat is - transferred to the host should be different. */ - - zip[id].packet_len = max_len * alloc_length; - zip_buf_alloc(id, zip[id].packet_len); - - zip[id].requested_blocks = max_len; - zip[id].packet_len = alloc_length; - - zip_set_buf_len(id, BufLen, &zip[id].packet_len); - - zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); - - zip[id].all_blocks_total = zip[id].block_total; - if (zip[id].packet_status != ZIP_PHASE_COMPLETE) - ui_sb_update_icon(SB_ZIP | id, 1); - else - ui_sb_update_icon(SB_ZIP | id, 0); - return; - - case GPCMD_MODE_SENSE_6: - case GPCMD_MODE_SENSE_10: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; - else - block_desc = 0; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = cdb[4]; - zip_buf_alloc(id, 256); - } else { - len = (cdb[8] | (cdb[7] << 8)); - zip_buf_alloc(id, 65536); - } - - zip[id].current_page_code = cdb[2] & 0x3F; - zip_log("Mode sense page: %02X\n", zip[id].current_page_code); - - if (!(zip_mode_sense_page_flags & (1LL << zip[id].current_page_code))) { - zip_invalid_field(id); - zip_buf_free(id); - return; - } - - memset(zipbufferb, 0, len); - alloc_length = len; - - if (cdb[0] == GPCMD_MODE_SENSE_6) { - len = zip_mode_sense(id, zipbufferb, 4, cdb[2], block_desc); - len = MIN(len, alloc_length); - zipbufferb[0] = len - 1; - zipbufferb[1] = 0; - if (block_desc) - zipbufferb[3] = 8; - } else { - len = zip_mode_sense(id, zipbufferb, 8, cdb[2], block_desc); - len = MIN(len, alloc_length); - zipbufferb[0]=(len - 2) >> 8; - zipbufferb[1]=(len - 2) & 255; - zipbufferb[2] = 0; - if (block_desc) { - zipbufferb[6] = 0; - zipbufferb[7] = 8; - } - } - - zip_set_buf_len(id, BufLen, &len); - - zip_log("ZIP %i: Reading mode page: %02X...\n", id, cdb[2]); - - zip_data_command_finish(id, len, len, alloc_length, 0); - return; - - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - zip_set_phase(id, SCSI_PHASE_DATA_OUT); - - if (cdb[0] == GPCMD_MODE_SELECT_6) { - len = cdb[4]; - zip_buf_alloc(id, 256); - } else { - len = (cdb[7] << 8) | cdb[8]; - zip_buf_alloc(id, 65536); - } - - zip_set_buf_len(id, BufLen, &len); - - zip[id].total_length = len; - zip[id].do_page_save = cdb[1] & 1; - - zip[id].current_page_pos = 0; - - zip_data_command_finish(id, len, len, len, 1); - return; - - case GPCMD_START_STOP_UNIT: - zip_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[4] & 3) { - case 0: /* Stop the disc. */ - zip_eject(id); /* The Iomega Windows 9x drivers require this. */ - break; - case 1: /* Start the disc and read the TOC. */ - break; - case 2: /* Eject the disc if possible. */ - /* zip_eject(id); */ - break; - case 3: /* Load the disc (close tray). */ - zip_reload(id); - break; - } - - zip_command_complete(id); - break; - - case GPCMD_INQUIRY: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - - max_len = cdb[3]; - max_len <<= 8; - max_len |= cdb[4]; - - zip_buf_alloc(id, 65536); - - if (cdb[1] & 1) { - preamble_len = 4; - size_idx = 3; - - zipbufferb[idx++] = 05; - zipbufferb[idx++] = cdb[2]; - zipbufferb[idx++] = 0; - - idx++; - - switch (cdb[2]) { - case 0x00: - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 0x83; - break; - case 0x83: - if (idx + 24 > max_len) { - zip_data_phase_error(id); - zip_buf_free(id); - return; - } - - zipbufferb[idx++] = 0x02; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 20; - ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ - idx += 20; - - if (idx + 72 > cdb[4]) - goto atapi_out; - zipbufferb[idx++] = 0x02; - zipbufferb[idx++] = 0x01; - zipbufferb[idx++] = 0x00; - zipbufferb[idx++] = 68; - ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ - idx += 8; - if (zip_drives[id].is_250) - ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ - else - ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ - idx += 40; - ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ - idx += 20; - break; - default: - zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); - zip_invalid_field(id); - zip_buf_free(id); - return; - } - } else { - preamble_len = 5; - size_idx = 4; - - memset(zipbufferb, 0, 8); - if (cdb[1] & 0xe0) - zipbufferb[0] = 0x60; /*No physical device on this LUN*/ - else - zipbufferb[0] = 0x00; /*Hard disk*/ - zipbufferb[1] = 0x80; /*Removable*/ - if (zip_drives[id].is_250) { - zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; - } else { - zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ - zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; - } - zipbufferb[4] = 31; - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - zipbufferb[6] = 1; /* 16-bit transfers supported */ - zipbufferb[7] = 0x20; /* Wide bus supported */ - } - - ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ - if (zip_drives[id].is_250) { - ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ - ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ - if (max_len >= 44) - ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ - if (max_len >= 122) - ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ - - } else { - ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ - ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ - } - idx = 36; - - if (max_len == 96) { - zipbufferb[4] = 91; - idx = 96; - } else if (max_len == 128) { - zipbufferb[4] = 0x75; - idx = 128; - } - } - -atapi_out: - zipbufferb[size_idx] = idx - preamble_len; - len=idx; - - len = MIN(len, max_len); - zip_set_buf_len(id, BufLen, &len); - - zip_data_command_finish(id, len, len, max_len, 0); - break; - - case GPCMD_PREVENT_REMOVAL: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_command_complete(id); - break; - - case GPCMD_SEEK_6: - case GPCMD_SEEK_10: - zip_set_phase(id, SCSI_PHASE_STATUS); - - switch(cdb[0]) { - case GPCMD_SEEK_6: - pos = (cdb[2] << 8) | cdb[3]; - break; - case GPCMD_SEEK_10: - pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; - break; - } - zip_seek(id, pos); - zip_command_complete(id); - break; - - case GPCMD_READ_CDROM_CAPACITY: - zip_set_phase(id, SCSI_PHASE_DATA_IN); - - zip_buf_alloc(id, 8); - - if (zip_read_capacity(id, zip[id].current_cdb, zipbufferb, &len) == 0) { - zip_buf_free(id); - return; - } - - zip_set_buf_len(id, BufLen, &len); - - zip_data_command_finish(id, len, len, len, 0); - break; - - case GPCMD_IOMEGA_EJECT: - zip_set_phase(id, SCSI_PHASE_STATUS); - zip_eject(id); - zip_command_complete(id); - break; - - default: - zip_illegal_opcode(id); - break; - } - - /* zip_log("ZIP %i: Phase: %02X, request length: %i\n", zip[id].phase, zip[id].request_length); */ - - if (zip_atapi_phase_to_scsi(id) == SCSI_PHASE_STATUS) - zip_buf_free(id); -} - -/* The command second phase function, needed for Mode Select. */ -uint8_t zip_phase_data_out(uint8_t id) -{ - uint16_t block_desc_len; - uint16_t pos; - - uint8_t error = 0; - uint8_t page, page_len; - - uint16_t i = 0; - - uint8_t hdr_len, val, old_val, ch; - - uint32_t last_to_write = 0, len = 0; - uint32_t c, h, s; - - switch(zip[id].current_cdb[0]) { - case GPCMD_VERIFY_6: - case GPCMD_VERIFY_10: - case GPCMD_VERIFY_12: - break; - case GPCMD_WRITE_6: - case GPCMD_WRITE_10: - case GPCMD_WRITE_AND_VERIFY_10: - case GPCMD_WRITE_12: - case GPCMD_WRITE_AND_VERIFY_12: - if (zip[id].requested_blocks > 0) - zip_blocks(id, &len, 1, 1); - break; - case GPCMD_WRITE_SAME_10: - if (!zip[id].current_cdb[7] && !zip[id].current_cdb[8]) { - if (zip_drives[id].is_250) - last_to_write = (zip_drives[id].medium_size - 1); - else - last_to_write = (ZIP_SECTORS - 1); - } else - last_to_write = zip[id].sector_pos + zip[id].sector_len - 1; - - for (i = zip[id].sector_pos; i <= last_to_write; i++) { - if (zip[id].current_cdb[1] & 2) { - zipbufferb[0] = (i >> 24) & 0xff; - zipbufferb[1] = (i >> 16) & 0xff; - zipbufferb[2] = (i >> 8) & 0xff; - zipbufferb[3] = i & 0xff; - } else if (zip[id].current_cdb[1] & 4) { - /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ - s = (i % 2048); - h = ((i - s) / 2048) % 1; - c = ((i - s) / 2048) / 1; - zipbufferb[0] = (c >> 16) & 0xff; - zipbufferb[1] = (c >> 8) & 0xff; - zipbufferb[2] = c & 0xff; - zipbufferb[3] = h & 0xff; - zipbufferb[4] = (s >> 24) & 0xff; - zipbufferb[5] = (s >> 16) & 0xff; - zipbufferb[6] = (s >> 8) & 0xff; - zipbufferb[7] = s & 0xff; - } - fseek(zip_drives[id].f, zip_drives[id].base + (i << 9), SEEK_SET); - fwrite(zipbufferb, 1, 512, zip_drives[id].f); - } - break; - case GPCMD_MODE_SELECT_6: - case GPCMD_MODE_SELECT_10: - if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_10) - hdr_len = 8; - else - hdr_len = 4; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { - block_desc_len = zipbufferb[2]; - block_desc_len <<= 8; - block_desc_len |= zipbufferb[3]; - } else { - block_desc_len = zipbufferb[6]; - block_desc_len <<= 8; - block_desc_len |= zipbufferb[7]; - } - } else - block_desc_len = 0; - - pos = hdr_len + block_desc_len; - - while(1) { - page = zipbufferb[pos] & 0x3F; - page_len = zipbufferb[pos + 1]; - - pos += 2; - - if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) - error |= 1; - else { - for (i = 0; i < page_len; i++) { - ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; - val = zipbufferb[pos + i]; - old_val = zip_mode_sense_pages_saved[id].pages[page][i + 2]; - if (val != old_val) { - if (ch) - zip_mode_sense_pages_saved[id].pages[page][i + 2] = val; - else - error |= 1; - } - } - } - - pos += page_len; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80; - else - val = zip_mode_sense_pages_default.pages[page][0] & 0x80; - if (zip[id].do_page_save && val) - zip_mode_sense_save(id); - - if (pos >= zip[id].total_length) - break; - } - - if (error) { - zip_invalid_field_pl(id); - return 0; - } - break; - } - - return 1; -} - -/* This is the general ATAPI PIO request function. */ -void zip_pio_request(uint8_t id, uint8_t out) -{ - int old_pos = 0; - int ret = 0; - - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) { - zip_log("ZIP %i: Lowering IDE IRQ\n", id); - ide_irq_lower(&(ide_drives[zip_drives[id].ide_channel])); - } - - zip[id].status = BUSY_STAT; - - if (zip[id].pos >= zip[id].packet_len) { - zip_log("ZIP %i: %i bytes %s, command done\n", id, zip[id].pos, out ? "written" : "read"); - - zip[id].pos = zip[id].request_pos = 0; - if (out) { - ret = zip_phase_data_out(id); - /* If ret = 0 (phase 1 error), then we do not do anything else other than - free the buffer, as the phase and callback have already been set by the - error function. */ - if (ret) - zip_command_complete(id); - } else - zip_command_complete(id); - ui_sb_update_icon(SB_ZIP | id, 0); - zip_buf_free(id); - } else { - zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", id, zip[id].pos, out ? "written" : "read", zip[id].packet_len - zip[id].pos); - - /* Make sure to keep pos, and reset request_pos to 0. */ - /* Also make sure to not reset total_read. */ - - /* If less than (packet length) bytes are remaining, update packet length - accordingly. */ - if ((zip[id].packet_len - zip[id].pos) < (zip[id].max_transfer_len)) - zip[id].max_transfer_len = zip[id].packet_len - zip[id].pos; - - old_pos = zip[id].pos; - zip[id].packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; - zip_command_common(id); - zip[id].pos = old_pos; - zip[id].request_pos = 0; - } -} - -void zip_phase_callback(uint8_t id); - -int zip_read_from_ide_dma(uint8_t channel) -{ - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) - return 0; - - if (ide_bus_master_write) { - if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) - return 0; - else - return 1; - } - - return 0; -} - -int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; - int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; - - if (id > ZIP_NUM) - return 0; - - zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(zipbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); - return 1; -} - -void zip_irq_raise(uint8_t id) -{ - if (zip_drives[id].bus_type < ZIP_BUS_SCSI) - ide_irq_raise(&(ide_drives[zip_drives[id].ide_channel])); -} - -int zip_read_from_dma(uint8_t id) -{ - int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; - - int ret = 0; - - int in_data_length = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) - ret = zip_read_from_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - else - ret = zip_read_from_ide_dma(zip_drives[id].ide_channel); - - if (!ret) - return 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - in_data_length = *BufLen; - zip_log("ZIP %i: SCSI Input data length: %i\n", id, in_data_length); - } else { - in_data_length = zip[id].max_transfer_len; - zip_log("ZIP %i: ATAPI Input data length: %i\n", id, in_data_length); - } - - ret = zip_phase_data_out(id); - - if (ret || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { - zip_buf_free(id); - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].status = READY_STAT; - zip[id].phase = 3; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - if (ret) - return 1; - else - return 0; - } - - return 0; -} - -int zip_write_to_ide_dma(uint8_t channel) -{ - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) { - zip_log("ZIP %i: Drive not found\n", id); - return 0; - } - - if (ide_bus_master_read) { - if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) - return 0; - else - return 1; - } - - return 0; -} - -int zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) -{ - uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; - int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; - - if (id > ZIP_NUM) - return 0; - - zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); - memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, zipbufferb, *BufLen); - zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], zipbufferb[6], zipbufferb[7]); - zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); - return 1; -} - -int zip_write_to_dma(uint8_t id) -{ - int ret = 0; - - if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { - zip_log("Write to SCSI DMA: (%02X:%02X)\n", zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - ret = zip_write_to_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); - } else - ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); - - if (ret || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { - zip_buf_free(id); - zip[id].packet_status = ZIP_PHASE_COMPLETE; - zip[id].status = READY_STAT; - zip[id].phase = 3; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - if (ret) - return 1; - else - return 0; - } - - return 0; -} - -/* If the result is 1, issue an IRQ, otherwise not. */ -void zip_phase_callback(uint8_t id) -{ - switch(zip[id].packet_status) { - case ZIP_PHASE_IDLE: - zip_log("ZIP %i: ZIP_PHASE_IDLE\n", id); - zip[id].pos=0; - zip[id].phase = 1; - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - return; - case ZIP_PHASE_COMMAND: - zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", id); - zip[id].status = BUSY_STAT | (zip[id].status &ERR_STAT); - memcpy(zip[id].atapi_cdb, zipbufferb, zip[id].cdb_len); - zip_command(id, zip[id].atapi_cdb); - return; - case ZIP_PHASE_COMPLETE: - zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", id); - zip[id].status = READY_STAT; - zip[id].phase = 3; - zip[id].packet_status = 0xFF; - ui_sb_update_icon(SB_ZIP | id, 0); - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_OUT: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", id); - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - zip[id].phase = 0; - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_OUT_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); - zip_read_from_dma(id); - return; - case ZIP_PHASE_DATA_IN: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); - zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); - zip[id].phase = 2; - zip_irq_raise(id); - return; - case ZIP_PHASE_DATA_IN_DMA: - zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); - zip_write_to_dma(id); - return; - case ZIP_PHASE_ERROR: - zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); - zip[id].status = READY_STAT | ERR_STAT; - zip[id].phase = 3; - zip[id].packet_status = 0xFF; - zip_irq_raise(id); - ui_sb_update_icon(SB_ZIP | id, 0); - return; - } -} - -/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ -uint32_t zip_read(uint8_t channel, int length) -{ - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - uint8_t id = atapi_zip_drives[channel]; - - uint32_t temp = 0; - - if (id > ZIP_NUM) - return 0; - - zipbufferw = (uint16_t *) zipbufferb; - zipbufferl = (uint32_t *) zipbufferb; - - if (!zipbufferb) - return 0; - - /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, - which can happen when issuing media access commands with an allocated length below minimum request length - (which is 1 sector = 512 bytes). */ - switch(length) { - case 1: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferb[zip[id].pos] : 0; - zip[id].pos++; - zip[id].request_pos++; - break; - case 2: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferw[zip[id].pos >> 1] : 0; - zip[id].pos += 2; - zip[id].request_pos += 2; - break; - case 4: - temp = (zip[id].pos < zip[id].packet_len) ? zipbufferl[zip[id].pos >> 2] : 0; - zip[id].pos += 4; - zip[id].request_pos += 4; - break; - default: - return 0; - } - - if (zip[id].packet_status == ZIP_PHASE_DATA_IN) { - if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { - /* Time for a DRQ. */ - // zip_log("ZIP %i: Issuing read callback\n", id); - zip_pio_request(id, 0); - } - // zip_log("ZIP %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, temp, zip[id].pos, zip[id].request_pos); - return temp; - } else { - // zip_log("ZIP %i: Returning zero (buffer position: %i, request position: %i)\n", id, zip[id].pos, zip[id].request_pos); - return 0; - } -} - -/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ -void zip_write(uint8_t channel, uint32_t val, int length) -{ - uint16_t *zipbufferw; - uint32_t *zipbufferl; - - uint8_t id = atapi_zip_drives[channel]; - - if (id > ZIP_NUM) - return; - - if (zip[id].packet_status == ZIP_PHASE_IDLE) { - if (!zipbufferb) - zip_buf_alloc(id, zip[id].cdb_len); - } - - zipbufferw = (uint16_t *) zipbufferb; - zipbufferl = (uint32_t *) zipbufferb; - - if (!zipbufferb) - return; - - switch(length) { - case 1: - zipbufferb[zip[id].pos] = val & 0xff; - zip[id].pos++; - zip[id].request_pos++; - break; - case 2: - zipbufferw[zip[id].pos >> 1] = val & 0xffff; - zip[id].pos += 2; - zip[id].request_pos += 2; - break; - case 4: - zipbufferl[zip[id].pos >> 2] = val; - zip[id].pos += 4; - zip[id].request_pos += 4; - break; - default: - return; - } - - if (zip[id].packet_status == ZIP_PHASE_DATA_OUT) { - if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { - /* Time for a DRQ. */ - zip_pio_request(id, 1); - } - return; - } else if (zip[id].packet_status == ZIP_PHASE_IDLE) { - if (zip[id].pos >= zip[id].cdb_len) { - zip[id].pos=0; - zip[id].status = BUSY_STAT; - zip[id].packet_status = ZIP_PHASE_COMMAND; - timer_process(); - zip_phase_callback(id); - timer_update_outstanding(); - } - return; - } -} - - -/* Peform a master init on the entire module. */ -void -zip_global_init(void) -{ - /* Clear the global data. */ - memset(zip, 0x00, sizeof(zip)); - memset(zip_drives, 0x00, sizeof(zip_drives)); -} - - -void -zip_hard_reset(void) -{ - int c; - - for (c=0; c> 5) & 7) != zip_drives[id].scsi_device_lun) { + zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((zip[id].request_length >> 5) & 7)); + zip_invalid_lun(id); + return 0; + } + } + + if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { + zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? "SCSI" : ((zip_drives[id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA) ? "ATAPI PIO/DMA" : "ATAPI PIO")); + + zip_illegal_opcode(id); + return 0; + } + + if ((zip_drives[id].bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { + zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); + zip_illegal_opcode(id); + return 0; + } + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { + zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); + zip_illegal_opcode(id); + return 0; + } + + ready = (zip_drives[id].f != NULL); + + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && zip[id].unit_attention) + zip[id].unit_attention = 0; + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (zip[id].unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { + /* zip_log("ZIP %i: Unit attention now 2\n", id); */ + zip[id].unit_attention = 2; + zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); + zip_unit_attention(id); + return 0; + } + } + else if (zip[id].unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* zip_log("ZIP %i: Unit attention now 0\n", id); */ + zip[id].unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + zip_sense_clear(id, cdb[0]); + + /* Next it's time for NOT READY. */ + if (!ready) + zip[id].media_status = MEC_MEDIA_REMOVAL; + else + zip[id].media_status = (zip[id].unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { + zip_log("ZIP %i: Not ready (%02X)\n", id, cdb[0]); + zip_not_ready(id); + return 0; + } + + zip_log("ZIP %i: Continuing with command %02X\n", id, cdb[0]); + + return 1; +} + +void zip_clear_callback(uint8_t channel) +{ + uint8_t id = atapi_zip_drives[channel]; + + if (id < ZIP_NUM) + { + zip[id].callback = 0LL; + zip_set_callback(id); + } +} + +static void zip_seek(uint8_t id, uint32_t pos) +{ + /* zip_log("ZIP %i: Seek %08X\n", id, pos); */ + zip[id].sector_pos = pos; +} + +static void zip_rezero(uint8_t id) +{ + zip[id].sector_pos = zip[id].sector_len = 0; + zip_seek(id, 0); +} + +void zip_reset(uint8_t id) +{ + zip_rezero(id); + zip[id].status = 0; + zip[id].callback = 0LL; + zip_set_callback(id); + zip[id].packet_status = 0xff; + zip[id].unit_attention = 0; +} + +void zip_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, zip[id].sense, alloc_length); + else { + buffer[1] = zip_sense_key; + buffer[2] = zip_asc; + buffer[3] = zip_ascq; + } + } + + buffer[0] = desc ? 0x72 : 0x70; + + if (zip[id].unit_attention && (zip_sense_key == 0)) { + buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; + buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[desc ? 3 : 13]=0; + } + + zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); + + if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + zip[id].unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + zip_sense_clear(id, GPCMD_REQUEST_SENSE); +} + +void zip_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + int ready = 0; + + ready = (zip_drives[id].f != NULL); + + if (!ready && zip[id].unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + zip[id].unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + + zip_request_sense(id, buffer, alloc_length, 0); +} + +void zip_set_buf_len(uint8_t id, int32_t *BufLen, uint32_t *src_len) +{ + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + zip_log("ZIP %i: Actual transfer length: %i\n", id, *BufLen); + } +} + +void zip_buf_alloc(uint8_t id, uint32_t len) +{ + zip_log("ZIP %i: Allocated buffer length: %i\n", id, len); + zipbufferb = (uint8_t *) malloc(len); +} + +void zip_buf_free(uint8_t id) +{ + if (zipbufferb) { + zip_log("ZIP %i: Freeing buffer...\n", id); + free(zipbufferb); + zipbufferb = NULL; + } +} + +void zip_command(uint8_t id, uint8_t *cdb) +{ + uint32_t len; + int pos=0; + uint32_t max_len; + unsigned idx = 0; + unsigned size_idx; + unsigned preamble_len; + uint32_t alloc_length; + int block_desc = 0; + int ret; + int32_t blen = 0; + int32_t *BufLen; + uint32_t i = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + zip[id].status &= ~ERR_STAT; + } else { + BufLen = &blen; + zip[id].error = 0; + } + + zip[id].packet_len = 0; + zip[id].request_pos = 0; + + zip[id].data_pos = 0; + + memcpy(zip[id].current_cdb, cdb, zip[id].cdb_len); + + if (cdb[0] != 0) { + zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", id, cdb[0], zip_sense_key, zip_asc, zip_ascq, zip[id].unit_attention); + zip_log("ZIP %i: Request length: %04X\n", id, zip[id].request_length); + + zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + zip[id].sector_len = 0; + + zip_set_phase(id, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (zip_pre_execution_check(id, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + zip_invalid_field(id); + return; + } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_FORMAT_UNIT: + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) + { + zip_write_protected(id); + return; + } + + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_IOMEGA_SENSE: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(id, 256); + zip_set_buf_len(id, BufLen, &max_len); + memset(zipbufferb, 0, 256); + if (cdb[2] == 1) { + /* This page is related to disk health status - setting + this page to 0 makes disk health read as "marginal". */ + zipbufferb[0] = 0x58; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x58; i++) + zipbufferb[i + 0x02] = 0xff; + } else if (cdb[2] == 2) { + zipbufferb[0] = 0x3d; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x13; i++) + zipbufferb[i + 0x02] = 0x00; + zipbufferb[0x15] = 0x00; + if (zip_drives[id].read_only) + zipbufferb[0x15] |= 0x02; + for (i = 0x00; i < 0x27; i++) + zipbufferb[i + 0x16] = 0x00; + } else { + zip_invalid_field(id); + zip_buf_free(id); + return; + } + zip_data_command_finish(id, 18, 18, cdb[4], 0); + break; + + case GPCMD_REZERO_UNIT: + zip[id].sector_pos = zip[id].sector_len = 0; + zip_seek(id, 0); + zip_set_phase(id, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + zip_set_phase(id, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(id, 256); + zip_set_buf_len(id, BufLen, &max_len); + len = (cdb[1] & 1) ? 8 : 18; + zip_request_sense(id, zipbufferb, max_len, cdb[1] & 1); + zip_data_command_finish(id, len, len, cdb[4], 0); + break; + + case GPCMD_SET_SPEED: + case GPCMD_SET_SPEED_ALT: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_MECHANISM_STATUS: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + zip_buf_alloc(id, 8); + + zip_set_buf_len(id, BufLen, &len); + + memset(zipbufferb, 0, 8); + zipbufferb[5] = 1; + + zip_data_command_finish(id, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + alloc_length = 512; + + switch(cdb[0]) { + case GPCMD_READ_6: + zip[id].sector_len = cdb[4]; + zip[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); + break; + case GPCMD_READ_10: + zip[id].sector_len = (cdb[7] << 8) | cdb[8]; + zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); + break; + case GPCMD_READ_12: + zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (!zip[id].sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = zip[id].sector_len; + zip[id].requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + zip[id].packet_len = max_len * alloc_length; + zip_buf_alloc(id, zip[id].packet_len); + + ret = zip_blocks(id, &alloc_length, 1, 0); + if (ret <= 0) { + zip_buf_free(id); + return; + } + + zip[id].requested_blocks = max_len; + zip[id].packet_len = alloc_length; + + zip_set_buf_len(id, BufLen, &zip[id].packet_len); + + zip_data_command_finish(id, alloc_length, 512, alloc_length, 0); + + zip[id].all_blocks_total = zip[id].block_total; + if (zip[id].packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) + { + zip_write_protected(id); + return; + } + + switch(cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + zip[id].sector_len = cdb[4]; + zip[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + zip[id].sector_len = (cdb[7] << 8) | cdb[8]; + zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, zip[id].sector_len, zip[id].sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + zip[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + zip[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (zip_drives[id].is_250) { + if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) + { + zip_lba_out_of_range(id); + return; + } + } else { + if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) + { + zip_lba_out_of_range(id); + return; + } + } + + if (!zip[id].sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = zip[id].sector_len; + zip[id].requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + zip[id].packet_len = max_len * alloc_length; + zip_buf_alloc(id, zip[id].packet_len); + + zip[id].requested_blocks = max_len; + zip[id].packet_len = max_len << 9; + + zip_set_buf_len(id, BufLen, &zip[id].packet_len); + + zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); + + zip[id].all_blocks_total = zip[id].block_total; + if (zip[id].packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_WRITE_SAME_10: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((cdb[1] & 6) == 6) + { + zip_invalid_field(id); + return; + } + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) + { + zip_write_protected(id); + return; + } + + zip[id].sector_len = (cdb[7] << 8) | cdb[8]; + zip[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + if (zip_drives[id].is_250) { + if ((zip[id].sector_pos >= zip_drives[id].medium_size) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= zip_drives[id].medium_size)) + { + zip_lba_out_of_range(id); + return; + } + } else { + if ((zip[id].sector_pos >= ZIP_SECTORS) || ((zip[id].sector_pos + zip[id].sector_len - 1) >= ZIP_SECTORS)) + { + zip_lba_out_of_range(id); + return; + } + } + + if (!zip[id].sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = zip[id].sector_len; + zip[id].requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + zip[id].packet_len = max_len * alloc_length; + zip_buf_alloc(id, zip[id].packet_len); + + zip[id].requested_blocks = max_len; + zip[id].packet_len = alloc_length; + + zip_set_buf_len(id, BufLen, &zip[id].packet_len); + + zip_data_command_finish(id, zip[id].packet_len, 512, zip[id].packet_len, 1); + + zip[id].all_blocks_total = zip[id].block_total; + if (zip[id].packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; + zip_buf_alloc(id, 256); + } else { + len = (cdb[8] | (cdb[7] << 8)); + zip_buf_alloc(id, 65536); + } + + zip[id].current_page_code = cdb[2] & 0x3F; + zip_log("Mode sense page: %02X\n", zip[id].current_page_code); + + if (!(zip_mode_sense_page_flags & (1LL << zip[id].current_page_code))) { + zip_invalid_field(id); + zip_buf_free(id); + return; + } + + memset(zipbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = zip_mode_sense(id, zipbufferb, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0] = len - 1; + zipbufferb[1] = 0; + if (block_desc) + zipbufferb[3] = 8; + } else { + len = zip_mode_sense(id, zipbufferb, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0]=(len - 2) >> 8; + zipbufferb[1]=(len - 2) & 255; + zipbufferb[2] = 0; + if (block_desc) { + zipbufferb[6] = 0; + zipbufferb[7] = 8; + } + } + + zip_set_buf_len(id, BufLen, &len); + + zip_log("ZIP %i: Reading mode page: %02X...\n", id, cdb[2]); + + zip_data_command_finish(id, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + zip_buf_alloc(id, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + zip_buf_alloc(id, 65536); + } + + zip_set_buf_len(id, BufLen, &len); + + zip[id].total_length = len; + zip[id].do_page_save = cdb[1] & 1; + + zip[id].current_page_pos = 0; + + zip_data_command_finish(id, len, len, len, 1); + return; + + case GPCMD_START_STOP_UNIT: + zip_set_phase(id, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + zip_eject(id); /* The Iomega Windows 9x drivers require this. */ + break; + case 1: /* Start the disc and read the TOC. */ + break; + case 2: /* Eject the disc if possible. */ + /* zip_eject(id); */ + break; + case 3: /* Load the disc (close tray). */ + zip_reload(id); + break; + } + + zip_command_complete(id); + break; + + case GPCMD_INQUIRY: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + zip_buf_alloc(id, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + zipbufferb[idx++] = 05; + zipbufferb[idx++] = cdb[2]; + zipbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + zip_data_phase_error(id); + zip_buf_free(id); + return; + } + + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 20; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x01; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 68; + ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ + idx += 8; + if (zip_drives[id].is_250) + ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ + else + ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ + idx += 40; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + zip_invalid_field(id); + zip_buf_free(id); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(zipbufferb, 0, 8); + if (cdb[1] & 0xe0) + zipbufferb[0] = 0x60; /*No physical device on this LUN*/ + else + zipbufferb[0] = 0x00; /*Hard disk*/ + zipbufferb[1] = 0x80; /*Removable*/ + if (zip_drives[id].is_250) { + zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } else { + zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } + zipbufferb[4] = 31; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zipbufferb[6] = 1; /* 16-bit transfers supported */ + zipbufferb[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ + if (zip_drives[id].is_250) { + ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ + if (max_len >= 44) + ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ + if (max_len >= 122) + ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ + + } else { + ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ + } + idx = 36; + + if (max_len == 96) { + zipbufferb[4] = 91; + idx = 96; + } else if (max_len == 128) { + zipbufferb[4] = 0x75; + idx = 128; + } + } + +atapi_out: + zipbufferb[size_idx] = idx - preamble_len; + len=idx; + + len = MIN(len, max_len); + zip_set_buf_len(id, BufLen, &len); + + zip_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + zip_set_phase(id, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + zip_seek(id, pos); + zip_command_complete(id); + break; + + case GPCMD_READ_CDROM_CAPACITY: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + zip_buf_alloc(id, 8); + + if (zip_read_capacity(id, zip[id].current_cdb, zipbufferb, &len) == 0) { + zip_buf_free(id); + return; + } + + zip_set_buf_len(id, BufLen, &len); + + zip_data_command_finish(id, len, len, len, 0); + break; + + case GPCMD_IOMEGA_EJECT: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_eject(id); + zip_command_complete(id); + break; + + case GPCMD_READ_FORMAT_CAPACITIES: + len = (cdb[7] << 8) | cdb[8]; + + zip_buf_alloc(id, len); + memset(zipbufferb, 0, len); + + pos = 0; + + /* List header */ + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 0; + if (zip_drives[id].f != NULL) + zipbufferb[pos++] = 16; + else + zipbufferb[pos++] = 8; + + /* Current/Maximum capacity header */ + if (zip_drives[id].is_250) { + if (zip_drives[id].f != NULL) { + zipbufferb[pos++] = (zip_drives[id].medium_size >> 24) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 16) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 8) & 0xff; + zipbufferb[pos++] = zip_drives[id].medium_size & 0xff; + zipbufferb[pos++] = 2; /* Current medium capacity */ + } else { + zipbufferb[pos++] = (ZIP_250_SECTORS >> 24) & 0xff; + zipbufferb[pos++] = (ZIP_250_SECTORS >> 16) & 0xff; + zipbufferb[pos++] = (ZIP_250_SECTORS >> 8) & 0xff; + zipbufferb[pos++] = ZIP_250_SECTORS & 0xff; + zipbufferb[pos++] = 3; /* Maximum medium capacity */ + } + } else { + zipbufferb[pos++] = (ZIP_SECTORS >> 24) & 0xff; + zipbufferb[pos++] = (ZIP_SECTORS >> 16) & 0xff; + zipbufferb[pos++] = (ZIP_SECTORS >> 8) & 0xff; + zipbufferb[pos++] = ZIP_SECTORS & 0xff; + if (zip_drives[id].f != NULL) + zipbufferb[pos++] = 2; + else + zipbufferb[pos++] = 3; + } + + zipbufferb[pos++] = 512 >> 16; + zipbufferb[pos++] = 512 >> 8; + zipbufferb[pos++] = 512 & 0xff; + + if (zip_drives[id].f != NULL) { + /* Formattable capacity descriptor */ + zipbufferb[pos++] = (zip_drives[id].medium_size >> 24) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 16) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 8) & 0xff; + zipbufferb[pos++] = zip_drives[id].medium_size & 0xff; + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 512 >> 16; + zipbufferb[pos++] = 512 >> 8; + zipbufferb[pos++] = 512 & 0xff; + } + + zip_set_buf_len(id, BufLen, &len); + + zip_data_command_finish(id, len, len, len, 0); + break; + + default: + zip_illegal_opcode(id); + break; + } + + /* zip_log("ZIP %i: Phase: %02X, request length: %i\n", zip[id].phase, zip[id].request_length); */ + + if (zip_atapi_phase_to_scsi(id) == SCSI_PHASE_STATUS) + zip_buf_free(id); +} + +/* The command second phase function, needed for Mode Select. */ +uint8_t zip_phase_data_out(uint8_t id) +{ + uint16_t block_desc_len; + uint16_t pos; + + uint8_t error = 0; + uint8_t page, page_len; + + uint16_t i = 0; + + uint8_t hdr_len, val, old_val, ch; + + uint32_t last_to_write = 0, len = 0; + uint32_t c, h, s; + + switch(zip[id].current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if (zip[id].requested_blocks > 0) + zip_blocks(id, &len, 1, 1); + break; + case GPCMD_WRITE_SAME_10: + if (!zip[id].current_cdb[7] && !zip[id].current_cdb[8]) { + if (zip_drives[id].is_250) + last_to_write = (zip_drives[id].medium_size - 1); + else + last_to_write = (ZIP_SECTORS - 1); + } else + last_to_write = zip[id].sector_pos + zip[id].sector_len - 1; + + for (i = zip[id].sector_pos; i <= last_to_write; i++) { + if (zip[id].current_cdb[1] & 2) { + zipbufferb[0] = (i >> 24) & 0xff; + zipbufferb[1] = (i >> 16) & 0xff; + zipbufferb[2] = (i >> 8) & 0xff; + zipbufferb[3] = i & 0xff; + } else if (zip[id].current_cdb[1] & 4) { + /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ + s = (i % 2048); + h = ((i - s) / 2048) % 1; + c = ((i - s) / 2048) / 1; + zipbufferb[0] = (c >> 16) & 0xff; + zipbufferb[1] = (c >> 8) & 0xff; + zipbufferb[2] = c & 0xff; + zipbufferb[3] = h & 0xff; + zipbufferb[4] = (s >> 24) & 0xff; + zipbufferb[5] = (s >> 16) & 0xff; + zipbufferb[6] = (s >> 8) & 0xff; + zipbufferb[7] = s & 0xff; + } + fseek(zip_drives[id].f, zip_drives[id].base + (i << 9), SEEK_SET); + fwrite(zipbufferb, 1, 512, zip_drives[id].f); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (zip[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = zipbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[3]; + } else { + block_desc_len = zipbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[7]; + } + } else + block_desc_len = 0; + + pos = hdr_len + block_desc_len; + + while(1) { + page = zipbufferb[pos] & 0x3F; + page_len = zipbufferb[pos + 1]; + + pos += 2; + + if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; + val = zipbufferb[pos + i]; + old_val = zip_mode_sense_pages_saved[id].pages[page][i + 2]; + if (val != old_val) { + if (ch) + zip_mode_sense_pages_saved[id].pages[page][i + 2] = val; + else + error |= 1; + } + } + } + + pos += page_len; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = zip_mode_sense_pages_default.pages[page][0] & 0x80; + if (zip[id].do_page_save && val) + zip_mode_sense_save(id); + + if (pos >= zip[id].total_length) + break; + } + + if (error) { + zip_invalid_field_pl(id); + return 0; + } + break; + } + + return 1; +} + +/* This is the general ATAPI PIO request function. */ +void zip_pio_request(uint8_t id, uint8_t out) +{ + int old_pos = 0; + int ret = 0; + + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) { + zip_log("ZIP %i: Lowering IDE IRQ\n", id); + ide_irq_lower(&(ide_drives[zip_drives[id].ide_channel])); + } + + zip[id].status = BUSY_STAT; + + if (zip[id].pos >= zip[id].packet_len) { + zip_log("ZIP %i: %i bytes %s, command done\n", id, zip[id].pos, out ? "written" : "read"); + + zip[id].pos = zip[id].request_pos = 0; + if (out) { + ret = zip_phase_data_out(id); + /* If ret = 0 (phase 1 error), then we do not do anything else other than + free the buffer, as the phase and callback have already been set by the + error function. */ + if (ret) + zip_command_complete(id); + } else + zip_command_complete(id); + ui_sb_update_icon(SB_ZIP | id, 0); + zip_buf_free(id); + } else { + zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", id, zip[id].pos, out ? "written" : "read", zip[id].packet_len - zip[id].pos); + + /* Make sure to keep pos, and reset request_pos to 0. */ + /* Also make sure to not reset total_read. */ + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((zip[id].packet_len - zip[id].pos) < (zip[id].max_transfer_len)) + zip[id].max_transfer_len = zip[id].packet_len - zip[id].pos; + + old_pos = zip[id].pos; + zip[id].packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; + zip_command_common(id); + zip[id].pos = old_pos; + zip[id].request_pos = 0; + } +} + +void zip_phase_callback(uint8_t id); + +int zip_read_from_ide_dma(uint8_t channel) +{ + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) + return 0; + + if (ide_bus_master_write) { + if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) + return 0; + else + return 1; + } + + return 0; +} + +int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(zipbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); + return 1; +} + +void zip_irq_raise(uint8_t id) +{ + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + ide_irq_raise(&(ide_drives[zip_drives[id].ide_channel])); +} + +int zip_read_from_dma(uint8_t id) +{ + int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + + int ret = 0; + + int in_data_length = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + ret = zip_read_from_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + else + ret = zip_read_from_ide_dma(zip_drives[id].ide_channel); + + if (!ret) + return 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + in_data_length = *BufLen; + zip_log("ZIP %i: SCSI Input data length: %i\n", id, in_data_length); + } else { + in_data_length = zip[id].max_transfer_len; + zip_log("ZIP %i: ATAPI Input data length: %i\n", id, in_data_length); + } + + ret = zip_phase_data_out(id); + + if (ret || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { + zip_buf_free(id); + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].status = READY_STAT; + zip[id].phase = 3; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + if (ret) + return 1; + else + return 0; + } + + return 0; +} + +int zip_write_to_ide_dma(uint8_t channel) +{ + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) { + zip_log("ZIP %i: Drive not found\n", id); + return 0; + } + + if (ide_bus_master_read) { + if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) + return 0; + else + return 1; + } + + return 0; +} + +int zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, zipbufferb, *BufLen); + zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], zipbufferb[6], zipbufferb[7]); + zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); + return 1; +} + +int zip_write_to_dma(uint8_t id) +{ + int ret = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zip_log("Write to SCSI DMA: (%02X:%02X)\n", zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + ret = zip_write_to_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + } else + ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); + + if (ret || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { + zip_buf_free(id); + zip[id].packet_status = ZIP_PHASE_COMPLETE; + zip[id].status = READY_STAT; + zip[id].phase = 3; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + if (ret) + return 1; + else + return 0; + } + + return 0; +} + +/* If the result is 1, issue an IRQ, otherwise not. */ +void zip_phase_callback(uint8_t id) +{ + switch(zip[id].packet_status) { + case ZIP_PHASE_IDLE: + zip_log("ZIP %i: ZIP_PHASE_IDLE\n", id); + zip[id].pos=0; + zip[id].phase = 1; + zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); + return; + case ZIP_PHASE_COMMAND: + zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", id); + zip[id].status = BUSY_STAT | (zip[id].status &ERR_STAT); + memcpy(zip[id].atapi_cdb, zipbufferb, zip[id].cdb_len); + zip_command(id, zip[id].atapi_cdb); + return; + case ZIP_PHASE_COMPLETE: + zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", id); + zip[id].status = READY_STAT; + zip[id].phase = 3; + zip[id].packet_status = 0xFF; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_OUT: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", id); + zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); + zip[id].phase = 0; + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_OUT_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); + zip_read_from_dma(id); + return; + case ZIP_PHASE_DATA_IN: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); + zip[id].status = READY_STAT | DRQ_STAT | (zip[id].status & ERR_STAT); + zip[id].phase = 2; + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_IN_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); + zip_write_to_dma(id); + return; + case ZIP_PHASE_ERROR: + zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); + zip[id].status = READY_STAT | ERR_STAT; + zip[id].phase = 3; + zip[id].packet_status = 0xFF; + zip_irq_raise(id); + ui_sb_update_icon(SB_ZIP | id, 0); + return; + } +} + +/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ +uint32_t zip_read(uint8_t channel, int length) +{ + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + uint32_t temp = 0; + + if (id > ZIP_NUM) + return 0; + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return 0; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 512 bytes). */ + switch(length) { + case 1: + temp = (zip[id].pos < zip[id].packet_len) ? zipbufferb[zip[id].pos] : 0; + zip[id].pos++; + zip[id].request_pos++; + break; + case 2: + temp = (zip[id].pos < zip[id].packet_len) ? zipbufferw[zip[id].pos >> 1] : 0; + zip[id].pos += 2; + zip[id].request_pos += 2; + break; + case 4: + temp = (zip[id].pos < zip[id].packet_len) ? zipbufferl[zip[id].pos >> 2] : 0; + zip[id].pos += 4; + zip[id].request_pos += 4; + break; + default: + return 0; + } + + if (zip[id].packet_status == ZIP_PHASE_DATA_IN) { + if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { + /* Time for a DRQ. */ + // zip_log("ZIP %i: Issuing read callback\n", id); + zip_pio_request(id, 0); + } + // zip_log("ZIP %i: Returning: %02X (buffer position: %i, request position: %i)\n", id, temp, zip[id].pos, zip[id].request_pos); + return temp; + } else { + // zip_log("ZIP %i: Returning zero (buffer position: %i, request position: %i)\n", id, zip[id].pos, zip[id].request_pos); + return 0; + } +} + +/* Reimplement as 8-bit due to reimplementation of IDE data read and write. */ +void zip_write(uint8_t channel, uint32_t val, int length) +{ + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) + return; + + if (zip[id].packet_status == ZIP_PHASE_IDLE) { + if (!zipbufferb) + zip_buf_alloc(id, zip[id].cdb_len); + } + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return; + + switch(length) { + case 1: + zipbufferb[zip[id].pos] = val & 0xff; + zip[id].pos++; + zip[id].request_pos++; + break; + case 2: + zipbufferw[zip[id].pos >> 1] = val & 0xffff; + zip[id].pos += 2; + zip[id].request_pos += 2; + break; + case 4: + zipbufferl[zip[id].pos >> 2] = val; + zip[id].pos += 4; + zip[id].request_pos += 4; + break; + default: + return; + } + + if (zip[id].packet_status == ZIP_PHASE_DATA_OUT) { + if ((zip[id].request_pos >= zip[id].max_transfer_len) || (zip[id].pos >= zip[id].packet_len)) { + /* Time for a DRQ. */ + zip_pio_request(id, 1); + } + return; + } else if (zip[id].packet_status == ZIP_PHASE_IDLE) { + if (zip[id].pos >= zip[id].cdb_len) { + zip[id].pos=0; + zip[id].status = BUSY_STAT; + zip[id].packet_status = ZIP_PHASE_COMMAND; + timer_process(); + zip_phase_callback(id); + timer_update_outstanding(); + } + return; + } +} + + +/* Peform a master init on the entire module. */ +void +zip_global_init(void) +{ + /* Clear the global data. */ + memset(zip, 0x00, sizeof(zip)); + memset(zip_drives, 0x00, sizeof(zip_drives)); +} + + +void +zip_hard_reset(void) +{ + int c; + + for (c=0; c * @@ -100,6 +100,7 @@ extern uint64_t source_hwnd; /* (O) -H hwnd */ #ifdef USE_WX extern int video_fps; /* (O) render speed in fps */ #endif +extern int config_ro; /* (O) dont modify cfg file */ extern int settings_only; /* (O) only the settings dlg */ extern wchar_t log_path[1024]; /* (O) full path of logfile */ @@ -155,8 +156,9 @@ extern int serial_do_log; extern int nic_do_log; #endif -extern char emu_title[128]; /* full name of application */ -extern char emu_version[128]; /* version ID string */ +extern char emu_title[64]; /* full name of application */ +extern char emu_version[32]; /* short version ID string */ +extern char emu_fullversion[128]; /* full version ID string */ extern wchar_t emu_path[1024]; /* emu installation path */ extern wchar_t usr_path[1024]; /* path (dir) of user data */ extern wchar_t cfg_path[1024]; /* full path of config file */ @@ -174,8 +176,8 @@ extern int config_changed; /* config has changed */ extern void pclog_ex(const char *fmt, va_list); #endif extern void pclog(const char *fmt, ...); -extern void fatal(const char *fmt, ...); extern void pc_version(const char *platform); +extern void fatal(const char *fmt, ...); extern int pc_init_modules(void); extern int pc_init(int argc, wchar_t *argv[]); extern void pc_close(void *threadid); diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index f5224a5..6c5f34e 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -32,7 +32,7 @@ * BIOSES: I need to re-do the bios.txt format so we can load non-BIOS * ROM files for a given machine, such as font roms here.. * - * Version: @(#)m_amstrad.c 1.0.6 2018/03/20 + * Version: @(#)m_amstrad.c 1.0.7 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -542,9 +542,6 @@ vid_init_1512(amstrad_t *ams) vid->cgacol = 7; vid->cgamode = 0x12; - /* Load the PC1512 CGA Character Set ROM. */ - loadfont(L"roms/machines/amstrad/pc1512/40078", 2); - timer_add(vid_poll_1512, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, vid_read_1512, NULL, NULL, vid_write_1512, NULL, NULL, @@ -691,7 +688,7 @@ vid_poll_1640(void *priv) static void -vid_init_1640(amstrad_t *ams) +vid_init_1640(amstrad_t *ams, wchar_t *fn, int sz) { amsvid_t *vid; @@ -699,8 +696,8 @@ vid_init_1640(amstrad_t *ams) vid = (amsvid_t *)malloc(sizeof(amsvid_t)); memset(vid, 0x00, sizeof(amsvid_t)); - rom_init(&vid->bios_rom, L"roms/machines/amstrad/pc1640/40100", - 0xc0000, 0x8000, 0x7fff, 0, 0); + /* Load the BIOS. */ + rom_init(&vid->bios_rom, fn, 0xc0000, sz, sz - 1, 0, 0); ega_init(&vid->ega, 9, 0); vid->cga.vram = vid->ega.vram; @@ -844,9 +841,6 @@ vid_init_200(amstrad_t *ams) cga->vram = malloc(0x4000); cga_init(cga); - /* Load the PC200 CGA Character Set ROM. */ - loadfont(L"roms/machines/amstrad/pc200/40109.bin", 1); - mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); io_sethandler(0x03d0, 16, @@ -1222,14 +1216,15 @@ ams_read(uint16_t port, void *priv) void -machine_amstrad_init(const machine_t *model) +machine_amstrad_init(const machine_t *model, void *arg) { + romdef_t *roms = (romdef_t *)arg; amstrad_t *ams; ams = (amstrad_t *)malloc(sizeof(amstrad_t)); memset(ams, 0x00, sizeof(amstrad_t)); - machine_common_init(model); + machine_common_init(model, arg); nmi_init(); @@ -1253,6 +1248,10 @@ machine_amstrad_init(const machine_t *model) case ROM_PC1512: device_add(&fdc_xt_device); if (vid_card == VID_INTERNAL) { + /* Load the PC1512 CGA Character Set ROM. */ + loadfont(roms->fontfn, roms->fontnum); + + /* Initialize the internal CGA controller. */ vid_init_1512(ams); device_add_ex(&vid_1512_device, ams->vid); } @@ -1261,7 +1260,8 @@ machine_amstrad_init(const machine_t *model) case ROM_PC1640: device_add(&fdc_xt_device); if (vid_card == VID_INTERNAL) { - vid_init_1640(ams); + /* Load the BIOS for the internal CGA/EGA. */ + vid_init_1640(ams, roms->vidfn, roms->vidsz); device_add_ex(&vid_1640_device, ams->vid); } break; @@ -1269,6 +1269,9 @@ machine_amstrad_init(const machine_t *model) case ROM_PC200: device_add(&fdc_xt_device); if (vid_card == VID_INTERNAL) { + /* Load the PC200 CGA Character Set ROM. */ + loadfont(roms->fontfn, roms->fontnum); + vid_init_200(ams); device_add_ex(&vid_200_device, ams->vid); } diff --git a/src/machine/m_at.c b/src/machine/m_at.c index 851eeb1..b418e3c 100644 --- a/src/machine/m_at.c +++ b/src/machine/m_at.c @@ -8,7 +8,7 @@ * * Standard PC/AT implementation. * - * Version: @(#)m_at.c 1.0.3 2018/03/19 + * Version: @(#)m_at.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -46,20 +46,20 @@ #include "../dma.h" #include "../mem.h" #include "../device.h" +#include "../nvr.h" +#include "../lpt.h" +#include "../keyboard.h" +#include "../game/gameport.h" #include "../floppy/fdd.h" #include "../floppy/fdc.h" -#include "../nvr.h" -#include "../game/gameport.h" -#include "../keyboard.h" -#include "../lpt.h" #include "../disk/hdc.h" #include "machine.h" void -machine_at_common_init(const machine_t *model) +machine_at_common_init(const machine_t *model, void *arg) { - machine_common_init(model); + machine_common_init(model, arg); pit_set_out_func(&pit, 1, pit_refresh_timer_at); pic2_init(); @@ -76,72 +76,72 @@ machine_at_common_init(const machine_t *model) void -machine_at_init(const machine_t *model) +machine_at_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_at_device); } void -machine_at_ps2_init(const machine_t *model) +machine_at_ps2_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_ps2_device); } void -machine_at_common_ide_init(const machine_t *model) +machine_at_common_ide_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&ide_isa_2ch_opt_device); } void -machine_at_ide_init(const machine_t *model) +machine_at_ide_init(const machine_t *model, void *arg) { - machine_at_init(model); + machine_at_init(model, arg); device_add(&ide_isa_2ch_opt_device); } void -machine_at_ps2_ide_init(const machine_t *model) +machine_at_ps2_ide_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); device_add(&ide_isa_2ch_opt_device); } void -machine_at_top_remap_init(const machine_t *model) +machine_at_top_remap_init(const machine_t *model, void *arg) { - machine_at_init(model); + machine_at_init(model, arg); mem_remap_top_384k(); } void -machine_at_ide_top_remap_init(const machine_t *model) +machine_at_ide_top_remap_init(const machine_t *model, void *arg) { - machine_at_ide_init(model); + machine_at_ide_init(model, arg); mem_remap_top_384k(); } void -machine_at_ibm_init(const machine_t *model) +machine_at_ibm_init(const machine_t *model, void *arg) { - machine_at_top_remap_init(model); + machine_at_top_remap_init(model, arg); device_add(&fdc_at_device); } diff --git a/src/machine/m_at_430fx.c b/src/machine/m_at_430fx.c index 315044a..fd41ee6 100644 --- a/src/machine/m_at_430fx.c +++ b/src/machine/m_at_430fx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 430FX PCISet chip. * - * Version: @(#)m_at_430fx.c 1.0.5 2018/03/15 + * Version: @(#)m_at_430fx.c 1.0.6 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -227,9 +227,9 @@ static void i430fx_init(void) void -machine_at_p54tp4xe_init(const machine_t *model) +machine_at_p54tp4xe_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); memregs_init(); pci_init(PCI_CONFIG_TYPE_1); @@ -248,9 +248,9 @@ machine_at_p54tp4xe_init(const machine_t *model) void -machine_at_endeavor_init(const machine_t *model) +machine_at_endeavor_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_ps2_ami_device); memregs_init(); @@ -281,9 +281,9 @@ at_endeavor_get_device(void) void -machine_at_zappa_init(const machine_t *model) +machine_at_zappa_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_ps2_ami_device); memregs_init(); @@ -302,9 +302,9 @@ machine_at_zappa_init(const machine_t *model) void -machine_at_mb500n_init(const machine_t *model) +machine_at_mb500n_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); @@ -322,9 +322,9 @@ machine_at_mb500n_init(const machine_t *model) void -machine_at_president_init(const machine_t *model) +machine_at_president_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); memregs_init(); pci_init(PCI_CONFIG_TYPE_1); @@ -343,9 +343,9 @@ machine_at_president_init(const machine_t *model) void -machine_at_thor_init(const machine_t *model) +machine_at_thor_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_ps2_ami_device); memregs_init(); diff --git a/src/machine/m_at_430hx.c b/src/machine/m_at_430hx.c index 1f6d6bd..8981f6e 100644 --- a/src/machine/m_at_430hx.c +++ b/src/machine/m_at_430hx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 430HX PCISet chip. * - * Version: @(#)m_at_430hx.c 1.0.3 2018/03/15 + * Version: @(#)m_at_430hx.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -236,9 +236,9 @@ acerm3a_in(uint16_t port, void *p) void -machine_at_acerm3a_init(const machine_t *model) +machine_at_acerm3a_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); powermate_memregs_init(); pci_init(PCI_CONFIG_TYPE_1); @@ -259,9 +259,9 @@ machine_at_acerm3a_init(const machine_t *model) void -machine_at_acerv35n_init(const machine_t *model) +machine_at_acerv35n_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); powermate_memregs_init(); pci_init(PCI_CONFIG_TYPE_1); @@ -282,9 +282,9 @@ machine_at_acerv35n_init(const machine_t *model) void -machine_at_ap53_init(const machine_t *model) +machine_at_ap53_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_ps2_ami_device); memregs_init(); @@ -306,9 +306,9 @@ machine_at_ap53_init(const machine_t *model) void -machine_at_p55t2p4_init(const machine_t *model) +machine_at_p55t2p4_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); memregs_init(); pci_init(PCI_CONFIG_TYPE_1); @@ -327,9 +327,9 @@ machine_at_p55t2p4_init(const machine_t *model) void -machine_at_p55t2s_init(const machine_t *model) +machine_at_p55t2s_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_ps2_ami_device); memregs_init(); diff --git a/src/machine/m_at_430lx_nx.c b/src/machine/m_at_430lx_nx.c index 59c70a6..4e7d2d6 100644 --- a/src/machine/m_at_430lx_nx.c +++ b/src/machine/m_at_430lx_nx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 430LX and 430NX PCISet chips. * - * Version: @(#)m_at_430lx_nx.c 1.0.3 2018/03/15 + * Version: @(#)m_at_430lx_nx.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -231,9 +231,9 @@ static void i430nx_init(void) static void -machine_at_premiere_common_init(const machine_t *model) +machine_at_premiere_common_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_ps2_ami_device); memregs_init(); @@ -253,18 +253,18 @@ machine_at_premiere_common_init(const machine_t *model) void -machine_at_batman_init(const machine_t *model) +machine_at_batman_init(const machine_t *model, void *arg) { - machine_at_premiere_common_init(model); + machine_at_premiere_common_init(model, arg); i430lx_init(); } void -machine_at_plato_init(const machine_t *model) +machine_at_plato_init(const machine_t *model, void *arg) { - machine_at_premiere_common_init(model); + machine_at_premiere_common_init(model, arg); i430nx_init(); } diff --git a/src/machine/m_at_430vx.c b/src/machine/m_at_430vx.c index 9cbf7a8..b5a61dd 100644 --- a/src/machine/m_at_430vx.c +++ b/src/machine/m_at_430vx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 430VX PCISet chip. * - * Version: @(#)m_at_430vx.c 1.0.3 2018/03/15 + * Version: @(#)m_at_430vx.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -213,9 +213,9 @@ void i430vx_init(void) void -machine_at_p55tvp4_init(const machine_t *model) +machine_at_p55tvp4_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); memregs_init(); pci_init(PCI_CONFIG_TYPE_1); @@ -234,9 +234,9 @@ machine_at_p55tvp4_init(const machine_t *model) void -machine_at_i430vx_init(const machine_t *model) +machine_at_i430vx_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); memregs_init(); pci_init(PCI_CONFIG_TYPE_1); @@ -255,9 +255,9 @@ machine_at_i430vx_init(const machine_t *model) void -machine_at_p55va_init(const machine_t *model) +machine_at_p55va_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); pci_init(PCI_CONFIG_TYPE_1); pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); diff --git a/src/machine/m_at_440fx.c b/src/machine/m_at_440fx.c index bb4e941..001339f 100644 --- a/src/machine/m_at_440fx.c +++ b/src/machine/m_at_440fx.c @@ -8,7 +8,7 @@ * * Implementation of the Intel 440FX PCISet chip. * - * Version: @(#)m_at_440fx.c 1.0.3 2018/03/15 + * Version: @(#)m_at_440fx.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -215,9 +215,9 @@ static void i440fx_init(void) void -machine_at_i440fx_init(const machine_t *model) +machine_at_i440fx_init(const machine_t *model, void *arg) { - machine_at_ps2_init(model); + machine_at_ps2_init(model, arg); memregs_init(); pci_init(PCI_CONFIG_TYPE_1); @@ -237,9 +237,9 @@ machine_at_i440fx_init(const machine_t *model) void -machine_at_s1668_init(const machine_t *model) +machine_at_s1668_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_ps2_ami_device); memregs_init(); diff --git a/src/machine/m_at_4gpv31.c b/src/machine/m_at_4gpv31.c index 98619a9..013be15 100644 --- a/src/machine/m_at_4gpv31.c +++ b/src/machine/m_at_4gpv31.c @@ -11,7 +11,7 @@ * NOTE: The NEAT 82c206 code should be moved into a 82c206 module, * so it can be re-used by other boards. * - * Version: @(#)m_4gpv31.c 1.0.2 2018/03/15 + * Version: @(#)m_4gpv31.c 1.0.3 2018/03/21 * * Author: Fred N. van Kempen, * @@ -174,10 +174,12 @@ neat_init(void) void -machine_at_4gpv31_init(const machine_t *model) +machine_at_4gpv31_init(const machine_t *model, void *arg) { - machine_at_common_ide_init(model); + machine_at_common_ide_init(model, arg); + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); neat_init(); diff --git a/src/machine/m_at_ali1429.c b/src/machine/m_at_ali1429.c index 30c7592..f88babf 100644 --- a/src/machine/m_at_ali1429.c +++ b/src/machine/m_at_ali1429.c @@ -8,7 +8,7 @@ * * Implementation the ALI M1429 mainboard. * - * Version: @(#)m_at_ali1429.c 1.0.2 2018/03/15 + * Version: @(#)m_at_ali1429.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,96 +53,114 @@ #include "machine.h" -static int ali1429_index; -static uint8_t ali1429_regs[256]; +static int ali1429_index; +static uint8_t ali1429_regs[256]; -static void ali1429_recalc(void) +static void +ali1429_recalc(void) { - int c; - - for (c = 0; c < 8; c++) - { - uint32_t base = 0xc0000 + (c << 15); - if (ali1429_regs[0x13] & (1 << c)) - { - switch (ali1429_regs[0x14] & 3) - { - case 0: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 1: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - } - } - else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } - - flushmmucache(); -} + uint32_t base; + int c; -void ali1429_write(uint16_t port, uint8_t val, void *priv) -{ - if (!(port & 1)) - ali1429_index = val; - else - { - ali1429_regs[ali1429_index] = val; - switch (ali1429_index) - { - case 0x13: - ali1429_recalc(); - break; - case 0x14: - shadowbios = val & 1; - shadowbios_write = val & 2; - ali1429_recalc(); - break; - } - } -} + for (c = 0; c < 8; c++) { + base = 0xc0000 + (c << 15); -uint8_t ali1429_read(uint16_t port, void *priv) -{ - if (!(port & 1)) - return ali1429_index; - if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix) - return 0xff; /*Don't conflict with Cyrix config registers*/ - return ali1429_regs[ali1429_index]; + if (ali1429_regs[0x13] & (1 << c)) { + switch (ali1429_regs[0x14] & 3) { + case 0: + mem_set_mem_state(base, 0x8000, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + + case 1: + mem_set_mem_state(base, 0x8000, + MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + + case 2: + mem_set_mem_state(base, 0x8000, + MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + + case 3: + mem_set_mem_state(base, 0x8000, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + } else { + mem_set_mem_state(base, 0x8000, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + flushmmucache(); } -static void ali1429_reset(void) +static void +ali1429_write(uint16_t port, uint8_t val, void *priv) { - memset(ali1429_regs, 0xff, 256); + if (! (port & 1)) + ali1429_index = val; + else { + ali1429_regs[ali1429_index] = val; + + switch (ali1429_index) { + case 0x13: + ali1429_recalc(); + break; + + case 0x14: + shadowbios = val & 1; + shadowbios_write = val & 2; + ali1429_recalc(); + break; + } + } } -static void ali1429_init(void) +static uint8_t +ali1429_read(uint16_t port, void *priv) { - io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, NULL); + if (! (port & 1)) + return(ali1429_index); + + if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix) + return(0xff); /*Don't conflict with Cyrix config registers*/ + + return(ali1429_regs[ali1429_index]); +} + + +static void +ali1429_reset(void) +{ + memset(ali1429_regs, 0xff, 256); +} + + +static void +ali1429_init(void) +{ + io_sethandler(0x0022, 2, + ali1429_read,NULL,NULL, ali1429_write,NULL,NULL, NULL); } void -machine_at_ali1429_init(const machine_t *model) +machine_at_ali1429_init(const machine_t *model, void *arg) { - ali1429_reset(); + ali1429_reset(); - machine_at_common_ide_init(model); + machine_at_common_ide_init(model, arg); - device_add(&keyboard_at_ami_device); - device_add(&fdc_at_device); + device_add(&keyboard_at_ami_device); - ali1429_init(); + device_add(&fdc_at_device); - secondary_ide_check(); + ali1429_init(); + + secondary_ide_check(); } diff --git a/src/machine/m_at_commodore.c b/src/machine/m_at_commodore.c index 4b1668b..baf75e7 100644 --- a/src/machine/m_at_commodore.c +++ b/src/machine/m_at_commodore.c @@ -8,7 +8,7 @@ * * Implementation of the Commodore PC3 system. * - * Version: @(#)m_at_commodore.c 1.0.2 2018/03/15 + * Version: @(#)m_at_commodore.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -91,9 +91,9 @@ pc3_init(void) void -machine_at_cmdpc_init(const machine_t *model) +machine_at_cmdpc_init(const machine_t *model, void *arg) { - machine_at_ide_top_remap_init(model); + machine_at_ide_top_remap_init(model, arg); device_add(&fdc_at_device); diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 0a94abf..53006ef 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -8,7 +8,7 @@ * * Emulation of various Compaq PC's. * - * Version: @(#)m_at_compaq.c 1.0.3 2018/03/15 + * Version: @(#)m_at_compaq.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -118,9 +118,9 @@ write_raml(uint32_t addr, uint32_t val, void *priv) void -machine_at_compaq_init(const machine_t *model) +machine_at_compaq_init(const machine_t *model, void *arg) { - machine_at_top_remap_init(model); + machine_at_top_remap_init(model, arg); device_add(&fdc_at_device); mem_mapping_add(&ram_mapping, 0xfa0000, 0x60000, diff --git a/src/machine/m_at_headland.c b/src/machine/m_at_headland.c index a548169..a691fff 100644 --- a/src/machine/m_at_headland.c +++ b/src/machine/m_at_headland.c @@ -8,7 +8,7 @@ * * Implementation of the HEADLAND AT286 chipset. * - * Version: @(#)m_at_headland.c 1.0.2 2018/03/15 + * Version: @(#)m_at_headland.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -104,9 +104,9 @@ headland_init(void) void -machine_at_headland_init(const machine_t *model) +machine_at_headland_init(const machine_t *model, void *arg) { - machine_at_common_ide_init(model); + machine_at_common_ide_init(model, arg); device_add(&keyboard_at_ami_device); device_add(&fdc_at_device); diff --git a/src/machine/m_at_neat.c b/src/machine/m_at_neat.c index 3ca936f..87d0d7f 100644 --- a/src/machine/m_at_neat.c +++ b/src/machine/m_at_neat.c @@ -10,7 +10,7 @@ * * This is the chipset used in the AMI 286 clone model. * - * Version: @(#)m_at_neat.c 1.0.2 2018/03/15 + * Version: @(#)m_at_neat.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -131,9 +131,9 @@ neat_init(void) void -machine_at_neat_init(const machine_t *model) +machine_at_neat_init(const machine_t *model, void *arg) { - machine_at_init(model); + machine_at_init(model, arg); device_add(&fdc_at_device); neat_init(); @@ -141,9 +141,9 @@ machine_at_neat_init(const machine_t *model) void -machine_at_neat_ami_init(const machine_t *model) +machine_at_neat_ami_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_at_ami_device); device_add(&fdc_at_device); diff --git a/src/machine/m_at_opti495.c b/src/machine/m_at_opti495.c index b295e0f..cb09731 100644 --- a/src/machine/m_at_opti495.c +++ b/src/machine/m_at_opti495.c @@ -260,7 +260,7 @@ Note: the block address is forced to be a multiple of the block size by ignoring the appropriate number of the least-significant bits SeeAlso: #P0178,#P0187 * - * Version: @(#)m_at_opti495.c 1.0.2 2018/03/15 + * Version: @(#)m_at_opti495.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -364,9 +364,9 @@ opti495_init(void) void -machine_at_opti495_init(const machine_t *model) +machine_at_opti495_init(const machine_t *model, void *arg) { - machine_at_common_ide_init(model); + machine_at_common_ide_init(model, arg); device_add(&keyboard_at_device); device_add(&fdc_at_device); @@ -376,9 +376,9 @@ machine_at_opti495_init(const machine_t *model) void -machine_at_opti495_ami_init(const machine_t *model) +machine_at_opti495_ami_init(const machine_t *model, void *arg) { - machine_at_common_ide_init(model); + machine_at_common_ide_init(model, arg); device_add(&keyboard_at_ami_device); device_add(&fdc_at_device); diff --git a/src/machine/m_at_scat.c b/src/machine/m_at_scat.c index 43fe1b6..38da83d 100644 --- a/src/machine/m_at_scat.c +++ b/src/machine/m_at_scat.c @@ -10,7 +10,7 @@ * * Re-worked version based on the 82C235 datasheet and errata. * - * Version: @(#)m_at_scat.c 1.0.4 2018/03/20 + * Version: @(#)m_at_scat.c 1.0.5 2018/03/21 * * Authors: Fred N. van Kempen, * Original by GreatPsycho for PCem. @@ -54,689 +54,703 @@ #include "machine.h" -#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 -#define SCAT_VERSION 0x40 -#define SCAT_CLOCK_CONTROL 0x41 -#define SCAT_PERIPHERAL_CONTROL 0x44 -#define SCAT_MISCELLANEOUS_STATUS 0x45 -#define SCAT_POWER_MANAGEMENT 0x46 -#define SCAT_ROM_ENABLE 0x48 -#define SCAT_RAM_WRITE_PROTECT 0x49 -#define SCAT_SHADOW_RAM_ENABLE_1 0x4A -#define SCAT_SHADOW_RAM_ENABLE_2 0x4B -#define SCAT_SHADOW_RAM_ENABLE_3 0x4C -#define SCAT_DRAM_CONFIGURATION 0x4D -#define SCAT_EXTENDED_BOUNDARY 0x4E -#define SCAT_EMS_CONTROL 0x4F +#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 +#define SCAT_VERSION 0x40 +#define SCAT_CLOCK_CONTROL 0x41 +#define SCAT_PERIPHERAL_CONTROL 0x44 +#define SCAT_MISCELLANEOUS_STATUS 0x45 +#define SCAT_POWER_MANAGEMENT 0x46 +#define SCAT_ROM_ENABLE 0x48 +#define SCAT_RAM_WRITE_PROTECT 0x49 +#define SCAT_SHADOW_RAM_ENABLE_1 0x4a +#define SCAT_SHADOW_RAM_ENABLE_2 0x4b +#define SCAT_SHADOW_RAM_ENABLE_3 0x4c +#define SCAT_DRAM_CONFIGURATION 0x4d +#define SCAT_EXTENDED_BOUNDARY 0x4e +#define SCAT_EMS_CONTROL 0x4f -#define SCATSX_LAPTOP_FEATURES 0x60 -#define SCATSX_FAST_VIDEO_CONTROL 0x61 -#define SCATSX_FAST_VIDEORAM_ENABLE 0x62 -#define SCATSX_HIGH_PERFORMANCE_REFRESH 0x63 -#define SCATSX_CAS_TIMING_FOR_DMA 0x64 +#define SCATSX_LAPTOP_FEATURES 0x60 +#define SCATSX_FAST_VIDEO_CONTROL 0x61 +#define SCATSX_FAST_VIDEORAM_ENABLE 0x62 +#define SCATSX_HIGH_PERFORMANCE_REFRESH 0x63 +#define SCATSX_CAS_TIMING_FOR_DMA 0x64 -typedef struct scat_t -{ - uint8_t regs_2x8; - uint8_t regs_2x9; +typedef struct scat_t { + uint8_t regs_2x8; + uint8_t regs_2x9; } scat_t; -static uint8_t scat_regs[256]; -static int scat_index; -static uint8_t scat_port_92 = 0; -static uint8_t scat_ems_reg_2xA = 0; +static uint8_t scat_regs[256]; +static int scat_index; +static uint8_t scat_port_92 = 0; +static uint8_t scat_ems_reg_2xA = 0; +static scat_t scat_stat[32]; +static uint32_t scat_xms_bound; static mem_mapping_t scat_mapping[32]; static mem_mapping_t scat_high_mapping[16]; -static scat_t scat_stat[32]; -static uint32_t scat_xms_bound; static mem_mapping_t scat_shadowram_mapping[6]; static mem_mapping_t scat_4000_9FFF_mapping[24]; static mem_mapping_t scat_A000_BFFF_mapping; // TODO - 82C836 chipset's memory address mapping isn't fully implemented yet, so memory configuration is hardcoded now. -static int scatsx_mem_conf_val[33] = { 0x00, 0x01, 0x03, 0x04, 0x05, 0x08, 0x06, 0x06, - 0x0c, 0x09, 0x07, 0x07, 0x0d, 0x0a, 0x0f, 0x0f, - 0x0e, 0x0e, 0x10, 0x10, 0x13, 0x13, 0x11, 0x11, - 0x14, 0x14, 0x12, 0x12, 0x15, 0x15, 0x15, 0x15, - 0x16 }; +static int scatsx_mem_conf_val[33] = { + 0x00, 0x01, 0x03, 0x04, 0x05, 0x08, 0x06, 0x06, + 0x0c, 0x09, 0x07, 0x07, 0x0d, 0x0a, 0x0f, 0x0f, + 0x0e, 0x0e, 0x10, 0x10, 0x13, 0x13, 0x11, 0x11, + 0x14, 0x14, 0x12, 0x12, 0x15, 0x15, 0x15, 0x15, + 0x16 +}; -uint8_t scat_read(uint16_t port, void *priv); -void scat_write(uint16_t port, uint8_t val, void *priv); -void scat_shadow_state_update() +static uint8_t scat_read(uint16_t port, void *priv); +static void scat_write(uint16_t port, uint8_t val, void *priv); + +static void +scat_shadow_state_update(void) { - int i, val; + int i, val; - // TODO - ROMCS enable features should be implemented later. - for (i = 0; i < 24; i++) - { - val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; - if (i < 8) - { - val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; - } - else - { - if ((scat_regs[SCAT_RAM_WRITE_PROTECT] >> ((i - 8) >> 1)) & 1) - { - val |= MEM_WRITE_DISABLED; - } - else - { - val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; - } - } - mem_set_mem_state((i + 40) << 14, 0x4000, val); - } + // TODO - ROMCS enable features should be implemented later. + for (i = 0; i < 24; i++) { + val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; + if (i < 8) { + val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; + } else { + if ((scat_regs[SCAT_RAM_WRITE_PROTECT] >> ((i - 8) >> 1)) & 1) + val |= MEM_WRITE_DISABLED; + else + val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; + } + mem_set_mem_state((i + 40) << 14, 0x4000, val); + } - flushmmucache(); + flushmmucache(); } -void scat_set_xms_bound(uint8_t val) + +static void +scat_set_xms_bound(uint8_t val) { - uint32_t max_xms_size = (mem_size >= 16128) ? (((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) ? 0xFE0000 : 0xFC0000) : mem_size << 10; - int i; + uint32_t max_xms_size = (mem_size >= 16128) ? (((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) ? 0xFE0000 : 0xFC0000) : mem_size << 10; + int i; - switch (val & 0x0F) - { - case 1: - scat_xms_bound = 0x100000; - break; - case 2: - scat_xms_bound = 0x140000; - break; - case 3: - scat_xms_bound = 0x180000; - break; - case 4: - scat_xms_bound = 0x200000; - break; - case 5: - scat_xms_bound = 0x300000; - break; - case 6: - scat_xms_bound = 0x400000; - break; - case 7: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x600000 : 0x500000; - break; - case 8: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x800000 : 0x700000; - break; - case 9: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xA00000 : 0x800000; - break; - case 10: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xC00000 : 0x900000; - break; - case 11: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xE00000 : 0xA00000; - break; - case 12: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xB00000; - break; - case 13: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xC00000; - break; - case 14: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xD00000; - break; - case 15: - scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xF00000; - break; - default: - scat_xms_bound = max_xms_size; - break; - } + switch (val & 0x0f) { + case 1: + scat_xms_bound = 0x100000; + break; - if ((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (val & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3)) - { - if (val != 1) - { - if(mem_size > 1024) mem_mapping_disable(&ram_high_mapping); - for(i=0;i<6;i++) - mem_mapping_enable(&scat_shadowram_mapping[i]); - if ((val & 0x0F) == 0) - scat_xms_bound = 0x160000; - } - else - { - for(i=0;i<6;i++) - mem_mapping_disable(&scat_shadowram_mapping[i]); - if(mem_size > 1024) mem_mapping_enable(&ram_high_mapping); - } - pclog("Set XMS bound(%02X) = %06X(%dKbytes for EMS access)\n", val, scat_xms_bound, (0x160000 - scat_xms_bound) >> 10); - if (scat_xms_bound > 0x100000) - mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - if (scat_xms_bound < 0x160000) - mem_set_mem_state(scat_xms_bound, 0x160000 - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } - else - { - for(i=0;i<6;i++) - mem_mapping_disable(&scat_shadowram_mapping[i]); - if(mem_size > 1024) mem_mapping_enable(&ram_high_mapping); + case 2: + scat_xms_bound = 0x140000; + break; - if (scat_xms_bound > max_xms_size) - scat_xms_bound = max_xms_size; - pclog("Set XMS bound(%02X) = %06X(%dKbytes for EMS access)\n", val, scat_xms_bound, ((mem_size << 10) - scat_xms_bound) >> 10); - if (scat_xms_bound > 0x100000) - mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - if (scat_xms_bound < (mem_size << 10)) - mem_set_mem_state(scat_xms_bound, (mem_size << 10) - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } + case 3: + scat_xms_bound = 0x180000; + break; + + case 4: + scat_xms_bound = 0x200000; + break; + + case 5: + scat_xms_bound = 0x300000; + break; + + case 6: + scat_xms_bound = 0x400000; + break; + + case 7: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x600000 : 0x500000; + break; + + case 8: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x800000 : 0x700000; + break; + + case 9: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xA00000 : 0x800000; + break; + + case 10: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xC00000 : 0x900000; + break; + + case 11: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xE00000 : 0xA00000; + break; + + case 12: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xB00000; + break; + + case 13: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xC00000; + break; + + case 14: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xD00000; + break; + + case 15: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xF00000; + break; + + default: + scat_xms_bound = max_xms_size; + break; + } + + if ((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (val & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3)) { + if (val != 1) { + if(mem_size > 1024) mem_mapping_disable(&ram_high_mapping); + for(i=0;i<6;i++) + mem_mapping_enable(&scat_shadowram_mapping[i]); + if ((val & 0x0F) == 0) + scat_xms_bound = 0x160000; + } else { + for(i=0;i<6;i++) + mem_mapping_disable(&scat_shadowram_mapping[i]); + if(mem_size > 1024) mem_mapping_enable(&ram_high_mapping); + } + pclog("SCAT: set XMS bound(%02X) = %06X(%dKbytes for EMS access)\n", val, scat_xms_bound, (0x160000 - scat_xms_bound) >> 10); + if (scat_xms_bound > 0x100000) + mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (scat_xms_bound < 0x160000) + mem_set_mem_state(scat_xms_bound, 0x160000 - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } else { + for(i=0;i<6;i++) + mem_mapping_disable(&scat_shadowram_mapping[i]); + if(mem_size > 1024) mem_mapping_enable(&ram_high_mapping); + + if (scat_xms_bound > max_xms_size) + scat_xms_bound = max_xms_size; + pclog("SCAT: set XMS bound(%02X) = %06X(%dKbytes for EMS access)\n", val, scat_xms_bound, ((mem_size << 10) - scat_xms_bound) >> 10); + if (scat_xms_bound > 0x100000) + mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (scat_xms_bound < (mem_size << 10)) + mem_set_mem_state(scat_xms_bound, (mem_size << 10) - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } } -uint32_t get_scat_addr(uint32_t addr, scat_t *p) + +static uint32_t +get_scat_addr(uint32_t addr, scat_t *p) { - if (p && (scat_regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) - addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; + if (p && (scat_regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) + addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; - if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) - { - if (mem_size < 2048 && ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) > 7 || (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) != 0)) - addr = (addr & ~0x780000) | ((addr & 0x600000) >> 2); - else if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 8 && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) - { - addr &= ~0x600000; - if(mem_size > 2048 || (mem_size == 2048 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 6)) - addr |= (addr & 0x180000) << 2; - } + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) { + if (mem_size < 2048 && ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) > 7 || (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) != 0)) + addr = (addr & ~0x780000) | ((addr & 0x600000) >> 2); + else if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 8 && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) { + addr &= ~0x600000; + if(mem_size > 2048 || (mem_size == 2048 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 6)) + addr |= (addr & 0x180000) << 2; + } - if ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3 && (addr & ~0x600000) >= 0x100000 && (addr & ~0x600000) < 0x160000) - addr ^= mem_size < 2048 ? 0x1F0000 : 0x670000; - } - else - { - if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3 && (addr & ~0x600000) >= 0x100000 && (addr & ~0x600000) < 0x160000) - addr ^= 0x1F0000; - } - return addr; + if ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3 && (addr & ~0x600000) >= 0x100000 && (addr & ~0x600000) < 0x160000) + addr ^= mem_size < 2048 ? 0x1F0000 : 0x670000; + } else { + if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3 && (addr & ~0x600000) >= 0x100000 && (addr & ~0x600000) < 0x160000) + addr ^= 0x1F0000; + } + + return addr; } -void scat_memmap_state_update() + +static void +scat_memmap_state_update(void) { - int i; - uint32_t addr; + uint32_t addr; + int i; - for(i=16;i<24;i++) - { - addr = get_scat_addr(0x40000 + (i << 14), NULL); - mem_mapping_set_exec(&scat_4000_9FFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); - } - addr = get_scat_addr(0xA0000, NULL); - mem_mapping_set_exec(&scat_A000_BFFF_mapping, addr < (mem_size << 10) ? ram + addr : NULL); - for(i=0;i<6;i++) - { - addr = get_scat_addr(0x100000 + (i << 16), NULL); - mem_mapping_set_exec(&scat_shadowram_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); - } + for(i=16;i<24;i++) { + addr = get_scat_addr(0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&scat_4000_9FFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); + } - flushmmucache(); + addr = get_scat_addr(0xA0000, NULL); + mem_mapping_set_exec(&scat_A000_BFFF_mapping, addr < (mem_size << 10) ? ram + addr : NULL); + for (i=0;i<6;i++) { + addr = get_scat_addr(0x100000 + (i << 16), NULL); + mem_mapping_set_exec(&scat_shadowram_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); + } + + flushmmucache(); } -void scat_set_global_EMS_state(int state) -{ - int i; - uint32_t base_addr, virt_addr; - for(i=((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0 : 24; i<32; i++) - { - base_addr = (i + 16) << 14; - if(i >= 24) - base_addr += 0x30000; - if(state && (scat_stat[i].regs_2x9 & 0x80)) - { - virt_addr = get_scat_addr(base_addr, &scat_stat[i]); - if(i < 24) mem_mapping_disable(&scat_4000_9FFF_mapping[i]); - mem_mapping_enable(&scat_mapping[i]); - if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_mapping[i], ram + virt_addr); - else mem_mapping_set_exec(&scat_mapping[i], NULL); - } - else - { - mem_mapping_set_exec(&scat_mapping[i], ram + base_addr); - mem_mapping_disable(&scat_mapping[i]); - if(i < 24) mem_mapping_enable(&scat_4000_9FFF_mapping[i]); - } - } - flushmmucache(); +static void +scat_set_global_EMS_state(int state) +{ + uint32_t base_addr, virt_addr; + int i; + + for (i=((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0 : 24; i<32; i++) { + base_addr = (i + 16) << 14; + if (i >= 24) + base_addr += 0x30000; + if (state && (scat_stat[i].regs_2x9 & 0x80)) { + virt_addr = get_scat_addr(base_addr, &scat_stat[i]); + if (i < 24) mem_mapping_disable(&scat_4000_9FFF_mapping[i]); + mem_mapping_enable(&scat_mapping[i]); + if (virt_addr < (mem_size << 10)) + mem_mapping_set_exec(&scat_mapping[i], ram+virt_addr); + else + mem_mapping_set_exec(&scat_mapping[i], NULL); + } else { + mem_mapping_set_exec(&scat_mapping[i], ram + base_addr); + mem_mapping_disable(&scat_mapping[i]); + if (i < 24) + mem_mapping_enable(&scat_4000_9FFF_mapping[i]); + } + } + + flushmmucache(); } -void scat_write(uint16_t port, uint8_t val, void *priv) + +static void +scat_write(uint16_t port, uint8_t val, void *priv) { - uint8_t scat_reg_valid = 0, scat_shadow_update = 0, scat_map_update = 0, index; - uint32_t base_addr, virt_addr; + uint8_t scat_reg_valid = 0, scat_shadow_update = 0, scat_map_update = 0, index; + uint32_t base_addr, virt_addr; - switch (port) - { - case 0x22: - scat_index = val; - break; - - case 0x23: - switch (scat_index) - { - case SCAT_DMA_WAIT_STATE_CONTROL: - case SCAT_CLOCK_CONTROL: - case SCAT_PERIPHERAL_CONTROL: - scat_reg_valid = 1; - break; - case SCAT_EMS_CONTROL: - if(val & 0x40) - { - if(val & 1) - { - io_sethandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_removehandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - } - else - { - io_sethandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_removehandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - } - } - else - { - io_removehandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - io_removehandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); - } - scat_set_global_EMS_state(val & 0x80); - scat_reg_valid = 1; - break; - case SCAT_POWER_MANAGEMENT: - // TODO - Only use AUX parity disable bit for this version. Other bits should be implemented later. - val &= (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x40 : 0x60; - scat_reg_valid = 1; - break; - case SCAT_DRAM_CONFIGURATION: - if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((scat_regs[SCAT_VERSION] & 0xF0) != 0)) - { - if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (val & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (val & 0x1F) == 3)) - { - if(mem_size > 1024) mem_mapping_disable(&ram_high_mapping); - for(index=0;index<6;index++) - mem_mapping_enable(&scat_shadowram_mapping[index]); - } - else - { - for(index=0;index<6;index++) - mem_mapping_disable(&scat_shadowram_mapping[index]); - if(mem_size > 1024) mem_mapping_enable(&ram_high_mapping); - } - } - else - { - for(index=0;index<6;index++) - mem_mapping_disable(&scat_shadowram_mapping[index]); - if(mem_size > 1024) mem_mapping_enable(&ram_high_mapping); - } - scat_map_update = 1; + switch (port) { + case 0x22: + scat_index = val; + break; - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) - { - cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; - cpu_update_waitstates(); - } - else - { - if(mem_size != 1024 || ((val & 0x1F) != 2 && (val & 0x1F) != 3)) - val = (val & 0xe0) | scatsx_mem_conf_val[mem_size >> 9]; - } + case 0x23: + switch (scat_index) { + case SCAT_DMA_WAIT_STATE_CONTROL: + case SCAT_CLOCK_CONTROL: + case SCAT_PERIPHERAL_CONTROL: + scat_reg_valid = 1; + break; - scat_reg_valid = 1; - break; - case SCAT_EXTENDED_BOUNDARY: - scat_set_xms_bound(val & ((scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x4f : 0x1f)); - mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - if((val ^ scat_regs[SCAT_EXTENDED_BOUNDARY]) & 0x40) scat_map_update = 1; - scat_reg_valid = 1; - break; - case SCAT_ROM_ENABLE: - case SCAT_RAM_WRITE_PROTECT: - case SCAT_SHADOW_RAM_ENABLE_1: - case SCAT_SHADOW_RAM_ENABLE_2: - case SCAT_SHADOW_RAM_ENABLE_3: - scat_reg_valid = 1; - scat_shadow_update = 1; - break; - case SCATSX_LAPTOP_FEATURES: - if((scat_regs[SCAT_VERSION] & 0xF0) != 0) - { - val = (val & ~8) | (scat_regs[SCATSX_LAPTOP_FEATURES] & 8); - scat_reg_valid = 1; - } - break; - case SCATSX_FAST_VIDEO_CONTROL: - case SCATSX_FAST_VIDEORAM_ENABLE: - case SCATSX_HIGH_PERFORMANCE_REFRESH: - case SCATSX_CAS_TIMING_FOR_DMA: - if((scat_regs[SCAT_VERSION] & 0xF0) != 0) scat_reg_valid = 1; - break; - default: - break; - } - if (scat_reg_valid) - scat_regs[scat_index] = val; - else pclog("Attemped to write unimplemented SCAT register %02X at %04X:%04X\n", scat_index, val, CS, cpu_state.pc); - if (scat_shadow_update) - scat_shadow_state_update(); - if (scat_map_update) - scat_memmap_state_update(); -// pclog("Write SCAT Register %02X to %02X at %04X:%04X\n", scat_index, val, CS, cpu_state.pc); - break; + case SCAT_EMS_CONTROL: + if (val & 0x40) { + if (val & 1) { + io_sethandler(0x0218, 3, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0208, 3, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + } else { + io_sethandler(0x0208, 3, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0218, 3, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + } + } else { + io_removehandler(0x0208, 3, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0218, 3, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + } + scat_set_global_EMS_state(val & 0x80); + scat_reg_valid = 1; + break; - case 0x92: - if ((mem_a20_alt ^ val) & 2) - { - mem_a20_alt = val & 2; - mem_a20_recalc(); - } - if ((~scat_port_92 & val) & 1) - { - softresetx86(); - cpu_set_edx(); - } - scat_port_92 = val; - break; + case SCAT_POWER_MANAGEMENT: + // TODO - Only use AUX parity disable bit for this version. Other bits should be implemented later. + val &= (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x40 : 0x60; + scat_reg_valid = 1; + break; - case 0x208: - case 0x218: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - { -// pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; - else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; - scat_stat[index].regs_2x8 = val; - base_addr = (index + 16) << 14; - if(index >= 24) - base_addr += 0x30000; + case SCAT_DRAM_CONFIGURATION: + if ((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((scat_regs[SCAT_VERSION] & 0xF0) != 0)) { + if ((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (val & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (val & 0x1F) == 3)) { + if (mem_size > 1024) + mem_mapping_disable(&ram_high_mapping); + for (index=0;index<6;index++) + mem_mapping_enable(&scat_shadowram_mapping[index]); + } else { + for (index=0;index<6;index++) + mem_mapping_disable(&scat_shadowram_mapping[index]); + if (mem_size > 1024) + mem_mapping_enable(&ram_high_mapping); + } + } else { + for (index=0;index<6;index++) + mem_mapping_disable(&scat_shadowram_mapping[index]); + if (mem_size > 1024) + mem_mapping_enable(&ram_high_mapping); + } + scat_map_update = 1; - if((scat_regs[SCAT_EMS_CONTROL] & 0x80) && (scat_stat[index].regs_2x9 & 0x80)) - { - virt_addr = get_scat_addr(base_addr, &scat_stat[index]); - if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_mapping[index], ram + virt_addr); - else mem_mapping_set_exec(&scat_mapping[index], NULL); - flushmmucache(); - } - } - break; - case 0x209: - case 0x219: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - { -// pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; - else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; - scat_stat[index].regs_2x9 = val; - base_addr = (index + 16) << 14; - if(index >= 24) - base_addr += 0x30000; + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) { + cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; + cpu_update_waitstates(); + } else { + if (mem_size != 1024 || ((val & 0x1F) != 2 && (val & 0x1F) != 3)) + val = (val & 0xe0) | scatsx_mem_conf_val[mem_size >> 9]; + } - if (scat_regs[SCAT_EMS_CONTROL] & 0x80) - { - if (val & 0x80) - { - virt_addr = get_scat_addr(base_addr, &scat_stat[index]); - if(index < 24) mem_mapping_disable(&scat_4000_9FFF_mapping[index]); - if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_mapping[index], ram + virt_addr); - else mem_mapping_set_exec(&scat_mapping[index], NULL); - mem_mapping_enable(&scat_mapping[index]); -// pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); - } - else - { - mem_mapping_set_exec(&scat_mapping[index], ram + base_addr); - mem_mapping_disable(&scat_mapping[index]); - if(index < 24) mem_mapping_enable(&scat_4000_9FFF_mapping[index]); -// pclog("Unmap page %d(address %06X)\n", scat_ems_reg_2xA & 0x1f, base_addr); - } - flushmmucache(); - } + scat_reg_valid = 1; + break; - if (scat_ems_reg_2xA & 0x80) - { - scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & (((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0x1f : 3)); - } - } - break; - case 0x20A: - case 0x21A: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - { -// pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); - scat_ems_reg_2xA = ((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? val : val & 0xc3; - } - break; - } + case SCAT_EXTENDED_BOUNDARY: + scat_set_xms_bound(val & ((scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x4f : 0x1f)); + mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if ((val ^ scat_regs[SCAT_EXTENDED_BOUNDARY]) & 0x40) + scat_map_update = 1; + scat_reg_valid = 1; + break; + + case SCAT_ROM_ENABLE: + case SCAT_RAM_WRITE_PROTECT: + case SCAT_SHADOW_RAM_ENABLE_1: + case SCAT_SHADOW_RAM_ENABLE_2: + case SCAT_SHADOW_RAM_ENABLE_3: + scat_reg_valid = 1; + scat_shadow_update = 1; + break; + + case SCATSX_LAPTOP_FEATURES: + if ((scat_regs[SCAT_VERSION] & 0xF0) != 0) { + val = (val & ~8) | (scat_regs[SCATSX_LAPTOP_FEATURES] & 8); + scat_reg_valid = 1; + } + break; + + case SCATSX_FAST_VIDEO_CONTROL: + case SCATSX_FAST_VIDEORAM_ENABLE: + case SCATSX_HIGH_PERFORMANCE_REFRESH: + case SCATSX_CAS_TIMING_FOR_DMA: + if ((scat_regs[SCAT_VERSION] & 0xF0) != 0) + scat_reg_valid = 1; + break; + + default: + break; + } + if (scat_reg_valid) + scat_regs[scat_index] = val; + else + pclog("SCAT: attempted to write unimplemented SCAT register %02X at %04X:%04X\n", scat_index, val, CS, cpu_state.pc); + if (scat_shadow_update) + scat_shadow_state_update(); + if (scat_map_update) + scat_memmap_state_update(); +// pclog("SCAT: write Register %02X to %02X at %04X:%04X\n", scat_index, val, CS, cpu_state.pc); + break; + + case 0x92: + if ((mem_a20_alt ^ val) & 2) { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~scat_port_92 & val) & 1) { + softresetx86(); + cpu_set_edx(); + } + scat_port_92 = val; + break; + + case 0x208: + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { +// pclog("SCAT: write EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) + index = scat_ems_reg_2xA & 0x1F; + else + index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; + scat_stat[index].regs_2x8 = val; + base_addr = (index + 16) << 14; + if (index >= 24) + base_addr += 0x30000; + + if ((scat_regs[SCAT_EMS_CONTROL] & 0x80) && (scat_stat[index].regs_2x9 & 0x80)) { + virt_addr = get_scat_addr(base_addr, &scat_stat[index]); + if (virt_addr < (mem_size << 10)) + mem_mapping_set_exec(&scat_mapping[index], ram + virt_addr); + else + mem_mapping_set_exec(&scat_mapping[index], NULL); + flushmmucache(); + } + } + break; + + case 0x209: + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { +// pclog("SCAT: write EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) + index = scat_ems_reg_2xA & 0x1F; + else + index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; + scat_stat[index].regs_2x9 = val; + base_addr = (index + 16) << 14; + if (index >= 24) + base_addr += 0x30000; + + if (scat_regs[SCAT_EMS_CONTROL] & 0x80) { + if (val & 0x80) { + virt_addr = get_scat_addr(base_addr, &scat_stat[index]); + if (index < 24) + mem_mapping_disable(&scat_4000_9FFF_mapping[index]); + if (virt_addr < (mem_size << 10)) + mem_mapping_set_exec(&scat_mapping[index], ram + virt_addr); + else + mem_mapping_set_exec(&scat_mapping[index], NULL); + mem_mapping_enable(&scat_mapping[index]); +// pclog("SCAT: map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); + } else { + mem_mapping_set_exec(&scat_mapping[index], ram + base_addr); + mem_mapping_disable(&scat_mapping[index]); + if (index < 24) + mem_mapping_enable(&scat_4000_9FFF_mapping[index]); +// pclog("SCAT: unmap page %d(address %06X)\n", scat_ems_reg_2xA & 0x1f, base_addr); + } + flushmmucache(); + } + + if (scat_ems_reg_2xA & 0x80) { + scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & (((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0x1f : 3)); + } + } + break; + + case 0x20A: + case 0x21A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { +// pclog("SCAT: write EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + scat_ems_reg_2xA = ((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? val : val & 0xc3; + } + break; + } } -uint8_t scat_read(uint16_t port, void *priv) + +static uint8_t +scat_read(uint16_t port, void *priv) { - uint8_t val = 0xff, index; - switch (port) - { - case 0x23: - switch (scat_index) - { - case SCAT_MISCELLANEOUS_STATUS: - val = (scat_regs[scat_index] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); - break; - case SCAT_DRAM_CONFIGURATION: - if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) val = (scat_regs[scat_index] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10); - else if(mem_size != 1024) val = (scat_regs[scat_index] & 0xe0) | scatsx_mem_conf_val[mem_size >> 9]; - else val = scat_regs[scat_index]; - break; - default: - val = scat_regs[scat_index]; - break; - } -// pclog("Read SCAT Register %02X at %04X:%04X\n", scat_index, CS, cpu_state.pc); - break; + uint8_t val = 0xff, index; - case 0x92: - val = scat_port_92; - break; + switch (port) { + case 0x23: + switch (scat_index) { + case SCAT_MISCELLANEOUS_STATUS: + val = (scat_regs[scat_index] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); + break; - case 0x208: - case 0x218: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - { -// pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; - else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; - val = scat_stat[index].regs_2x8; - } - break; - case 0x209: - case 0x219: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - { -// pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); - if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; - else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; - val = scat_stat[index].regs_2x9; - } - break; - case 0x20A: - case 0x21A: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) - { -// pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); - val = scat_ems_reg_2xA; - } - break; - } - return val; + case SCAT_DRAM_CONFIGURATION: + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) + val = (scat_regs[scat_index] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10); + else + if (mem_size != 1024) + val = (scat_regs[scat_index] & 0xe0) | scatsx_mem_conf_val[mem_size >> 9]; + else + val = scat_regs[scat_index]; + break; + + default: + val = scat_regs[scat_index]; + break; + } +// pclog("SCAT: read Register %02X at %04X:%04X\n", scat_index, CS, cpu_state.pc); + break; + + case 0x92: + val = scat_port_92; + break; + + case 0x208: + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { +// pclog("SCAT: read EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) + index = scat_ems_reg_2xA & 0x1F; + else + index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; + val = scat_stat[index].regs_2x8; + } + break; + + case 0x209: + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { +// pclog("SCAT: read EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) + index = scat_ems_reg_2xA & 0x1F; + else + index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; + val = scat_stat[index].regs_2x9; + } + break; + + case 0x20A: + case 0x21A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { +// pclog("SCAT: read EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + val = scat_ems_reg_2xA; + } + break; + } + + return val; } -uint8_t mem_read_scatems(uint32_t addr, void *priv) + +static uint8_t +mem_read_scatems(uint32_t addr, void *priv) { - uint8_t val = 0xff; - scat_t *stat = (scat_t *)priv; + scat_t *stat = (scat_t *)priv; + uint8_t val = 0xff; - addr = get_scat_addr(addr, stat); - if (addr < (mem_size << 10)) - val = mem_read_ram(addr, priv); + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = mem_read_ram(addr, priv); - return val; + return val; } -void mem_write_scatems(uint32_t addr, uint8_t val, void *priv) -{ - scat_t *stat = (scat_t *)priv; - addr = get_scat_addr(addr, stat); - if (addr < (mem_size << 10)) - mem_write_ram(addr, val, priv); +static void +mem_write_scatems(uint32_t addr, uint8_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + mem_write_ram(addr, val, priv); } static void scat_init(void) { - int i; + int i; - io_sethandler(0x0022, 2, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0022, 2, + scat_read,NULL,NULL, scat_write,NULL,NULL, NULL); - port_92_reset(); + port_92_reset(); - port_92_add(); + port_92_add(); - for (i = 0; i < 256; i++) - { - scat_regs[i] = 0xff; - } + for (i = 0; i < 256; i++) + scat_regs[i] = 0xff; - scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; - scat_regs[SCAT_VERSION] = 4; - scat_regs[SCAT_CLOCK_CONTROL] = 2; - scat_regs[SCAT_PERIPHERAL_CONTROL] = 0x80; - scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; - scat_regs[SCAT_POWER_MANAGEMENT] = 0; - scat_regs[SCAT_ROM_ENABLE] = 0xC0; - scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; - scat_regs[SCAT_DRAM_CONFIGURATION] = cpu_waitstates == 1 ? 2 : 0x12; - scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; - scat_regs[SCAT_EMS_CONTROL] = 0; - scat_port_92 = 0; + scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + scat_regs[SCAT_VERSION] = 4; + scat_regs[SCAT_CLOCK_CONTROL] = 2; + scat_regs[SCAT_PERIPHERAL_CONTROL] = 0x80; + scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + scat_regs[SCAT_POWER_MANAGEMENT] = 0; + scat_regs[SCAT_ROM_ENABLE] = 0xC0; + scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + scat_regs[SCAT_DRAM_CONFIGURATION] = cpu_waitstates == 1 ? 2 : 0x12; + scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; + scat_regs[SCAT_EMS_CONTROL] = 0; + scat_port_92 = 0; - mem_mapping_set_addr(&ram_low_mapping, 0, 0x40000); + mem_mapping_set_addr(&ram_low_mapping, 0, 0x40000); - for (i = 0; i < 24; i++) - { - mem_mapping_add(&scat_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&scat_4000_9FFF_mapping[i]); - } + for (i = 0; i < 24; i++) { + mem_mapping_add(&scat_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&scat_4000_9FFF_mapping[i]); + } - mem_mapping_add(&scat_A000_BFFF_mapping, 0xA0000, 0x20000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&scat_A000_BFFF_mapping); + mem_mapping_add(&scat_A000_BFFF_mapping, 0xA0000, 0x20000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&scat_A000_BFFF_mapping); - for (i = 0; i < 32; i++) - { - scat_stat[i].regs_2x8 = 0xff; - scat_stat[i].regs_2x9 = 0x03; - mem_mapping_add(&scat_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); - mem_mapping_disable(&scat_mapping[i]); - } + for (i = 0; i < 32; i++) { + scat_stat[i].regs_2x8 = 0xff; + scat_stat[i].regs_2x9 = 0x03; + mem_mapping_add(&scat_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); + mem_mapping_disable(&scat_mapping[i]); + } - for(i=4;i<10;i++) isram[i] = 0; + for (i=4;i<10;i++) + isram[i] = 0; - /* TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. + /* TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. Normal CPU accessing address FC0000 to FEFFFF map to ROM should be implemented later. */ - for (i = 12; i < 16; i++) - { - mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), 0, NULL); - } + for (i = 12; i < 16; i++) { + mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), 0, NULL); + } - for(i=0;i<6;i++) - mem_mapping_add(&scat_shadowram_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); + for (i = 0; i < 6; i++) + mem_mapping_add(&scat_shadowram_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); - scat_set_xms_bound(0); - scat_shadow_state_update(); + scat_set_xms_bound(0); + scat_shadow_state_update(); } static void scatsx_init(void) { - int i; + int i; - io_sethandler(0x0022, 0x0002, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0022, 2, + scat_read,NULL,NULL, scat_write,NULL,NULL, NULL); - port_92_reset(); + port_92_reset(); - port_92_add(); + port_92_add(); - for (i = 0; i < 256; i++) - { - scat_regs[i] = 0xff; - } + for (i = 0; i < 256; i++) + scat_regs[i] = 0xff; - scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; - scat_regs[SCAT_VERSION] = 0x13; - scat_regs[SCAT_CLOCK_CONTROL] = 6; - scat_regs[SCAT_PERIPHERAL_CONTROL] = 0; - scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; - scat_regs[SCAT_POWER_MANAGEMENT] = 0; - scat_regs[SCAT_ROM_ENABLE] = 0xC0; - scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; - scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; - scat_regs[SCAT_DRAM_CONFIGURATION] = 1; - scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; - scat_regs[SCAT_EMS_CONTROL] = 0; - scat_regs[SCATSX_LAPTOP_FEATURES] = 0; - scat_regs[SCATSX_FAST_VIDEO_CONTROL] = 0; - scat_regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0; - scat_regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8; - scat_regs[SCATSX_CAS_TIMING_FOR_DMA] = 3; - scat_port_92 = 0; + scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + scat_regs[SCAT_VERSION] = 0x13; + scat_regs[SCAT_CLOCK_CONTROL] = 6; + scat_regs[SCAT_PERIPHERAL_CONTROL] = 0; + scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + scat_regs[SCAT_POWER_MANAGEMENT] = 0; + scat_regs[SCAT_ROM_ENABLE] = 0xC0; + scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + scat_regs[SCAT_DRAM_CONFIGURATION] = 1; + scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; + scat_regs[SCAT_EMS_CONTROL] = 0; + scat_regs[SCATSX_LAPTOP_FEATURES] = 0; + scat_regs[SCATSX_FAST_VIDEO_CONTROL] = 0; + scat_regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0; + scat_regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8; + scat_regs[SCATSX_CAS_TIMING_FOR_DMA] = 3; + scat_port_92 = 0; - mem_mapping_set_addr(&ram_low_mapping, 0, 0x80000); + mem_mapping_set_addr(&ram_low_mapping, 0, 0x80000); - for (i = 16; i < 24; i++) - { - mem_mapping_add(&scat_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&scat_4000_9FFF_mapping[i]); - } + for (i = 16; i < 24; i++) { + mem_mapping_add(&scat_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&scat_4000_9FFF_mapping[i]); + } - mem_mapping_add(&scat_A000_BFFF_mapping, 0xA0000, 0x20000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&scat_A000_BFFF_mapping); + mem_mapping_add(&scat_A000_BFFF_mapping, 0xA0000, 0x20000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&scat_A000_BFFF_mapping); - for (i = 24; i < 32; i++) - { - scat_stat[i].regs_2x8 = 0xff; - scat_stat[i].regs_2x9 = 0x03; - mem_mapping_add(&scat_mapping[i], (i + 28) << 14, 0x04000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + ((i + 28) << 14), 0, &scat_stat[i]); - mem_mapping_disable(&scat_mapping[i]); - } + for (i = 24; i < 32; i++) { + scat_stat[i].regs_2x8 = 0xff; + scat_stat[i].regs_2x9 = 0x03; + mem_mapping_add(&scat_mapping[i], (i + 28) << 14, 0x04000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + ((i + 28) << 14), 0, &scat_stat[i]); + mem_mapping_disable(&scat_mapping[i]); + } - /* TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. - Normal CPU accessing address FC0000 to FEFFFF map to ROM should be implemented later. */ - for (i = 12; i < 16; i++) - { - mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), 0, NULL); - } + /* TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. + Normal CPU accessing address FC0000 to FEFFFF map to ROM should be implemented later. */ + for (i = 12; i < 16; i++) + mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), 0, NULL); - for(i=0;i<6;i++) - mem_mapping_add(&scat_shadowram_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); + for (i = 0; i < 6; i++) + mem_mapping_add(&scat_shadowram_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); - scat_set_xms_bound(0); - scat_shadow_state_update(); + scat_set_xms_bound(0); + scat_shadow_state_update(); } void -machine_at_scat_init(const machine_t *model) +machine_at_scat_init(const machine_t *model, void *arg) { - machine_at_init(model); + machine_at_init(model, arg); + device_add(&fdc_at_device); scat_init(); @@ -744,9 +758,9 @@ machine_at_scat_init(const machine_t *model) void -machine_at_scatsx_init(const machine_t *model) +machine_at_scatsx_init(const machine_t *model, void *arg) { - machine_at_common_init(model); + machine_at_common_init(model, arg); device_add(&keyboard_at_ami_device); diff --git a/src/machine/m_at_sis_85c471.c b/src/machine/m_at_sis_85c471.c index 3382487..be5480d 100644 --- a/src/machine/m_at_sis_85c471.c +++ b/src/machine/m_at_sis_85c471.c @@ -12,7 +12,7 @@ * * Used by DTK PKM-0038S E-2 * - * Version: @(#)m_at_sis85c471.c 1.0.3 2018/03/15 + * Version: @(#)m_at_sis85c471.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -55,220 +55,226 @@ #include "machine.h" -static int sis_85c471_curreg; -static uint8_t sis_85c471_regs[39]; +static int sis_curreg; +static uint8_t sis_regs[39]; -static void sis_85c471_write(uint16_t port, uint8_t val, void *priv) +static void +sis_write(uint16_t port, uint8_t val, void *priv) { - uint8_t index = (port & 1) ? 0 : 1; - uint8_t x; + uint8_t index = (port & 1) ? 0 : 1; + uint8_t x; - if (index) - { - if ((val >= 0x50) && (val <= 0x76)) sis_85c471_curreg = val; - return; - } - else - { - if ((sis_85c471_curreg < 0x50) || (sis_85c471_curreg > 0x76)) return; - x = val ^ sis_85c471_regs[sis_85c471_curreg - 0x50]; - /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ - if (sis_85c471_curreg != 0x52) sis_85c471_regs[sis_85c471_curreg - 0x50] = val; - goto process_value; - } + if (index) { + if ((val >= 0x50) && (val <= 0x76)) + sis_curreg = val; return; + } -process_value: - switch(sis_85c471_curreg) - { - case 0x73: + if ((sis_curreg < 0x50) || (sis_curreg > 0x76)) return; + + x = val ^ sis_regs[sis_curreg - 0x50]; + /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ + if (sis_curreg != 0x52) + sis_regs[sis_curreg - 0x50] = val; + + switch(sis_curreg) { + case 0x73: #if 0 - if (x & 0x40) - { - if (val & 0x40) - ide_pri_enable(); - else - ide_pri_disable(); - } -#endif - - if (x & 0x20) - { - if (val & 0x20) - { - serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); - serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); - } - else - { - serial_remove(1); - serial_remove(2); - } - } - - if (x & 0x10) - { - if (val & 0x10) - lpt1_init(0x378); - else - lpt1_remove(); - } - - break; - } - sis_85c471_curreg = 0; -} - - -static uint8_t sis_85c471_read(uint16_t port, void *priv) -{ - uint8_t index = (port & 1) ? 0 : 1; - uint8_t temp; - - if (index) - return sis_85c471_curreg; - else - if ((sis_85c471_curreg >= 0x50) && (sis_85c471_curreg <= 0x76)) - { - temp = sis_85c471_regs[sis_85c471_curreg - 0x50]; - sis_85c471_curreg = 0; - return temp; - } - else - return 0xFF; -} - - -static void sis_85c471_init(void) -{ - int i = 0; - - lpt2_remove(); - - sis_85c471_curreg = 0; - for (i = 0; i < 0x27; i++) - { - sis_85c471_regs[i] = 0; - } - sis_85c471_regs[9] = 0x40; - switch (mem_size) - { - case 0: - case 1: - sis_85c471_regs[9] |= 0; - break; - case 2: - case 3: - sis_85c471_regs[9] |= 1; - break; - case 4: - sis_85c471_regs[9] |= 2; - break; - case 5: - sis_85c471_regs[9] |= 0x20; - break; - case 6: - case 7: - sis_85c471_regs[9] |= 9; - break; - case 8: - case 9: - sis_85c471_regs[9] |= 4; - break; - case 10: - case 11: - sis_85c471_regs[9] |= 5; - break; - case 12: - case 13: - case 14: - case 15: - sis_85c471_regs[9] |= 0xB; - break; - case 16: - sis_85c471_regs[9] |= 0x13; - break; - case 17: - sis_85c471_regs[9] |= 0x21; - break; - case 18: - case 19: - sis_85c471_regs[9] |= 6; - break; - case 20: - case 21: - case 22: - case 23: - sis_85c471_regs[9] |= 0xD; - break; - case 24: - case 25: - case 26: - case 27: - case 28: - case 29: - case 30: - case 31: - sis_85c471_regs[9] |= 0xE; - break; - case 32: - case 33: - case 34: - case 35: - sis_85c471_regs[9] |= 0x1B; - break; - case 36: - case 37: - case 38: - case 39: - sis_85c471_regs[9] |= 0xF; - break; - case 40: - case 41: - case 42: - case 43: - case 44: - case 45: - case 46: - case 47: - sis_85c471_regs[9] |= 0x17; - break; - case 48: - sis_85c471_regs[9] |= 0x1E; - break; - default: - if (mem_size < 64) - { - sis_85c471_regs[9] |= 0x1E; - } - else if ((mem_size >= 65) && (mem_size < 68)) - { - sis_85c471_regs[9] |= 0x22; - } + if (x & 0x40) { + if (val & 0x40) + ide_pri_enable(); else - { - sis_85c471_regs[9] |= 0x24; + ide_pri_disable(); + } +#endif + if (x & 0x20) { + if (val & 0x20) { + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + } else { + serial_remove(1); + serial_remove(2); } - break; - } + } - sis_85c471_regs[0x11] = 9; - sis_85c471_regs[0x12] = 0xFF; - sis_85c471_regs[0x23] = 0xF0; - sis_85c471_regs[0x26] = 1; + if (x & 0x10) { + if (val & 0x10) + lpt1_init(0x378); + else + lpt1_remove(); + } - io_sethandler(0x0022, 0x0002, sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, NULL); + break; + } + + sis_curreg = 0; +} + + +static uint8_t +sis_read(uint16_t port, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t temp; + + if (index) + return sis_curreg; + + if ((sis_curreg >= 0x50) && (sis_curreg <= 0x76)) { + temp = sis_regs[sis_curreg - 0x50]; + sis_curreg = 0; + return temp; + } + + return 0xFF; +} + + +static void +sis_init(void) +{ + int i = 0; + + lpt2_remove(); + + sis_curreg = 0; + for (i = 0; i < 0x27; i++) + sis_regs[i] = 0; + sis_regs[9] = 0x40; + + switch (mem_size) { + case 0: + case 1: + sis_regs[9] |= 0; + break; + + case 2: + case 3: + sis_regs[9] |= 1; + break; + + case 4: + sis_regs[9] |= 2; + break; + + case 5: + sis_regs[9] |= 0x20; + break; + + case 6: + case 7: + sis_regs[9] |= 9; + break; + + case 8: + case 9: + sis_regs[9] |= 4; + break; + + case 10: + case 11: + sis_regs[9] |= 5; + break; + + case 12: + case 13: + case 14: + case 15: + sis_regs[9] |= 0xB; + break; + + case 16: + sis_regs[9] |= 0x13; + break; + + case 17: + sis_regs[9] |= 0x21; + break; + + case 18: + case 19: + sis_regs[9] |= 6; + break; + + case 20: + case 21: + case 22: + case 23: + sis_regs[9] |= 0xD; + break; + + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + sis_regs[9] |= 0xE; + break; + + case 32: + case 33: + case 34: + case 35: + sis_regs[9] |= 0x1B; + break; + + case 36: + case 37: + case 38: + case 39: + sis_regs[9] |= 0xF; + break; + + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + sis_regs[9] |= 0x17; + break; + + case 48: + sis_regs[9] |= 0x1E; + break; + + default: + if (mem_size < 64) { + sis_regs[9] |= 0x1E; + } else if ((mem_size >= 65) && (mem_size < 68)) { + sis_regs[9] |= 0x22; + } else { + sis_regs[9] |= 0x24; + } + break; + } + + sis_regs[0x11] = 9; + sis_regs[0x12] = 0xFF; + sis_regs[0x23] = 0xF0; + sis_regs[0x26] = 1; + + io_sethandler(0x0022, 2, + sis_read,NULL,NULL, sis_write,NULL,NULL, NULL); } void -machine_at_dtk486_init(const machine_t *model) +machine_at_dtk486_init(const machine_t *model, void *arg) { - machine_at_ide_init(model); + machine_at_ide_init(model, arg); + device_add(&fdc_at_device); memregs_init(); - sis_85c471_init(); + + sis_init(); + secondary_ide_check(); } diff --git a/src/machine/m_at_sis_85c496.c b/src/machine/m_at_sis_85c496.c index b31bb54..8e3ea83 100644 --- a/src/machine/m_at_sis_85c496.c +++ b/src/machine/m_at_sis_85c496.c @@ -8,7 +8,7 @@ * * Implementation of the SiS 85C496 chipset. * - * Version: @(#)m_at_sis_85c496.c 1.0.3 2018/03/15 + * Version: @(#)m_at_sis_85c496.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,171 +53,190 @@ #include "machine.h" -typedef struct sis_85c496_t -{ - uint8_t pci_conf[256]; +typedef struct { + uint8_t pci_conf[256]; } sis_85c496_t; sis_85c496_t sis496; -static void sis_85c496_recalcmapping(void) +static void +recalc_mapping(void) { - int c; - - for (c = 0; c < 8; c++) - { - uint32_t base = 0xc0000 + (c << 15); - if (sis496.pci_conf[0x44] & (1 << c)) - { - switch (sis496.pci_conf[0x45] & 3) - { - case 0: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); - break; - case 1: - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - break; - case 2: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - break; - case 3: - mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); - break; - } - } - else - mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - } + uint32_t base; + int c; - flushmmucache(); - shadowbios = (sis496.pci_conf[0x44] & 0xf0); -} + for (c = 0; c < 8; c++) { + base = 0xc0000 + (c << 15); + if (sis496.pci_conf[0x44] & (1 << c)) { + switch (sis496.pci_conf[0x45] & 3) { + case 0: + mem_set_mem_state(base, 0x8000, + MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; -static void sis_85c496_write(int func, int addr, uint8_t val, void *p) -{ - switch (addr) - { - case 0x44: /*Shadow configure*/ - if ((sis496.pci_conf[0x44] & val) ^ 0xf0) - { - sis496.pci_conf[0x44] = val; - sis_85c496_recalcmapping(); - } - break; - case 0x45: /*Shadow configure*/ - if ((sis496.pci_conf[0x45] & val) ^ 0x01) - { - sis496.pci_conf[0x45] = val; - sis_85c496_recalcmapping(); - } - break; - - case 0xc0: - if (val & 0x80) - pci_set_irq_routing(PCI_INTA, val & 0xf); - else - pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); - break; - case 0xc1: - if (val & 0x80) - pci_set_irq_routing(PCI_INTB, val & 0xf); - else - pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); - break; - case 0xc2: - if (val & 0x80) - pci_set_irq_routing(PCI_INTC, val & 0xf); - else - pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); - break; - case 0xc3:// pclog("IRQ routing %02x %02x\n", addr, val); - if (val & 0x80) - pci_set_irq_routing(PCI_INTD, val & 0xf); - else - pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); - break; - } - - if ((addr >= 4 && addr < 8) || addr >= 0x40) - sis496.pci_conf[addr] = val; -} + case 1: + mem_set_mem_state(base, 0x8000, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(base, 0x8000, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; -static uint8_t sis_85c496_read(int func, int addr, void *p) -{ - return sis496.pci_conf[addr]; -} - + case 3: + mem_set_mem_state(base, 0x8000, + MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } else { + mem_set_mem_state(base, 0x8000, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } -static void sis_85c496_reset(void) -{ - memset(&sis496, 0, sizeof(sis_85c496_t)); - - sis496.pci_conf[0x00] = 0x39; /*SiS*/ - sis496.pci_conf[0x01] = 0x10; - sis496.pci_conf[0x02] = 0x96; /*496/497*/ - sis496.pci_conf[0x03] = 0x04; + flushmmucache(); - sis496.pci_conf[0x04] = 7; - sis496.pci_conf[0x05] = 0; - - sis496.pci_conf[0x06] = 0x80; - sis496.pci_conf[0x07] = 0x02; - - sis496.pci_conf[0x08] = 2; /*Device revision*/ - - sis496.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ - sis496.pci_conf[0x0a] = 0x00; - sis496.pci_conf[0x0b] = 0x06; - - sis496.pci_conf[0x0e] = 0x00; /*Single function device*/ -} - - -static void sis_85c496_pci_reset(void) -{ - uint8_t val = 0; - - val = sis_85c496_read(0, 0x44, NULL); /* Read current value of 0x44. */ - sis_85c496_write(0, 0x44, val & 0xf, NULL); /* Turn off shadow BIOS but keep the lower 4 bits. */ -} - - -static void sis_85c496_init(void) -{ - pci_add_card(5, sis_85c496_read, sis_85c496_write, NULL); - - sis_85c496_reset(); - - pci_reset_handler.pci_master_reset = sis_85c496_pci_reset; + shadowbios = (sis496.pci_conf[0x44] & 0xf0); } static void -machine_at_sis_85c496_common_init(const machine_t *model) +sis_write(int func, int addr, uint8_t val, void *p) { - machine_at_ps2_init(model); - device_add(&ide_pci_device); + switch (addr) { + case 0x44: /*Shadow configure*/ + if ((sis496.pci_conf[0x44] & val) ^ 0xf0) { + sis496.pci_conf[0x44] = val; + recalc_mapping(); + } + break; - memregs_init(); - pci_init(PCI_CONFIG_TYPE_1); - pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); - pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); - pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); - pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); - pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + case 0x45: /*Shadow configure*/ + if ((sis496.pci_conf[0x45] & val) ^ 0x01) { + sis496.pci_conf[0x45] = val; + recalc_mapping(); + } + break; - sis_85c496_init(); + case 0xc0: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, val & 0xf); + else + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + break; + + case 0xc1: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, val & 0xf); + else + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + break; + + case 0xc2: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, val & 0xf); + else + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + break; + + case 0xc3:// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, val & 0xf); + else + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + break; + } + + if ((addr >= 4 && addr < 8) || addr >= 0x40) + sis496.pci_conf[addr] = val; +} + + +static uint8_t +sis_read(int func, int addr, void *p) +{ + return sis496.pci_conf[addr]; +} + + +static void +sis_reset(void) +{ + memset(&sis496, 0, sizeof(sis_85c496_t)); + + sis496.pci_conf[0x00] = 0x39; /*SiS*/ + sis496.pci_conf[0x01] = 0x10; + sis496.pci_conf[0x02] = 0x96; /*496/497*/ + sis496.pci_conf[0x03] = 0x04; + + sis496.pci_conf[0x04] = 7; + sis496.pci_conf[0x05] = 0; + + sis496.pci_conf[0x06] = 0x80; + sis496.pci_conf[0x07] = 0x02; + + sis496.pci_conf[0x08] = 2; /*Device revision*/ + + sis496.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis496.pci_conf[0x0a] = 0x00; + sis496.pci_conf[0x0b] = 0x06; + + sis496.pci_conf[0x0e] = 0x00; /*Single function device*/ +} + + +static void +sis_pci_reset(void) +{ + uint8_t val = 0; + + /* Read current value of 0x44. */ + val = sis_read(0, 0x44, NULL); + + /* Turn off shadow BIOS but keep the lower 4 bits. */ + sis_write(0, 0x44, val & 0xf, NULL); +} + + +static void +sis_init(void) +{ + pci_add_card(5, sis_read, sis_write, NULL); + + sis_reset(); + + pci_reset_handler.pci_master_reset = sis_pci_reset; +} + + +static void +machine_at_sis_85c496_common_init(const machine_t *model, void *arg) +{ + machine_at_ps2_init(model, arg); + + device_add(&ide_pci_device); + + memregs_init(); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + + sis_init(); } void -machine_at_r418_init(const machine_t *model) +machine_at_r418_init(const machine_t *model, void *arg) { - machine_at_sis_85c496_common_init(model); + machine_at_sis_85c496_common_init(model, arg); - fdc37c665_init(); + fdc37c665_init(); } diff --git a/src/machine/m_at_t3100e.c b/src/machine/m_at_t3100e.c index 24355da..7f5ec1d 100644 --- a/src/machine/m_at_t3100e.c +++ b/src/machine/m_at_t3100e.c @@ -117,7 +117,7 @@ * bit 2 set for single-pixel LCD font * bits 0,1 for display font * - * Version: @(#)m_at_t3100e.c 1.0.4 2018/03/15 + * Version: @(#)m_at_t3100e.c 1.0.5 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -163,600 +163,624 @@ #include "m_at_t3100e.h" -extern uint8_t *ram; /* Physical RAM */ - - -static const int t3100e_log = 0; - - /* The T3100e motherboard can (and does) dynamically reassign RAM between * conventional, XMS and EMS. This translates to monkeying with the mappings. */ extern mem_mapping_t base_mapping; - extern mem_mapping_t ram_low_mapping; /* This is to switch conventional RAM * between 512k and 640k */ - extern mem_mapping_t ram_mid_mapping; /* This will not be used */ - extern mem_mapping_t ram_high_mapping; /* This is RAM beyond 1Mb if any */ -extern uint8_t *ram; -static unsigned t3100e_ems_page_reg[] = -{ - 0x208, 0x4208, 0x8208, 0xc208, /* The first four map the first 2Mb */ +static unsigned t3100e_ems_page_reg[] = { + 0x0208, 0x4208, 0x8208, 0xc208, /* The first four map the first 2Mb */ /* of RAM into the page frame */ - 0x218, 0x4218, 0x8218, 0xc218, /* The next four map the next 2Mb */ + 0x0218, 0x4218, 0x8218, 0xc218, /* The next four map the next 2Mb */ /* of RAM */ - 0x258, 0x4258, 0x8258, 0xc258, /* and so on. */ - 0x268, 0x4268, 0x8268, 0xc268, + 0x0258, 0x4258, 0x8258, 0xc258, /* and so on. */ + 0x0268, 0x4268, 0x8268, 0xc268, }; -struct t3100e_ems_regs -{ - uint8_t page[16]; - mem_mapping_t mapping[4]; - uint32_t page_exec[4]; /* Physical location of memory pages */ - uint32_t upper_base; /* Start of upper RAM */ - uint8_t upper_pages; /* Pages of EMS available from upper RAM */ - uint8_t upper_is_ems; /* Upper RAM is EMS? */ - mem_mapping_t upper_mapping; - uint8_t notify; /* Notification from keyboard controller */ - uint8_t turbo; /* 0 for 6MHz, else full speed */ - uint8_t mono; /* Emulates PC/AT 'mono' motherboard switch */ + +struct t3100e_ems_regs { + uint8_t page[16]; + mem_mapping_t mapping[4]; + uint32_t page_exec[4]; /* Physical location of memory pages */ + uint32_t upper_base; /* Start of upper RAM */ + uint8_t upper_pages; /* Pages of EMS available from upper RAM */ + uint8_t upper_is_ems; /* Upper RAM is EMS? */ + mem_mapping_t upper_mapping; + uint8_t notify; /* Notification from keyboard controller */ + uint8_t turbo; /* 0 for 6MHz, else full speed */ + uint8_t mono; /* Emulates PC/AT 'mono' motherboard switch */ /* Bit 0 is 0 for colour, 1 for mono */ } t3100e_ems; -void t3100e_ems_out(uint16_t addr, uint8_t val, void *p); + +static void t3100e_ems_out(uint16_t addr, uint8_t val, void *p); /* Given a memory address (which ought to be in the page frame at 0xD0000), * which page does it relate to? */ -static int addr_to_page(uint32_t addr) +static int +addr_to_page(uint32_t addr) { - if ((addr & 0xF0000) == 0xD0000) - { - return ((addr >> 14) & 3); - } - return -1; + if ((addr & 0xF0000) == 0xD0000) + return ((addr >> 14) & 3); + + return -1; } + /* And vice versa: Given a page slot, which memory address does it * correspond to? */ -static uint32_t page_to_addr(int pg) +static uint32_t +page_to_addr(int pg) { - return 0xD0000 + ((pg & 3) * 16384); + return 0xD0000 + ((pg & 3) * 16384); } + /* Given an EMS page ID, return its physical address in RAM. */ -uint32_t t3100e_ems_execaddr(struct t3100e_ems_regs *regs, +uint32_t +t3100e_ems_execaddr(struct t3100e_ems_regs *regs, int pg, uint16_t val) { - uint32_t addr; + uint32_t addr; - if (!(val & 0x80)) return 0; /* Bit 7 reset => not mapped */ + if (!(val & 0x80)) return 0; /* Bit 7 reset => not mapped */ - val &= 0x7F; - val += (0x80 * (pg >> 2)); /* The high bits of the register bank */ + val &= 0x7F; + val += (0x80 * (pg >> 2)); /* high bits of the register bank */ /* are used to extend val to allow up */ /* to 8Mb of EMS to be accessed */ - /* Is it in the upper memory range? */ - if (regs->upper_is_ems) - { - if (val < regs->upper_pages) - { - addr = regs->upper_base + 0x4000 * val; - return addr; - } - val -= regs->upper_pages; + /* Is it in the upper memory range? */ + if (regs->upper_is_ems) { + if (val < regs->upper_pages) { + addr = regs->upper_base + 0x4000 * val; + return addr; } - /* Otherwise work down from the top of high RAM (so, the more EMS, - * the less XMS) */ - if ((val * 0x4000) + 0x100000 >= (mem_size * 1024)) - { - return 0; /* Not enough high RAM for this page */ - } - /* High RAM found */ - addr = (mem_size * 1024) - 0x4000 * (val + 1); + val -= regs->upper_pages; + } - return addr; + /* Otherwise work down from the top of high RAM (so, the more EMS, + * the less XMS) */ + if ((val * 0x4000) + 0x100000 >= (mem_size * 1024)) + return 0; /* Not enough high RAM for this page */ + + /* High RAM found */ + addr = (mem_size * 1024) - 0x4000 * (val + 1); + + return addr; } /* The registers governing the EMS ports are in rather a nonintuitive order */ -static int port_to_page(uint16_t addr) +static int +port_to_page(uint16_t addr) { - switch (addr) - { - case 0x208: return 0; - case 0x4208: return 1; - case 0x8208: return 2; - case 0xC208: return 3; - case 0x218: return 4; - case 0x4218: return 5; - case 0x8218: return 6; - case 0xC218: return 7; - case 0x258: return 8; - case 0x4258: return 9; - case 0x8258: return 10; - case 0xC258: return 11; - case 0x268: return 12; - case 0x4268: return 13; - case 0x8268: return 14; - case 0xC268: return 15; - } - return -1; + switch (addr) { + case 0x208: return 0; + case 0x4208: return 1; + case 0x8208: return 2; + case 0xC208: return 3; + case 0x218: return 4; + case 0x4218: return 5; + case 0x8218: return 6; + case 0xC218: return 7; + case 0x258: return 8; + case 0x4258: return 9; + case 0x8258: return 10; + case 0xC258: return 11; + case 0x268: return 12; + case 0x4268: return 13; + case 0x8268: return 14; + case 0xC268: return 15; + } + + return -1; } -/* Used to dump the memory mapping table, for debugging -void dump_mappings() + +#if NOTUSED +/* Used to dump the memory mapping table, for debugging. */ +static void +dump_mappings(void) { - mem_mapping_t *mm = base_mapping.next; + mem_mapping_t *mm = base_mapping.next; - if (!t3100e_log) return; - while (mm) - { - const char *name = ""; - uint32_t offset = (uint32_t)(mm->exec - ram); + if (!t3100e_log) return; - if (mm == &ram_low_mapping ) name = "LOW "; - if (mm == &ram_mid_mapping ) name = "MID "; - if (mm == &ram_high_mapping) name = "HIGH"; - if (mm == &t3100e_ems.upper_mapping) name = "UPPR"; - if (mm == &t3100e_ems.mapping[0]) - { - name = "EMS0"; - offset = t3100e_ems.page_exec[0]; - } - if (mm == &t3100e_ems.mapping[1]) - { - name = "EMS1"; - offset = t3100e_ems.page_exec[1]; - } - if (mm == &t3100e_ems.mapping[2]) - { - name = "EMS2"; - offset = t3100e_ems.page_exec[2]; - } - if (mm == &t3100e_ems.mapping[3]) - { - name = "EMS3"; - offset = t3100e_ems.page_exec[3]; - } + while (mm) { + const char *name = ""; + uint32_t offset = (uint32_t)(mm->exec - ram); - pclog(" %p | base=%05x size=%05x %c @ %06x %s\n", mm, - mm->base, mm->size, mm->enable ? 'Y' : 'N', - offset, name); - - mm = mm->next; + if (mm == &ram_low_mapping ) name = "LOW "; + if (mm == &ram_mid_mapping ) name = "MID "; + if (mm == &ram_high_mapping) name = "HIGH"; + if (mm == &t3100e_ems.upper_mapping) name = "UPPR"; + if (mm == &t3100e_ems.mapping[0]) { + name = "EMS0"; + offset = t3100e_ems.page_exec[0]; + } + if (mm == &t3100e_ems.mapping[1]) { + name = "EMS1"; + offset = t3100e_ems.page_exec[1]; + } + if (mm == &t3100e_ems.mapping[2]) { + name = "EMS2"; + offset = t3100e_ems.page_exec[2]; + } + if (mm == &t3100e_ems.mapping[3]) { + name = "EMS3"; + offset = t3100e_ems.page_exec[3]; } -}*/ -void t3100e_map_ram(uint8_t val) + pclog(" %p | base=%05x size=%05x %c @ %06x %s\n", mm, + mm->base, mm->size, mm->enable ? 'Y' : 'N', + offset, name); + + mm = mm->next; + } +} +#endif + + +static void +t3100e_map_ram(uint8_t val) { - int n; - int32_t upper_len; + int32_t upper_len; + int n; - if (t3100e_log) - { - pclog("OUT 0x8084, %02x [ set memory mapping :", val | 0x40); - if (val & 1) pclog("ENABLE_EMS "); - if (val & 2) pclog("ENABLE_XMS "); - if (val & 4) pclog("640K "); - if (val & 8) pclog("X8X "); - if (val & 16) pclog("UPPER_IS_XMS "); - pclog("\n"); - } - /* Bit 2 controls size of conventional memory */ - if (val & 4) - { - t3100e_ems.upper_base = 0xA0000; - t3100e_ems.upper_pages = 24; - } - else - { - t3100e_ems.upper_base = 0x80000; - t3100e_ems.upper_pages = 32; - } - upper_len = t3100e_ems.upper_pages * 16384; +#if NOTUSED + if (t3100e_log) { + pclog("OUT 0x8084, %02x [ set memory mapping :", val | 0x40); + if (val & 1) pclog("ENABLE_EMS "); + if (val & 2) pclog("ENABLE_XMS "); + if (val & 4) pclog("640K "); + if (val & 8) pclog("X8X "); + if (val & 16) pclog("UPPER_IS_XMS "); + pclog("\n"); + } +#endif - mem_mapping_set_addr(&ram_low_mapping, 0, t3100e_ems.upper_base); - /* Bit 0 set if upper RAM is EMS */ - t3100e_ems.upper_is_ems = (val & 1); + /* Bit 2 controls size of conventional memory */ + if (val & 4) { + t3100e_ems.upper_base = 0xA0000; + t3100e_ems.upper_pages = 24; + } else { + t3100e_ems.upper_base = 0x80000; + t3100e_ems.upper_pages = 32; + } + upper_len = t3100e_ems.upper_pages * 16384; - /* Bit 1 set if high RAM is enabled */ - if (val & 2) - { - mem_mapping_enable(&ram_high_mapping); - } - else - { - mem_mapping_disable(&ram_high_mapping); - } + mem_mapping_set_addr(&ram_low_mapping, 0, t3100e_ems.upper_base); - /* Bit 4 set if upper RAM is mapped to high memory - * (and bit 1 set if XMS enabled) */ - if ((val & 0x12) == 0x12) - { - mem_mapping_set_addr(&t3100e_ems.upper_mapping, - mem_size * 1024, - upper_len); - mem_mapping_enable(&t3100e_ems.upper_mapping); - mem_mapping_set_exec(&t3100e_ems.upper_mapping, ram + t3100e_ems.upper_base); - } - else - { - mem_mapping_disable(&t3100e_ems.upper_mapping); - } - /* Recalculate EMS mappings */ - for (n = 0; n < 4; n++) - { - t3100e_ems_out(t3100e_ems_page_reg[n], t3100e_ems.page[n], + /* Bit 0 set if upper RAM is EMS */ + t3100e_ems.upper_is_ems = (val & 1); + + /* Bit 1 set if high RAM is enabled */ + if (val & 2) + mem_mapping_enable(&ram_high_mapping); + else + mem_mapping_disable(&ram_high_mapping); + + /* Bit 4 set if upper RAM is mapped to high memory + * (and bit 1 set if XMS enabled) */ + if ((val & 0x12) == 0x12) { + mem_mapping_set_addr(&t3100e_ems.upper_mapping, + mem_size * 1024, + upper_len); + mem_mapping_enable(&t3100e_ems.upper_mapping); + mem_mapping_set_exec(&t3100e_ems.upper_mapping, ram + t3100e_ems.upper_base); + } else { + mem_mapping_disable(&t3100e_ems.upper_mapping); + } + + /* Recalculate EMS mappings */ + for (n = 0; n < 4; n++) + t3100e_ems_out(t3100e_ems_page_reg[n], t3100e_ems.page[n], &t3100e_ems); - } - //dump_mappings(); +#if NOTUSED + dump_mappings(); +#endif } -void t3100e_notify_set(uint8_t value) +static uint8_t +t3100e_sys_in(uint16_t addr, void *p) { - t3100e_ems.notify = value; + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + + /* The low 4 bits always seem to be 0x0C. The high 4 are a + * notification sent by the keyboard controller when it detects + * an [Fn] key combination */ +#if NOTUSED + if (t3100e_log) pclog("IN 0x8084\n"); +#endif + + return 0x0C | (regs->notify << 4); } -void t3100e_mono_set(uint8_t value) -{ - t3100e_ems.mono = value; -} - -uint8_t t3100e_mono_get(void) -{ - return t3100e_ems.mono; -} - -void t3100e_turbo_set(uint8_t value) -{ - t3100e_ems.turbo = value; - if (!value) - { - cpu_dynamic_switch(0); /* 286/6 */ - } - else - { - cpu_dynamic_switch(cpu); - } -} - - - -uint8_t t3100e_sys_in(uint16_t addr, void *p) -{ - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; - - /* The low 4 bits always seem to be 0x0C. The high 4 are a - * notification sent by the keyboard controller when it detects - * an [Fn] key combination */ - if (t3100e_log) pclog("IN 0x8084\n"); - return 0x0C | (regs->notify << 4); -} - - /* Handle writes to the T3100e system control port at 0x8084 */ -void t3100e_sys_out(uint16_t addr, uint8_t val, void *p) +static void +t3100e_sys_out(uint16_t addr, uint8_t val, void *p) { -// struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; +// struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; - switch (val & 0xE0) - { - case 0x00: /* Set serial port IRQs. Not implemented */ - if (t3100e_log) pclog("OUT 0x8084, %02x [ set serial port IRQs]\n", val); - break; - case 0x40: /* Set RAM mappings. */ - t3100e_map_ram(val & 0x1F); - break; + switch (val & 0xE0) { + case 0x00: /* Set serial port IRQs. Not implemented */ +#if NOTUSED + if (t3100e_log) + pclog("OUT 0x8084, %02x [ set serial port IRQs]\n", val); +#endif + break; - case 0x80: /* Set video options. */ - t3100e_video_options_set(val & 0x1F); break; + case 0x40: /* Set RAM mappings. */ + t3100e_map_ram(val & 0x1F); + break; - /* Other options not implemented. */ - default: if (t3100e_log) pclog("OUT 0x8084, %02x\n", val); break; - } -} + case 0x80: /* Set video options. */ + t3100e_video_options_set(val & 0x1F); + break; - -uint8_t t3100e_config_get(void) -{ -/* The byte returned: - Bit 7: Set if internal plasma display enabled - Bit 6: Set if running at 6MHz, clear at full speed - Bit 5: Always 1? - Bit 4: Set if the FD2MB jumper is present (internal floppy is ?tri-mode) - Bit 3: Clear if the FD2 jumper is present (two internal floppies) - Bit 2: Set if the internal drive is A:, clear if B: - Bit 1: Set if the parallel port is configured as a floppy connector - for the second drive. - Bit 0: Set if the F2HD jumper is present (internal floppy is 720k) - */ - uint8_t value = 0x28; /* Start with bits 5 and 3 set. */ - - int type_a = fdd_get_type(0); - int type_b = fdd_get_type(1); - int prt_switch; /* External drive type: 0=> none, 1=>A, 2=>B */ - -/* Get display setting */ - if (t3100e_display_get()) value |= 0x80; - if (!t3100e_ems.turbo) value |= 0x40; - -/* Try to determine the floppy types.*/ - - prt_switch = (type_b ? 2 : 0); - switch(type_a) - { -/* Since a T3100e cannot have an internal 5.25" drive, mark 5.25" A: drive as - * being external, and set the internal type based on type_b. */ - case 1: /* 360k */ - case 2: /* 1.2Mb */ - case 3: /* 1.2Mb RPMx2*/ - prt_switch = 1; /* External drive is A: */ - switch (type_b) - { - case 1: /* 360k */ - case 4: value |= 1; break; /* 720k */ - case 6: value |= 0x10; break; /* Tri-mode */ - /* All others will be treated as 1.4M */ - } - break; - case 4: value |= 0x01; /* 720k */ - if (type_a == type_b) - { - value &= (~8); /* Two internal drives */ - prt_switch = 0; /* No external drive */ - } - break; - case 5: /* 1.4M */ - case 7: /* 2.8M */ - if (type_a == type_b) - { - value &= (~8); /* Two internal drives */ - prt_switch = 0; /* No external drive */ - } - break; - case 6: /* 3-mode */ - value |= 0x10; - if (type_a == type_b) - { - value &= (~8); /* Two internal drives */ - prt_switch = 0; /* No external drive */ - } - break; - } /* End switch */ - switch (prt_switch) - { - case 0: value |= 4; break; /* No external floppy */ - case 1: value |= 2; break; /* External floppy is A: */ - case 2: value |= 6; break; /* External floppy is B: */ - } - return value; + default: /* Other options not implemented. */ +#if NOTUSED + if (t3100e_log) pclog("OUT 0x8084, %02x\n", val); +#endif + break; + } } /* Read EMS page register */ -uint8_t t3100e_ems_in(uint16_t addr, void *p) +static uint8_t +t3100e_ems_in(uint16_t addr, void *p) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; - - return regs->page[port_to_page(addr)]; + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + + return regs->page[port_to_page(addr)]; } + /* Write EMS page register */ -void t3100e_ems_out(uint16_t addr, uint8_t val, void *p) +static void +t3100e_ems_out(uint16_t addr, uint8_t val, void *p) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; - int pg = port_to_page(addr); + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + int pg = port_to_page(addr); - regs->page_exec[pg & 3] = t3100e_ems_execaddr(regs, pg, val); - if (t3100e_log) pclog("EMS: page %d %02x -> %02x [%06x]\n", + regs->page_exec[pg & 3] = t3100e_ems_execaddr(regs, pg, val); +#if UNUSED + if (t3100e_log) pclog("EMS: page %d %02x -> %02x [%06x]\n", pg, regs->page[pg], val, regs->page_exec[pg & 3]); - regs->page[pg] = val; +#endif + regs->page[pg] = val; - pg &= 3; -/* Bit 7 set if page is enabled, reset if page is disabled */ - if (regs->page_exec[pg]) - { - if (t3100e_log) pclog("Enabling EMS RAM at %05x\n", - page_to_addr(pg)); - mem_mapping_enable(®s->mapping[pg]); - mem_mapping_set_exec(®s->mapping[pg], ram + regs->page_exec[pg]); - } - else - { - if (t3100e_log) pclog("Disabling EMS RAM at %05x\n", - page_to_addr(pg)); - mem_mapping_disable(®s->mapping[pg]); - } + /* Bit 7 set if page is enabled, reset if page is disabled */ + pg &= 3; + if (regs->page_exec[pg]) { +#if UNUSED + if (t3100e_log) pclog("Enabling EMS RAM at %05x\n", + page_to_addr(pg)); +#endif + mem_mapping_enable(®s->mapping[pg]); + mem_mapping_set_exec(®s->mapping[pg], ram + regs->page_exec[pg]); + } else { +#if UNUSED + if (t3100e_log) pclog("Disabling EMS RAM at %05x\n", + page_to_addr(pg)); +#endif + mem_mapping_disable(®s->mapping[pg]); + } } /* Read RAM in the EMS page frame */ -static uint8_t ems_read_ram(uint32_t addr, void *priv) +static uint8_t +ems_read_ram(uint32_t addr, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - int pg = addr_to_page(addr); + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); - if (pg < 0) return 0xFF; - addr = regs->page_exec[pg] + (addr & 0x3FFF); - return ram[addr]; + if (pg < 0) return 0xFF; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + return ram[addr]; } - - -static uint16_t ems_read_ramw(uint32_t addr, void *priv) +static uint16_t +ems_read_ramw(uint32_t addr, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - int pg = addr_to_page(addr); + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); - if (pg < 0) return 0xFF; - //pclog("ems_read_ramw addr=%05x ", addr); - addr = regs->page_exec[pg] + (addr & 0x3FFF); - //pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); - return *(uint16_t *)&ram[addr]; + if (pg < 0) return 0xFF; +//pclog("ems_read_ramw addr=%05x ", addr); + addr = regs->page_exec[pg] + (addr & 0x3FFF); +//pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); + return *(uint16_t *)&ram[addr]; } -static uint32_t ems_read_raml(uint32_t addr, void *priv) +static uint32_t +ems_read_raml(uint32_t addr, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - int pg = addr_to_page(addr); + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); - if (pg < 0) return 0xFF; - addr = regs->page_exec[pg] + (addr & 0x3FFF); - return *(uint32_t *)&ram[addr]; + if (pg < 0) return 0xFF; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + + return *(uint32_t *)&ram[addr]; } + /* Write RAM in the EMS page frame */ -static void ems_write_ram(uint32_t addr, uint8_t val, void *priv) +static void +ems_write_ram(uint32_t addr, uint8_t val, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - int pg = addr_to_page(addr); + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); - if (pg < 0) return; - addr = regs->page_exec[pg] + (addr & 0x3FFF); - ram[addr] = val; + if (pg < 0) return; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + ram[addr] = val; } -static void ems_write_ramw(uint32_t addr, uint16_t val, void *priv) +static void +ems_write_ramw(uint32_t addr, uint16_t val, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - int pg = addr_to_page(addr); + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); - if (pg < 0) return; - //pclog("ems_write_ramw addr=%05x ", addr); - addr = regs->page_exec[pg] + (addr & 0x3FFF); - //pclog("-> %06x val=%04x\n", addr, val); + if (pg < 0) return; +//pclog("ems_write_ramw addr=%05x ", addr); + addr = regs->page_exec[pg] + (addr & 0x3FFF); +//pclog("-> %06x val=%04x\n", addr, val); - *(uint16_t *)&ram[addr] = val; + *(uint16_t *)&ram[addr] = val; } -static void ems_write_raml(uint32_t addr, uint32_t val, void *priv) +static void +ems_write_raml(uint32_t addr, uint32_t val, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - int pg = addr_to_page(addr); + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); - if (pg < 0) return; - addr = regs->page_exec[pg] + (addr & 0x3FFF); - *(uint32_t *)&ram[addr] = val; + if (pg < 0) return; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + *(uint32_t *)&ram[addr] = val; } - -/* Read RAM in the upper area. This is basically what the 'remapped' +/* Read RAM in the upper area. This is basically what the 'remapped' * mapping in mem.c does, except that the upper area can move around */ -static uint8_t upper_read_ram(uint32_t addr, void *priv) +static uint8_t +upper_read_ram(uint32_t addr, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - addr = (addr - (1024 * mem_size)) + regs->upper_base; - return ram[addr]; -} - -static uint16_t upper_read_ramw(uint32_t addr, void *priv) -{ - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - - addr = (addr - (1024 * mem_size)) + regs->upper_base; - return *(uint16_t *)&ram[addr]; -} - -static uint32_t upper_read_raml(uint32_t addr, void *priv) -{ - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - - addr = (addr - (1024 * mem_size)) + regs->upper_base; - return *(uint32_t *)&ram[addr]; + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return ram[addr]; } -static void upper_write_ram(uint32_t addr, uint8_t val, void *priv) +static uint16_t +upper_read_ramw(uint32_t addr, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - addr = (addr - (1024 * mem_size)) + regs->upper_base; - ram[addr] = val; + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return *(uint16_t *)&ram[addr]; +} + +static uint32_t +upper_read_raml(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return *(uint32_t *)&ram[addr]; } -static void upper_write_ramw(uint32_t addr, uint16_t val, void *priv) +static void +upper_write_ram(uint32_t addr, uint8_t val, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - addr = (addr - (1024 * mem_size)) + regs->upper_base; - *(uint16_t *)&ram[addr] = val; + addr = (addr - (1024 * mem_size)) + regs->upper_base; + ram[addr] = val; } - -static void upper_write_raml(uint32_t addr, uint32_t val, void *priv) +static void +upper_write_ramw(uint32_t addr, uint16_t val, void *priv) { - struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - addr = (addr - (1024 * mem_size)) + regs->upper_base; - *(uint32_t *)&ram[addr] = val; + addr = (addr - (1024 * mem_size)) + regs->upper_base; + *(uint16_t *)&ram[addr] = val; } - - -void machine_at_t3100e_init(const machine_t *model) +static void +upper_write_raml(uint32_t addr, uint32_t val, void *priv) { - int pg; + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; - memset(&t3100e_ems, 0, sizeof(t3100e_ems)); - - machine_at_common_ide_init(model); + addr = (addr - (1024 * mem_size)) + regs->upper_base; + *(uint32_t *)&ram[addr] = val; +} - device_add(&keyboard_at_toshiba_device); - device_add(&fdc_at_device); - /* Hook up system control port */ - io_sethandler(0x8084, 0x0001, - t3100e_sys_in, NULL, NULL, - t3100e_sys_out, NULL, NULL, &t3100e_ems); +void +machine_at_t3100e_init(const machine_t *model, void *arg) +{ + int pg; - /* Start monitoring all 16 EMS registers */ - for (pg = 0; pg < 16; pg++) - { - io_sethandler(t3100e_ems_page_reg[pg], 0x0001, - t3100e_ems_in, NULL, NULL, - t3100e_ems_out, NULL, NULL, &t3100e_ems); - } + memset(&t3100e_ems, 0x00, sizeof(t3100e_ems)); - /* Map the EMS page frame */ - for (pg = 0; pg < 4; pg++) - { - if (t3100e_log) pclog("Adding memory map at %x for page %d\n", page_to_addr(pg), pg); - mem_mapping_add(&t3100e_ems.mapping[pg], + machine_at_common_ide_init(model, arg); + + device_add(&keyboard_at_toshiba_device); + + device_add(&fdc_at_device); + + /* Hook up system control port */ + io_sethandler(0x8084, 1, + t3100e_sys_in,NULL,NULL, t3100e_sys_out,NULL,NULL, &t3100e_ems); + + /* Start monitoring all 16 EMS registers */ + for (pg = 0; pg < 16; pg++) { + io_sethandler(t3100e_ems_page_reg[pg], 0x0001, + t3100e_ems_in, NULL, NULL, + t3100e_ems_out, NULL, NULL, &t3100e_ems); + } + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { +#if UNUSED + if (t3100e_log) pclog("Adding memory map at %x for page %d\n", page_to_addr(pg), pg); +#endif + mem_mapping_add(&t3100e_ems.mapping[pg], page_to_addr(pg), 16384, ems_read_ram, ems_read_ramw, ems_read_raml, ems_write_ram, ems_write_ramw, ems_write_raml, NULL, MEM_MAPPING_EXTERNAL, &t3100e_ems); - /* Start them all off disabled */ - mem_mapping_disable(&t3100e_ems.mapping[pg]); - } - /* Mapping for upper RAM when in use as XMS*/ - mem_mapping_add(&t3100e_ems.upper_mapping, mem_size * 1024, 384 * 1024, - upper_read_ram, upper_read_ramw, upper_read_raml, - upper_write_ram, upper_write_ramw, upper_write_raml, - NULL, MEM_MAPPING_INTERNAL, &t3100e_ems); - mem_mapping_disable(&t3100e_ems.upper_mapping); - device_add(&t3100e_device); + /* Start them all off disabled */ + mem_mapping_disable(&t3100e_ems.mapping[pg]); + } + + /* Mapping for upper RAM when in use as XMS*/ + mem_mapping_add(&t3100e_ems.upper_mapping, mem_size * 1024, 384 * 1024, + upper_read_ram, upper_read_ramw, upper_read_raml, + upper_write_ram, upper_write_ramw, upper_write_raml, + NULL, MEM_MAPPING_INTERNAL, &t3100e_ems); + + mem_mapping_disable(&t3100e_ems.upper_mapping); + + device_add(&t3100e_device); +} + + +uint8_t +t3100e_config_get(void) +{ + /* The byte returned: + * Bit 7: Set if internal plasma display enabled + * Bit 6: Set if running at 6MHz, clear at full speed + * Bit 5: Always 1? + * Bit 4: Set if the FD2MB jumper is present (internal floppy is ?tri-mode) + * Bit 3: Clear if the FD2 jumper is present (two internal floppies) + * Bit 2: Set if the internal drive is A:, clear if B: + * Bit 1: Set if the parallel port is configured as a floppy connector + * for the second drive. + * Bit 0: Set if the F2HD jumper is present (internal floppy is 720k) + */ + uint8_t value = 0x28; /* Start with bits 5 and 3 set. */ + + int type_a = fdd_get_type(0); + int type_b = fdd_get_type(1); + int prt_switch; /* External drive type: 0=> none, 1=>A, 2=>B */ + + /* Get display setting */ + if (t3100e_display_get()) value |= 0x80; + if (! t3100e_ems.turbo) value |= 0x40; + + /* Try to determine the floppy types.*/ + prt_switch = (type_b ? 2 : 0); + switch(type_a) { + /* + * Since a T3100e cannot have an internal 5.25" drive, + * mark 5.25" A: drive as being external, and set the + * internal type based on type_b. + */ + case 1: /* 360k */ + case 2: /* 1.2Mb */ + case 3: /* 1.2Mb RPMx2*/ + prt_switch = 1; /* External drive is A: */ + switch (type_b) { + case 1: /* 360k */ + case 4: value |= 1; break; /* 720k */ + case 6: value |= 0x10; break; /* Tri-mode */ + /* All others will be treated as 1.4M */ + } + break; + + case 4: + value |= 0x01; /* 720k */ + if (type_a == type_b) { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + + case 5: /* 1.4M */ + case 7: /* 2.8M */ + if (type_a == type_b) { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + + case 6: /* 3-mode */ + value |= 0x10; + if (type_a == type_b) { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + } + + switch (prt_switch) { + case 0: value |= 4; break; /* No external floppy */ + case 1: value |= 2; break; /* External floppy is A: */ + case 2: value |= 6; break; /* External floppy is B: */ + } + + return value; +} + + +void +t3100e_notify_set(uint8_t value) +{ + t3100e_ems.notify = value; +} + + +void +t3100e_mono_set(uint8_t value) +{ + t3100e_ems.mono = value; +} + + +uint8_t +t3100e_mono_get(void) +{ + return t3100e_ems.mono; +} + + +void +t3100e_turbo_set(uint8_t value) +{ + t3100e_ems.turbo = value; + if (! value) + cpu_dynamic_switch(0); /* 286/6 */ + else + cpu_dynamic_switch(cpu); } diff --git a/src/machine/m_at_wd76c10.c b/src/machine/m_at_wd76c10.c index a67be06..932a865 100644 --- a/src/machine/m_at_wd76c10.c +++ b/src/machine/m_at_wd76c10.c @@ -8,7 +8,7 @@ * * Implementation of the WD76C10 system controller. * - * Version: @(#)m_at_wd76c10.c 1.0.2 2018/03/15 + * Version: @(#)m_at_wd76c10.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -176,9 +176,9 @@ wd76c10_init(void) void -machine_at_wd76c10_init(const machine_t *model) +machine_at_wd76c10_init(const machine_t *model, void *arg) { - machine_at_common_ide_init(model); + machine_at_common_ide_init(model, arg); device_add(&keyboard_ps2_quadtel_device); wd76c10_fdc = device_add(&fdc_at_device); diff --git a/src/machine/m_europc.c b/src/machine/m_europc.c index 6355694..67b5f08 100644 --- a/src/machine/m_europc.c +++ b/src/machine/m_europc.c @@ -66,7 +66,7 @@ * bit 1: b8000 memory available * 0000:046a: 00 jim 250 01 jim 350 * - * Version: @(#)m_europc.c 1.0.4 2018/03/19 + * Version: @(#)m_europc.c 1.0.5 2018/03/21 * * Author: Fred N. van Kempen, * @@ -711,13 +711,13 @@ const device_t europc_device = { * user. */ void -machine_europc_init(const machine_t *model) +machine_europc_init(const machine_t *model, void *arg) { /* Clear the machine state. */ memset(&europc, 0x00, sizeof(europc_t)); europc.jim = 0x0250; - machine_common_init(model); + machine_common_init(model, arg); nmi_init(); mem_add_bios(); diff --git a/src/machine/m_olivetti_m24.c b/src/machine/m_olivetti_m24.c index 3ca2c16..af0a0e4 100644 --- a/src/machine/m_olivetti_m24.c +++ b/src/machine/m_olivetti_m24.c @@ -8,7 +8,7 @@ * * Emulation of the Olivetti M24. * - * Version: @(#)m_olivetti_m24.c 1.0.4 2018/03/19 + * Version: @(#)m_olivetti_m24.c 1.0.5 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -824,14 +824,14 @@ const device_t m24_device = { void -machine_olim24_init(const machine_t *model) +machine_olim24_init(const machine_t *model, void *arg) { olim24_t *m24; m24 = (olim24_t *)malloc(sizeof(olim24_t)); memset(m24, 0x00, sizeof(olim24_t)); - machine_common_init(model); + machine_common_init(model, arg); io_sethandler(0x0066, 2, m24_read,NULL,NULL, NULL,NULL,NULL, m24); diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index af17d3d..69b4286 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -8,7 +8,7 @@ * * Emulation of the IBM PCjr. * - * Version: @(#)m_pcjr.c 1.0.2 2018/03/15 + * Version: @(#)m_pcjr.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -59,6 +59,7 @@ #include "../sound/snd_sn76489.h" #include "../video/video.h" #include "../video/vid_cga_comp.h" +#include "../plat.h" #include "machine.h" @@ -750,7 +751,7 @@ pcjr_get_device(void) void -machine_pcjr_init(const machine_t *model) +machine_pcjr_init(const machine_t *model, UNUSED(void *arg)) { int display_type; pcjr_t *pcjr; diff --git a/src/machine/m_ps1.c b/src/machine/m_ps1.c index 3122370..8d43b18 100644 --- a/src/machine/m_ps1.c +++ b/src/machine/m_ps1.c @@ -28,7 +28,7 @@ * boot. Sometimes, they do, and then it shows an "Incorrect * DOS" error message?? --FvK * - * Version: @(#)m_ps1.c 1.0.5 2018/03/19 + * Version: @(#)m_ps1.c 1.0.6 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -86,6 +86,7 @@ #include "../video/video.h" #include "../video/vid_vga.h" #include "../video/vid_ti_cf62011.h" +#include "../plat.h" #include "machine.h" @@ -553,9 +554,9 @@ ps1_setup(int model) static void -ps1_common_init(const machine_t *model) +ps1_common_init(const machine_t *model, void *arg) { - machine_common_init(model); + machine_common_init(model, arg); mem_remap_top_384k(); @@ -588,27 +589,27 @@ ps1_common_init(const machine_t *model) void -machine_ps1_m2011_init(const machine_t *model) +machine_ps1_m2011_init(const machine_t *model, void *arg) { - ps1_common_init(model); + ps1_common_init(model, arg); ps1_setup(2011); } void -machine_ps1_m2121_init(const machine_t *model) +machine_ps1_m2121_init(const machine_t *model, void *arg) { - ps1_common_init(model); + ps1_common_init(model, arg); ps1_setup(2121); } void -machine_ps1_m2133_init(const machine_t *model) +machine_ps1_m2133_init(const machine_t *model, void *arg) { - ps1_common_init(model); + ps1_common_init(model, arg); ps1_setup(2133); diff --git a/src/machine/m_ps2_isa.c b/src/machine/m_ps2_isa.c index 414fcb2..8a36ed6 100644 --- a/src/machine/m_ps2_isa.c +++ b/src/machine/m_ps2_isa.c @@ -8,7 +8,7 @@ * * Implementation of ISA-based PS/2 machines. * - * Version: @(#)m_ps2_isa.c 1.0.3 2018/03/19 + * Version: @(#)m_ps2_isa.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -186,9 +186,10 @@ static void ps2board_init(void) void -machine_ps2_m30_286_init(const machine_t *model) +machine_ps2_m30_286_init(const machine_t *model, void *arg) { - machine_common_init(model); + machine_common_init(model, arg); + device_add(&fdc_at_ps1_device); pit_set_out_func(&pit, 1, pit_refresh_timer_at); diff --git a/src/machine/m_ps2_mca.c b/src/machine/m_ps2_mca.c index fc84b3f..85db18e 100644 --- a/src/machine/m_ps2_mca.c +++ b/src/machine/m_ps2_mca.c @@ -8,7 +8,7 @@ * * Implementation of MCA-based PS/2 machines. * - * Version: @(#)m_ps2_mca.c 1.0.5 2018/03/20 + * Version: @(#)m_ps2_mca.c 1.0.6 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -1270,9 +1270,9 @@ static void ps2_mca_board_model_80_type2_init(int is486) static void -machine_ps2_common_init(const machine_t *model) +machine_ps2_common_init(const machine_t *model, void *arg) { - machine_common_init(model); + machine_common_init(model, arg); dma16_init(); pic2_init(); @@ -1290,44 +1290,44 @@ machine_ps2_common_init(const machine_t *model) void -machine_ps2_model_50_init(const machine_t *model) +machine_ps2_model_50_init(const machine_t *model, void *arg) { - machine_ps2_common_init(model); + machine_ps2_common_init(model, arg); ps2_mca_board_model_50_init(); } void -machine_ps2_model_55sx_init(const machine_t *model) +machine_ps2_model_55sx_init(const machine_t *model, void *arg) { - machine_ps2_common_init(model); + machine_ps2_common_init(model, arg); ps2_mca_board_model_55sx_init(); } void -machine_ps2_model_70_type3_init(const machine_t *model) +machine_ps2_model_70_type3_init(const machine_t *model, void *arg) { - machine_ps2_common_init(model); + machine_ps2_common_init(model, arg); ps2_mca_board_model_70_type34_init(0); } void -machine_ps2_model_70_type4_init(const machine_t *model) +machine_ps2_model_70_type4_init(const machine_t *model, void *arg) { - machine_ps2_common_init(model); + machine_ps2_common_init(model, arg); ps2_mca_board_model_70_type34_init(1); } void -machine_ps2_model_80_init(const machine_t *model) +machine_ps2_model_80_init(const machine_t *model, void *arg) { - machine_ps2_common_init(model); + machine_ps2_common_init(model, arg); ps2_mca_board_model_80_type2_init(0); } diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index cfd2ff7..df301e4 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -8,7 +8,7 @@ * * Emulation of Tandy models 1000, 1000HX and 1000SL2. * - * Version: @(#)m_tandy.c 1.0.3 2018/03/19 + * Version: @(#)m_tandy.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -1685,7 +1685,6 @@ init_rom(tandy_t *dev) { dev->rom = (uint8_t *)malloc(0x80000); -#if 1 if (! rom_load_interleaved(L"roms/machines/tandy1000sl2/8079047.hu1", L"roms/machines/tandy1000sl2/8079048.hu2", 0x000000, 0x80000, 0, dev->rom)) { @@ -1694,16 +1693,6 @@ init_rom(tandy_t *dev) dev->rom = NULL; return; } -#else - f = rom_fopen(L"roms/machines/tandy1000sl2/8079047.hu1", L"rb"); - ff = rom_fopen(L"roms/machines/tandy1000sl2/8079048.hu2", L"rb"); - for (c = 0x0000; c < 0x80000; c += 2) { - dev->rom[c] = getc(f); - dev->rom[c + 1] = getc(ff); - } - fclose(ff); - fclose(f); -#endif mem_mapping_add(&dev->rom_mapping, 0xe0000, 0x10000, read_rom, read_romw, read_roml, NULL, NULL, NULL, @@ -1712,14 +1701,14 @@ init_rom(tandy_t *dev) void -machine_tandy1k_init(const machine_t *model) +machine_tandy1k_init(const machine_t *model, void *arg) { tandy_t *dev; dev = malloc(sizeof(tandy_t)); memset(dev, 0x00, sizeof(tandy_t)); - machine_common_init(model); + machine_common_init(model, arg); nmi_init(); diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 9b06769..aaed126 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -8,7 +8,7 @@ * * Implementation of standard IBM PC/XT class machine. * - * Version: @(#)m_xt.c 1.0.3 2018/03/19 + * Version: @(#)m_xt.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -53,15 +53,18 @@ void -machine_xt_init(const machine_t *model) +machine_xt_init(const machine_t *model, void *arg) { - machine_common_init(model); + machine_common_init(model, arg); pit_set_out_func(&pit, 1, pit_refresh_timer_xt); device_add(&keyboard_xt_device); + device_add(&fdc_xt_device); + nmi_init(); + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); } diff --git a/src/machine/m_xt_compaq.c b/src/machine/m_xt_compaq.c index 022154a..dcc4312 100644 --- a/src/machine/m_xt_compaq.c +++ b/src/machine/m_xt_compaq.c @@ -8,7 +8,7 @@ * * Emulation of various Compaq XT-class PC's. * - * Version: @(#)m_xt_compaq.c 1.0.4 2018/03/19 + * Version: @(#)m_xt_compaq.c 1.0.5 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -57,15 +57,18 @@ void -machine_xt_compaq_init(const machine_t *model) +machine_xt_compaq_init(const machine_t *model, void *arg) { - machine_common_init(model); + machine_common_init(model, arg); pit_set_out_func(&pit, 1, pit_refresh_timer_xt); device_add(&keyboard_xt_device); + device_add(&fdc_xt_device); + nmi_init(); + if (joystick_type != JOYSTICK_TYPE_NONE) device_add(&gameport_device); diff --git a/src/machine/m_xt_laserxt.c b/src/machine/m_xt_laserxt.c index 5b4e483..1366f84 100644 --- a/src/machine/m_xt_laserxt.c +++ b/src/machine/m_xt_laserxt.c @@ -8,7 +8,7 @@ * * Emulation of the Laser XT series of machines. * - * Version: @(#)m_xt_laserxt.c 1.0.2 2018/03/15 + * Version: @(#)m_xt_laserxt.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -48,130 +48,153 @@ #include "machine.h" -static int laserxt_emspage[4]; -static int laserxt_emscontrol[4]; -static mem_mapping_t laserxt_ems_mapping[4]; -static int laserxt_ems_baseaddr_index = 0; +static int ems_page[4]; +static int ems_control[4]; +static mem_mapping_t ems_mapping[4]; +static int ems_baseaddr_index = 0; -static uint32_t get_laserxt_ems_addr(uint32_t addr) +static uint32_t +get_ems_addr(uint32_t addr) { - if(laserxt_emspage[(addr >> 14) & 3] & 0x80) - { - addr = (romset == ROM_LTXT ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)) + ((laserxt_emspage[(addr >> 14) & 3] & 0x0F) << 14) + ((laserxt_emspage[(addr >> 14) & 3] & 0x40) << 12) + (addr & 0x3FFF); - } + if (ems_page[(addr >> 14) & 3] & 0x80) { + addr = (romset == ROM_LTXT ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)) + ((ems_page[(addr >> 14) & 3] & 0x0F) << 14) + ((ems_page[(addr >> 14) & 3] & 0x40) << 12) + (addr & 0x3FFF); + } - return addr; + return addr; } -static void laserxt_write(uint16_t port, uint8_t val, void *priv) +static void +do_write(uint16_t port, uint8_t val, void *priv) { - int i; - uint32_t paddr, vaddr; - switch (port) - { - case 0x0208: case 0x4208: case 0x8208: case 0xC208: - laserxt_emspage[port >> 14] = val; - paddr = 0xC0000 + (port & 0xC000) + (((laserxt_ems_baseaddr_index + (4 - (port >> 14))) & 0x0C) << 14); - if(val & 0x80) - { - mem_mapping_enable(&laserxt_ems_mapping[port >> 14]); - vaddr = get_laserxt_ems_addr(paddr); - mem_mapping_set_exec(&laserxt_ems_mapping[port >> 14], ram + vaddr); - } - else - { - mem_mapping_disable(&laserxt_ems_mapping[port >> 14]); - } - flushmmucache(); - break; - case 0x0209: case 0x4209: case 0x8209: case 0xC209: - laserxt_emscontrol[port >> 14] = val; - laserxt_ems_baseaddr_index = 0; - for(i=0; i<4; i++) - { - laserxt_ems_baseaddr_index |= (laserxt_emscontrol[i] & 0x80) >> (7 - i); - } - if(laserxt_ems_baseaddr_index < 3) - { - mem_mapping_disable(&romext_mapping); - } - else - { - mem_mapping_enable(&romext_mapping); - } + uint32_t paddr, vaddr; + int i; - mem_mapping_set_addr(&laserxt_ems_mapping[0], 0xC0000 + (((laserxt_ems_baseaddr_index + 4) & 0x0C) << 14), 0x4000); - mem_mapping_set_addr(&laserxt_ems_mapping[1], 0xC4000 + (((laserxt_ems_baseaddr_index + 3) & 0x0C) << 14), 0x4000); - mem_mapping_set_addr(&laserxt_ems_mapping[2], 0xC8000 + (((laserxt_ems_baseaddr_index + 2) & 0x0C) << 14), 0x4000); - mem_mapping_set_addr(&laserxt_ems_mapping[3], 0xCC000 + (((laserxt_ems_baseaddr_index + 1) & 0x0C) << 14), 0x4000); - flushmmucache(); - break; - } + switch (port) { + case 0x0208: + case 0x4208: + case 0x8208: + case 0xC208: + ems_page[port >> 14] = val; + paddr = 0xC0000 + (port & 0xC000) + (((ems_baseaddr_index + (4 - (port >> 14))) & 0x0C) << 14); + if (val & 0x80) { + mem_mapping_enable(&ems_mapping[port >> 14]); + vaddr = get_ems_addr(paddr); + mem_mapping_set_exec(&ems_mapping[port >> 14], ram + vaddr); + } else { + mem_mapping_disable(&ems_mapping[port >> 14]); + } + flushmmucache(); + break; + + case 0x0209: + case 0x4209: + case 0x8209: + case 0xC209: + ems_control[port >> 14] = val; + ems_baseaddr_index = 0; + for (i = 0; i < 4; i++) { + ems_baseaddr_index |= (ems_control[i] & 0x80) >> (7 - i); + } + if (ems_baseaddr_index < 3) + mem_mapping_disable(&romext_mapping); + else + mem_mapping_enable(&romext_mapping); + + mem_mapping_set_addr(&ems_mapping[0], 0xC0000 + (((ems_baseaddr_index + 4) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&ems_mapping[1], 0xC4000 + (((ems_baseaddr_index + 3) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&ems_mapping[2], 0xC8000 + (((ems_baseaddr_index + 2) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&ems_mapping[3], 0xCC000 + (((ems_baseaddr_index + 1) & 0x0C) << 14), 0x4000); + flushmmucache(); + break; + } } -static uint8_t laserxt_read(uint16_t port, void *priv) +static uint8_t +do_read(uint16_t port, void *priv) { - switch (port) - { - case 0x0208: case 0x4208: case 0x8208: case 0xC208: - return laserxt_emspage[port >> 14]; - case 0x0209: case 0x4209: case 0x8209: case 0xC209: - return laserxt_emscontrol[port >> 14]; - break; - } - return 0xff; + switch (port) { + case 0x0208: + case 0x4208: + case 0x8208: + case 0xC208: + return ems_page[port >> 14]; + + case 0x0209: + case 0x4209: + case 0x8209: + case 0xC209: + return ems_control[port >> 14]; + } + + return 0xff; } -static void mem_write_laserxtems(uint32_t addr, uint8_t val, void *priv) +static void +mem_write_ems(uint32_t addr, uint8_t val, void *priv) { - addr = get_laserxt_ems_addr(addr); - if (addr < (mem_size << 10)) - ram[addr] = val; + addr = get_ems_addr(addr); + + if (addr < (mem_size << 10)) + ram[addr] = val; } -static uint8_t mem_read_laserxtems(uint32_t addr, void *priv) +static uint8_t +mem_read_ems(uint32_t addr, void *priv) { - uint8_t val = 0xFF; - addr = get_laserxt_ems_addr(addr); - if (addr < (mem_size << 10)) - val = ram[addr]; - return val; + uint8_t val = 0xFF; + + addr = get_ems_addr(addr); + + if (addr < (mem_size << 10)) + val = ram[addr]; + + return val; } -static void laserxt_init(void) +static void +laserxt_init(void) { - int i; + int i; - if(mem_size > 640) - { - io_sethandler(0x0208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); - io_sethandler(0x4208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); - io_sethandler(0x8208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); - io_sethandler(0xc208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); - mem_mapping_set_addr(&ram_low_mapping, 0, romset == ROM_LTXT ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)); - } + if(mem_size > 640) { + io_sethandler(0x0208, 2, + do_read,NULL,NULL, do_write,NULL,NULL, NULL); + io_sethandler(0x4208, 2, + do_read,NULL,NULL, do_write,NULL,NULL, NULL); + io_sethandler(0x8208, 2, + do_read,NULL,NULL, do_write,NULL,NULL, NULL); + io_sethandler(0xc208, 2, + do_read,NULL,NULL, do_write,NULL,NULL, NULL); - for (i = 0; i < 4; i++) - { - laserxt_emspage[i] = 0x7F; - laserxt_emscontrol[i] = (i == 3) ? 0x00 : 0x80; - mem_mapping_add(&laserxt_ems_mapping[i], 0xE0000 + (i << 14), 0x4000, mem_read_laserxtems, NULL, NULL, mem_write_laserxtems, NULL, NULL, ram + 0xA0000 + (i << 14), 0, NULL); - mem_mapping_disable(&laserxt_ems_mapping[i]); - } - mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_mapping_set_addr(&ram_low_mapping, 0, romset == ROM_LTXT ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)); + } + + for (i = 0; i < 4; i++) { + ems_page[i] = 0x7F; + ems_control[i] = (i == 3) ? 0x00 : 0x80; + + mem_mapping_add(&ems_mapping[i], 0xE0000 + (i << 14), 0x4000, + mem_read_ems,NULL,NULL, + mem_write_ems,NULL,NULL, + ram + 0xA0000 + (i << 14), 0, NULL); + mem_mapping_disable(&ems_mapping[i]); + } + + mem_set_mem_state(0x0c0000, 0x40000, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); } void -machine_xt_laserxt_init(const machine_t *model) +machine_xt_laserxt_init(const machine_t *model, void *arg) { - machine_xt_init(model); + machine_xt_init(model, arg); - laserxt_init(); + laserxt_init(); } diff --git a/src/machine/m_xt_t1000.c b/src/machine/m_xt_t1000.c index f93cf75..07e798a 100644 --- a/src/machine/m_xt_t1000.c +++ b/src/machine/m_xt_t1000.c @@ -1,1033 +1,1033 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Implementation of the Toshiba T1000 and T1200 portables. - * - * The T1000 is the T3100e's little brother -- a real laptop - * with a rechargeable battery. - * - * Features: 80C88 at 4.77MHz - * - 512k system RAM - * - 640x200 monochrome LCD - * - 82-key keyboard - * - Real-time clock. Not the normal 146818, but a TC8521, - * which is a 4-bit chip. - * - A ROM drive (128k, 256k or 512k) which acts as a mini - * hard drive and contains a copy of DOS 2.11. - * - 160 bytes of non-volatile RAM for the CONFIG.SYS used - * when booting from the ROM drive. Possibly physically - * located in the keyboard controller RAM. - * - * An optional memory expansion board can be fitted. This adds - * 768k of RAM, which can be used for up to three purposes: - * > Conventional memory -- 128k between 512k and 640k - * > HardRAM -- a battery-backed RAM drive. - * > EMS - * - * This means that there are up to three different - * implementations of non-volatile RAM in the same computer - * (52 nibbles in the TC8521, 160 bytes of CONFIG.SYS, and - * up to 768k of HardRAM). - * - * The T1200 is a slightly upgraded version with a turbo mode - * (double CPU clock, 9.54MHz) and an optional hard drive. - * The interface for this is proprietary both at the physical - * and programming level. - * - * 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb] - * or 0Dh [10Mb]. - * - * The hard drive is a 20MB (615/2/26) RLL 3.5" drive. - * - * The TC8521 is a 4-bit RTC, so each memory location can only - * hold a single BCD digit. Hence everything has 'ones' and - * 'tens' digits. - * - * Version: @(#)m_xt_t1000.c 1.0.5 2018/03/18 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * John Elliott, - * - * Copyright 2018 Fred N. van Kempen. - * Copyright 2018 Miran Grca. - * Copyright 2017,2018 John Elliott. - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. - */ -#include -#include -#include -#include -#include -#include -#include "../emu.h" -#include "../cpu/cpu.h" -#include "../io.h" -#include "../pit.h" -#include "../nmi.h" -#include "../mem.h" -#include "../rom.h" -#include "../nvr.h" -#include "../device.h" -#include "../keyboard.h" -#include "../lpt.h" -#include "../floppy/fdd.h" -#include "../floppy/fdc.h" -#include "../game/gameport.h" -#include "../video/video.h" -#include "../plat.h" -#include "machine.h" -#include "m_xt_t1000.h" - - -#define T1000_ROMSIZE (512*1024UL) /* Maximum ROM drive size is 512k */ - - -enum TC8521_ADDR { - /* Page 0 registers */ - TC8521_SECOND1 = 0, - TC8521_SECOND10, - TC8521_MINUTE1, - TC8521_MINUTE10, - TC8521_HOUR1, - TC8521_HOUR10, - TC8521_WEEKDAY, - TC8521_DAY1, - TC8521_DAY10, - TC8521_MONTH1, - TC8521_MONTH10, - TC8521_YEAR1, - TC8521_YEAR10, - TC8521_PAGE, /* PAGE register */ - TC8521_TEST, /* TEST register */ - TC8521_RESET, /* RESET register */ - - /* Page 1 registers */ - TC8521_24HR = 0x1A, - TC8521_LEAPYEAR = 0x1B -}; - - -typedef struct { - /* ROM drive */ - uint8_t *romdrive; - uint8_t rom_ctl; - uint32_t rom_offset; - mem_mapping_t rom_mapping; - - /* CONFIG.SYS drive. */ - wchar_t cfgsys_fn[128]; - uint16_t cfgsys_len; - uint8_t *cfgsys; - - /* System control registers */ - uint8_t sys_ctl[16]; - uint8_t syskeys; - uint8_t turbo; - - /* NVRAM control */ - uint8_t nvr_c0; - uint8_t nvr_tick; - int nvr_addr; - uint8_t nvr_active; - mem_mapping_t nvr_mapping; /* T1200 NVRAM mapping */ - - /* EMS data */ - uint8_t ems_reg[4]; - mem_mapping_t mapping[4]; - uint32_t page_exec[4]; - uint8_t ems_port_index; - uint16_t ems_port; - uint8_t is_640k; - uint32_t ems_base; - int32_t ems_pages; - - fdc_t *fdc; - - nvr_t nvr; -} t1000_t; - - -static t1000_t t1000; - - -/* Set the chip time. */ -static void -tc8521_time_set(uint8_t *regs, struct tm *tm) -{ - regs[TC8521_SECOND1] = (tm->tm_sec % 10); - regs[TC8521_SECOND10] = (tm->tm_sec / 10); - regs[TC8521_MINUTE1] = (tm->tm_min % 10); - regs[TC8521_MINUTE10] = (tm->tm_min / 10); - if (regs[TC8521_24HR] & 0x01) { - regs[TC8521_HOUR1] = (tm->tm_hour % 10); - regs[TC8521_HOUR10] = (tm->tm_hour / 10); - } else { - regs[TC8521_HOUR1] = ((tm->tm_hour % 12) % 10); +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Toshiba T1000 and T1200 portables. + * + * The T1000 is the T3100e's little brother -- a real laptop + * with a rechargeable battery. + * + * Features: 80C88 at 4.77MHz + * - 512k system RAM + * - 640x200 monochrome LCD + * - 82-key keyboard + * - Real-time clock. Not the normal 146818, but a TC8521, + * which is a 4-bit chip. + * - A ROM drive (128k, 256k or 512k) which acts as a mini + * hard drive and contains a copy of DOS 2.11. + * - 160 bytes of non-volatile RAM for the CONFIG.SYS used + * when booting from the ROM drive. Possibly physically + * located in the keyboard controller RAM. + * + * An optional memory expansion board can be fitted. This adds + * 768k of RAM, which can be used for up to three purposes: + * > Conventional memory -- 128k between 512k and 640k + * > HardRAM -- a battery-backed RAM drive. + * > EMS + * + * This means that there are up to three different + * implementations of non-volatile RAM in the same computer + * (52 nibbles in the TC8521, 160 bytes of CONFIG.SYS, and + * up to 768k of HardRAM). + * + * The T1200 is a slightly upgraded version with a turbo mode + * (double CPU clock, 9.54MHz) and an optional hard drive. + * The interface for this is proprietary both at the physical + * and programming level. + * + * 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb] + * or 0Dh [10Mb]. + * + * The hard drive is a 20MB (615/2/26) RLL 3.5" drive. + * + * The TC8521 is a 4-bit RTC, so each memory location can only + * hold a single BCD digit. Hence everything has 'ones' and + * 'tens' digits. + * + * Version: @(#)m_xt_t1000.c 1.0.6 2018/03/21 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * John Elliott, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Miran Grca. + * Copyright 2017,2018 John Elliott. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include "../emu.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../nmi.h" +#include "../mem.h" +#include "../rom.h" +#include "../nvr.h" +#include "../device.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../video/video.h" +#include "../plat.h" +#include "machine.h" +#include "m_xt_t1000.h" + + +#define T1000_ROMSIZE (512*1024UL) /* Maximum ROM drive size is 512k */ + + +enum TC8521_ADDR { + /* Page 0 registers */ + TC8521_SECOND1 = 0, + TC8521_SECOND10, + TC8521_MINUTE1, + TC8521_MINUTE10, + TC8521_HOUR1, + TC8521_HOUR10, + TC8521_WEEKDAY, + TC8521_DAY1, + TC8521_DAY10, + TC8521_MONTH1, + TC8521_MONTH10, + TC8521_YEAR1, + TC8521_YEAR10, + TC8521_PAGE, /* PAGE register */ + TC8521_TEST, /* TEST register */ + TC8521_RESET, /* RESET register */ + + /* Page 1 registers */ + TC8521_24HR = 0x1A, + TC8521_LEAPYEAR = 0x1B +}; + + +typedef struct { + /* ROM drive */ + uint8_t *romdrive; + uint8_t rom_ctl; + uint32_t rom_offset; + mem_mapping_t rom_mapping; + + /* CONFIG.SYS drive. */ + wchar_t cfgsys_fn[128]; + uint16_t cfgsys_len; + uint8_t *cfgsys; + + /* System control registers */ + uint8_t sys_ctl[16]; + uint8_t syskeys; + uint8_t turbo; + + /* NVRAM control */ + uint8_t nvr_c0; + uint8_t nvr_tick; + int nvr_addr; + uint8_t nvr_active; + mem_mapping_t nvr_mapping; /* T1200 NVRAM mapping */ + + /* EMS data */ + uint8_t ems_reg[4]; + mem_mapping_t mapping[4]; + uint32_t page_exec[4]; + uint8_t ems_port_index; + uint16_t ems_port; + uint8_t is_640k; + uint32_t ems_base; + int32_t ems_pages; + + fdc_t *fdc; + + nvr_t nvr; +} t1000_t; + + +static t1000_t t1000; + + +/* Set the chip time. */ +static void +tc8521_time_set(uint8_t *regs, struct tm *tm) +{ + regs[TC8521_SECOND1] = (tm->tm_sec % 10); + regs[TC8521_SECOND10] = (tm->tm_sec / 10); + regs[TC8521_MINUTE1] = (tm->tm_min % 10); + regs[TC8521_MINUTE10] = (tm->tm_min / 10); + if (regs[TC8521_24HR] & 0x01) { + regs[TC8521_HOUR1] = (tm->tm_hour % 10); + regs[TC8521_HOUR10] = (tm->tm_hour / 10); + } else { + regs[TC8521_HOUR1] = ((tm->tm_hour % 12) % 10); regs[TC8521_HOUR10] = (((tm->tm_hour % 12) / 10) | - ((tm->tm_hour >= 12) ? 2 : 0)); - } - regs[TC8521_WEEKDAY] = tm->tm_wday; - regs[TC8521_DAY1] = (tm->tm_mday % 10); - regs[TC8521_DAY10] = (tm->tm_mday / 10); - regs[TC8521_MONTH1] = ((tm->tm_mon + 1) % 10); - regs[TC8521_MONTH10] = ((tm->tm_mon + 1) / 10); - regs[TC8521_YEAR1] = ((tm->tm_year - 80) % 10); - regs[TC8521_YEAR10] = (((tm->tm_year - 80) % 100) / 10); -} - - -/* Get the chip time. */ -#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)]) -static void -tc8521_time_get(uint8_t *regs, struct tm *tm) -{ - tm->tm_sec = nibbles(TC8521_SECOND); - tm->tm_min = nibbles(TC8521_MINUTE); - if (regs[TC8521_24HR] & 0x01) - tm->tm_hour = nibbles(TC8521_HOUR); - else - tm->tm_hour = ((nibbles(TC8521_HOUR) % 12) + - (regs[TC8521_HOUR10] & 0x02) ? 12 : 0); + ((tm->tm_hour >= 12) ? 2 : 0)); + } + regs[TC8521_WEEKDAY] = tm->tm_wday; + regs[TC8521_DAY1] = (tm->tm_mday % 10); + regs[TC8521_DAY10] = (tm->tm_mday / 10); + regs[TC8521_MONTH1] = ((tm->tm_mon + 1) % 10); + regs[TC8521_MONTH10] = ((tm->tm_mon + 1) / 10); + regs[TC8521_YEAR1] = ((tm->tm_year - 80) % 10); + regs[TC8521_YEAR10] = (((tm->tm_year - 80) % 100) / 10); +} + + +/* Get the chip time. */ +#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)]) +static void +tc8521_time_get(uint8_t *regs, struct tm *tm) +{ + tm->tm_sec = nibbles(TC8521_SECOND); + tm->tm_min = nibbles(TC8521_MINUTE); + if (regs[TC8521_24HR] & 0x01) + tm->tm_hour = nibbles(TC8521_HOUR); + else + tm->tm_hour = ((nibbles(TC8521_HOUR) % 12) + + (regs[TC8521_HOUR10] & 0x02) ? 12 : 0); //FIXME: wday - tm->tm_mday = nibbles(TC8521_DAY); - tm->tm_mon = (nibbles(TC8521_MONTH) - 1); - tm->tm_year = (nibbles(TC8521_YEAR) + 1980); -} - - -/* This is called every second through the NVR/RTC hook. */ -static void -tc8521_tick(nvr_t *nvr) -{ - pclog("TC8521: ping\n"); -} - - -static void -tc8521_start(nvr_t *nvr) -{ - struct tm tm; - - /* Initialize the internal and chip times. */ - if (enable_sync) { - /* Use the internal clock's time. */ - nvr_time_get(&tm); - tc8521_time_set(nvr->regs, &tm); - } else { - /* Set the internal clock from the chip time. */ - tc8521_time_get(nvr->regs, &tm); - nvr_time_set(&tm); - } - + tm->tm_mday = nibbles(TC8521_DAY); + tm->tm_mon = (nibbles(TC8521_MONTH) - 1); + tm->tm_year = (nibbles(TC8521_YEAR) + 1980); +} + + +/* This is called every second through the NVR/RTC hook. */ +static void +tc8521_tick(nvr_t *nvr) +{ + pclog("TC8521: ping\n"); +} + + +static void +tc8521_start(nvr_t *nvr) +{ + struct tm tm; + + /* Initialize the internal and chip times. */ + if (enable_sync) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + tc8521_time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + tc8521_time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } + #if 0 - /* Start the RTC - BIOS will do this. */ - nvr->regs[TC8521_PAGE] |= 0x80; + /* Start the RTC - BIOS will do this. */ + nvr->regs[TC8521_PAGE] |= 0x80; #endif -} - - -/* Write to one of the chip registers. */ -static void -tc8521_write(uint16_t addr, uint8_t val, void *priv) -{ - nvr_t *nvr = (nvr_t *)priv; - uint8_t page; - - /* Get to the correct register page. */ - addr &= 0x0f; - page = nvr->regs[0x0d] & 0x03; - if (addr < 0x0d) - addr += (16 * page); - - if (addr >= 0x10 && nvr->regs[addr] != val) - nvr_dosave = 1; - - /* Store the new value. */ - nvr->regs[addr] = val; -} - - -/* Read from one of the chip registers. */ -static uint8_t -tc8521_read(uint16_t addr, void *priv) -{ - nvr_t *nvr = (nvr_t *)priv; - uint8_t page; - - /* Get to the correct register page. */ - addr &= 0x0f; - page = nvr->regs[0x0d] & 0x03; - if (addr < 0x0d) - addr += (16 * page); - - /* Grab and return the desired value. */ - return(nvr->regs[addr]); -} - - -/* Reset the 8521 to a default state. */ -static void -tc8521_reset(nvr_t *nvr) -{ - /* Clear the NVRAM. */ - memset(nvr->regs, 0xff, nvr->size); +} + + +/* Write to one of the chip registers. */ +static void +tc8521_write(uint16_t addr, uint8_t val, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t page; + + /* Get to the correct register page. */ + addr &= 0x0f; + page = nvr->regs[0x0d] & 0x03; + if (addr < 0x0d) + addr += (16 * page); + + if (addr >= 0x10 && nvr->regs[addr] != val) + nvr_dosave = 1; + + /* Store the new value. */ + nvr->regs[addr] = val; +} + + +/* Read from one of the chip registers. */ +static uint8_t +tc8521_read(uint16_t addr, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t page; + + /* Get to the correct register page. */ + addr &= 0x0f; + page = nvr->regs[0x0d] & 0x03; + if (addr < 0x0d) + addr += (16 * page); + + /* Grab and return the desired value. */ + return(nvr->regs[addr]); +} + + +/* Reset the 8521 to a default state. */ +static void +tc8521_reset(nvr_t *nvr) +{ + /* Clear the NVRAM. */ + memset(nvr->regs, 0xff, nvr->size); /* Reset the RTC registers. */ - memset(nvr->regs, 0x00, 16); - nvr->regs[TC8521_WEEKDAY] = 0x01; - nvr->regs[TC8521_DAY1] = 0x01; - nvr->regs[TC8521_MONTH1] = 0x01; -} - - -static void -tc8521_init(nvr_t *nvr, int size) -{ - /* This is machine specific. */ - nvr->size = size; - nvr->irq = -1; - - /* Set up any local handlers here. */ - nvr->reset = tc8521_reset; - nvr->start = tc8521_start; - nvr->tick = tc8521_tick; - - /* Initialize the actual NVR. */ - nvr_init(nvr); - - io_sethandler(0x02c0, 16, - tc8521_read,NULL,NULL, tc8521_write,NULL,NULL, nvr); -} - - -/* Given an EMS page ID, return its physical address in RAM. */ -static uint32_t -ems_execaddr(t1000_t *sys, int pg, uint16_t val) -{ - if (!(val & 0x80)) return(0); /* Bit 7 reset => not mapped */ - if (!sys->ems_pages) return(0); /* No EMS available: all used by - * HardRAM or conventional RAM */ - val &= 0x7f; - -#if 0 - pclog("Select EMS page: %d of %d\n", val, sys->ems_pages); -#endif - if (val < sys->ems_pages) { - /* EMS is any memory above 512k, - with ems_base giving the start address */ - return((512 * 1024) + (sys->ems_base * 0x10000) + (0x4000 * val)); - } - - return(0); -} - - -static uint8_t -ems_in(uint16_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - -#if 0 - pclog("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]); -#endif - return(sys->ems_reg[(addr >> 14) & 3]); -} - - -static void -ems_out(uint16_t addr, uint8_t val, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - int pg = (addr >> 14) & 3; - -#if 0 - pclog("ems_out(%04x, %02x) pg=%d\n", addr, val, pg); -#endif - sys->ems_reg[pg] = val; - sys->page_exec[pg] = ems_execaddr(sys, pg, val); - if (sys->page_exec[pg]) { - /* Page present */ - mem_mapping_enable(&sys->mapping[pg]); - mem_mapping_set_exec(&sys->mapping[pg], ram + sys->page_exec[pg]); - } else { - mem_mapping_disable(&sys->mapping[pg]); - } -} - - -/* Hardram size is in 64k units */ -static void -ems_set_hardram(t1000_t *sys, uint8_t val) -{ - int n; - - val &= 0x1f; /* Mask off pageframe address */ - if (val && mem_size > 512) - sys->ems_base = val; - else - sys->ems_base = 0; - -#if 0 - pclog("EMS base set to %02x\n", val); -#endif - sys->ems_pages = 48 - 4 * sys->ems_base; - if (sys->ems_pages < 0) sys->ems_pages = 0; - - /* Recalculate EMS mappings */ - for (n = 0; n < 4; n++) - ems_out(n << 14, sys->ems_reg[n], sys); -} - - -static void -ems_set_640k(t1000_t *sys, uint8_t val) -{ - if (val && mem_size >= 640) { - mem_mapping_set_addr(&ram_low_mapping, 0, 640 * 1024); - sys->is_640k = 1; - } else { - mem_mapping_set_addr(&ram_low_mapping, 0, 512 * 1024); - sys->is_640k = 0; - } -} - - -static void -ems_set_port(t1000_t *sys, uint8_t val) -{ - int n; - -#if 0 - pclog("ems_set_port(%d)", val & 0x0f); -#endif - if (sys->ems_port) { - for (n = 0; n <= 0xc000; n += 0x4000) { - io_removehandler(sys->ems_port+n, 1, - ems_in,NULL,NULL, ems_out,NULL,NULL, sys); - } - sys->ems_port = 0; - } - - val &= 0x0f; - sys->ems_port_index = val; - if (val == 7) { - /* No EMS */ - sys->ems_port = 0; - } else { - sys->ems_port = 0x208 | (val << 4); - for (n = 0; n <= 0xc000; n += 0x4000) { - io_sethandler(sys->ems_port+n, 1, - ems_in,NULL,NULL, ems_out,NULL,NULL, sys); - } - sys->ems_port = 0; - } - -#if 0 - pclog(" -> %04x\n", sys->ems_port); -#endif -} - - -static int -addr_to_page(uint32_t addr) -{ - return((addr - 0xd0000) / 0x4000); -} - - -/* Read RAM in the EMS page frame. */ -static uint8_t -ems_read_ram(uint32_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return(0xff); - addr = sys->page_exec[pg] + (addr & 0x3fff); - - return(ram[addr]); -} - - -static uint16_t -ems_read_ramw(uint32_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return(0xff); - -#if 0 - pclog("ems_read_ramw addr=%05x ", addr); -#endif - addr = sys->page_exec[pg] + (addr & 0x3FFF); - -#if 0 - pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); -#endif - - return(*(uint16_t *)&ram[addr]); -} - - -static uint32_t -ems_read_raml(uint32_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return(0xff); - addr = sys->page_exec[pg] + (addr & 0x3fff); - - return(*(uint32_t *)&ram[addr]); -} - - -/* Write RAM in the EMS page frame. */ -static void -ems_write_ram(uint32_t addr, uint8_t val, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return; - - addr = sys->page_exec[pg] + (addr & 0x3fff); - if (ram[addr] != val) nvr_dosave = 1; - - ram[addr] = val; -} - - -static void -ems_write_ramw(uint32_t addr, uint16_t val, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return; - -#if 0 - pclog("ems_write_ramw addr=%05x ", addr); -#endif - addr = sys->page_exec[pg] + (addr & 0x3fff); - -#if 0 - pclog("-> %06x val=%04x\n", addr, val); -#endif - - if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; - - *(uint16_t *)&ram[addr] = val; -} - - -static void -ems_write_raml(uint32_t addr, uint32_t val, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - int pg = addr_to_page(addr); - - if (pg < 0) return; - - addr = sys->page_exec[pg] + (addr & 0x3fff); - if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; - - *(uint32_t *)&ram[addr] = val; -} - - -static uint8_t -read_ctl(uint16_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - uint8_t ret = 0xff; - - switch (addr & 0x0f) { - case 1: - ret = sys->syskeys; - break; - - case 0x0f: /* Detect EMS board */ - switch (sys->sys_ctl[0x0e]) { - case 0x50: - if (mem_size > 512) break; - ret = (0x90 | sys->ems_port_index); - break; - - case 0x51: - /* 0x60 is the page frame address: - (0xd000 - 0xc400) / 0x20 */ - ret = (sys->ems_base | 0x60); - break; - - case 0x52: - ret = (sys->is_640k ? 0x80 : 0); - break; - } - break; - - default: - ret = (sys->sys_ctl[addr & 0x0f]); - } - - return(ret); -} - - -/* Load contents of "CONFIG.SYS" device from file. */ -static void -cfgsys_load(t1000_t *dev) -{ - char temp[128]; - FILE *f; - - /* Set up the file's name. */ - sprintf(temp, "%s_cfgsys.nvr", machine_get_internal_name()); - mbstowcs(dev->cfgsys_fn, temp, sizeof_w(dev->cfgsys_fn)); - - /* Now attempt to load the file. */ - memset(dev->cfgsys, 0x1a, dev->cfgsys_len); - f = plat_fopen(nvr_path(dev->cfgsys_fn), L"rb"); - if (f != NULL) { - pclog("NVR: loaded CONFIG.SYS from '%ls'\n", dev->cfgsys_fn); - (void)fread(dev->cfgsys, dev->cfgsys_len, 1, f); - fclose(f); - } - else pclog("NVR: initialized CONFIG.SYS for '%ls'\n", dev->cfgsys_fn); -} - - -/* Write the contents of "CONFIG.SYS" to file. */ -static void -cfgsys_save(t1000_t *dev) -{ - FILE *f; - - /* Avoids writing empty files. */ - if (dev->cfgsys_len < 160) return; - - f = plat_fopen(nvr_path(dev->cfgsys_fn), L"wb"); - if (f != NULL) { - pclog("NVR: saved CONFIG.SYS to '%ls'\n", dev->cfgsys_fn); - (void)fwrite(dev->cfgsys, dev->cfgsys_len, 1, f); - fclose(f); - } -} - - -#if NOTUSED -/* All RAM beyond 512K is non-volatile */ -static void -emsboard_load(t1000_t *dev) -{ - FILE *f; - - if (mem_size > 512) { - f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb"); - if (f != NULL) { - fread(&ram[512 * 1024], 1024, (mem_size - 512), f); - fclose(f); - } - } -} - - -static void -emsboard_save(t1000_t *dev) -{ - FILE *f; - - if (mem_size > 512) { - f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb"); - if (f != NULL) { - fwrite(&ram[512 * 1024], 1024, (mem_size - 512), f); - fclose(f); - } - } -} -#endif - - -static void -t1200_turbo_set(uint8_t value) -{ - if (value == t1000.turbo) return; - - t1000.turbo = value; - if (! value) - cpu_dynamic_switch(0); - else - cpu_dynamic_switch(cpu); -} - - -static void -write_ctl(uint16_t addr, uint8_t val, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - sys->sys_ctl[addr & 0x0f] = val; - switch (addr & 0x0f) { - case 4: /* Video control */ - if (sys->sys_ctl[3] == 0x5A) { - t1000_video_options_set((val & 0x20) ? 1 : 0); - t1000_display_set((val & 0x40) ? 0 : 1); - if (romset == ROM_T1200) - t1200_turbo_set((val & 0x80) ? 1 : 0); - } - break; - - case 0x0f: /* EMS control */ - switch (sys->sys_ctl[0x0e]) { - case 0x50: - ems_set_port(sys, val); - break; - - case 0x51: - ems_set_hardram(sys, val); - break; - - case 0x52: - ems_set_640k(sys, val); - break; - } - break; - } -} - - -/* Ports 0xC0 to 0xC3 appear to have two purposes: - * - * > Access to the 160 bytes of non-volatile RAM containing CONFIG.SYS - * > Reading the floppy changeline. I don't know why the Toshiba doesn't - * use the normal port 0x3F7 for this, but it doesn't. - * - */ -static uint8_t -t1000_read_nvram(uint16_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - uint8_t tmp = 0xff; - - switch (addr) { - case 0xc2: /* Read next byte from NVRAM */ - if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) - tmp = sys->cfgsys[sys->nvr_addr]; - sys->nvr_addr++; - break; - - case 0xc3: /* Read floppy changeline and NVRAM ready state */ - tmp = fdc_read(0x03f7, t1000.fdc); - - tmp = (tmp & 0x80) >> 3; /* Bit 4 is changeline */ - tmp |= (sys->nvr_active & 0xc0);/* Bits 6,7 are r/w mode */ - tmp |= 0x2e; /* Bits 5,3,2,1 always 1 */ - tmp |= (sys->nvr_active & 0x40) >> 6; /* Ready state */ - break; - } - - return(tmp); -} - - -static void -t1000_write_nvram(uint16_t addr, uint8_t val, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - /* - * On the real T1000, port 0xC1 is only usable as the high byte - * of a 16-bit write to port 0xC0, with 0x5A in the low byte. - */ - switch (addr) { - case 0xc0: - sys->nvr_c0 = val; - break; - - case 0xc1: /* Write next byte to NVRAM */ - if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) { - if (sys->cfgsys[sys->nvr_addr] != val) - nvr_dosave = 1; - sys->cfgsys[sys->nvr_addr] = val; - } - sys->nvr_addr++; - break; - - case 0xc2: - break; - - case 0xc3: - /* - * At start of NVRAM read / write, 0x80 is written to - * port 0xC3. This seems to reset the NVRAM address - * counter. A single byte is then written (0xff for - * write, 0x00 for read) which appears to be ignored. - * Simulate that by starting the address counter off - * at -1. - */ - sys->nvr_active = val; - if (val == 0x80) sys->nvr_addr = -1; - break; - } -} - - -/* Port 0xC8 controls the ROM drive */ -static uint8_t -t1000_read_rom_ctl(uint16_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - return(sys->rom_ctl); -} - - -static void -t1000_write_rom_ctl(uint16_t addr, uint8_t val, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - sys->rom_ctl = val; - if (sys->romdrive && (val & 0x80)) { - /* Enable */ - sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMSIZE; - mem_mapping_set_addr(&sys->rom_mapping, 0xa0000, 0x10000); - mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + sys->rom_offset); - mem_mapping_enable(&sys->rom_mapping); - } else { - mem_mapping_disable(&sys->rom_mapping); - } -} - - -/* Read the ROM drive */ -static uint8_t -t1000_read_rom(uint32_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - if (! sys->romdrive) return(0xff); - - return(sys->romdrive[sys->rom_offset + (addr & 0xffff)]); -} - - -static uint16_t -t1000_read_romw(uint32_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - if (! sys->romdrive) return(0xffff); - - return(*(uint16_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); -} - - -static uint32_t -t1000_read_roml(uint32_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - if (! sys->romdrive) return(0xffffffff); - - return(*(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); -} - - -const device_t * -t1000_get_device(void) -{ - return(&t1000_video_device); -} - - -void -machine_xt_t1000_init(const machine_t *model) -{ - FILE *f; - int pg; - - memset(&t1000, 0x00, sizeof(t1000)); - t1000.turbo = 0xff; - t1000.ems_port_index = 7; /* EMS disabled */ - - /* Load the T1000 CGA Font ROM. */ - loadfont(L"roms/machines/toshiba/t1000/t1000font.rom", 2); - - /* - * The ROM drive is optional. - * - * If the file is missing, continue to boot; the BIOS will - * complain 'No ROM drive' but boot normally from floppy. - */ - f = rom_fopen(L"roms/machines/toshiba/t1000/t1000dos.rom"); - if (f != NULL) { - t1000.romdrive = malloc(T1000_ROMSIZE); - if (t1000.romdrive) { - memset(t1000.romdrive, 0xff, T1000_ROMSIZE); - fread(t1000.romdrive, T1000_ROMSIZE, 1, f); - } - fclose(f); - } - mem_mapping_add(&t1000.rom_mapping, 0xa0000, 0x10000, - t1000_read_rom,t1000_read_romw,t1000_read_roml, - NULL,NULL,NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); - mem_mapping_disable(&t1000.rom_mapping); - - /* Map the EMS page frame */ - for (pg = 0; pg < 4; pg++) { - mem_mapping_add(&t1000.mapping[pg], 0xd0000 + (0x4000 * pg), 16384, - ems_read_ram,ems_read_ramw,ems_read_raml, - ems_write_ram,ems_write_ramw,ems_write_raml, - NULL, MEM_MAPPING_EXTERNAL, &t1000); - - /* Start them all off disabled */ - mem_mapping_disable(&t1000.mapping[pg]); - } - - /* Non-volatile RAM for CONFIG.SYS */ - t1000.cfgsys_len = 160; - t1000.cfgsys = (uint8_t *)malloc(t1000.cfgsys_len); - io_sethandler(0xc0, 4, - t1000_read_nvram,NULL,NULL, - t1000_write_nvram,NULL,NULL, &t1000); - cfgsys_load(&t1000); - - /* ROM drive */ - io_sethandler(0xc8, 1, - t1000_read_rom_ctl,NULL,NULL, - t1000_write_rom_ctl,NULL,NULL, &t1000); - - /* System control functions, and add-on memory board */ - io_sethandler(0xe0, 16, - read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); - - machine_common_init(model); - - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); - device_add(&keyboard_xt_device); - t1000.fdc = device_add(&fdc_xt_device); - nmi_init(); - - tc8521_init(&t1000.nvr, model->nvrsz); - - device_add(&t1000_video_device); -} - - -static -uint8_t t1200_nvram_read(uint32_t addr, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - return(sys->cfgsys[addr & 0x7ff]); -} - - -static void -t1200_nvram_write(uint32_t addr, uint8_t value, void *priv) -{ - t1000_t *sys = (t1000_t *)priv; - - if (sys->cfgsys[addr & 0x7ff] != value) - nvr_dosave = 1; - - sys->cfgsys[addr & 0x7ff] = value; -} - - -const device_t * -t1200_get_device(void) -{ - return(&t1200_video_device); -} - - -void -machine_xt_t1200_init(const machine_t *model) -{ - int pg; - - memset(&t1000, 0x00, sizeof(t1000)); - t1000.ems_port_index = 7; /* EMS disabled */ - - /* Load the T1200 CGA Font ROM. */ - loadfont(L"roms/machines/toshiba/t1200/t1000font.bin", 2); - - /* Map the EMS page frame */ - for (pg = 0; pg < 4; pg++) { - mem_mapping_add(&t1000.mapping[pg], - 0xd0000 + (0x4000 * pg), 16384, - ems_read_ram,ems_read_ramw,ems_read_raml, - ems_write_ram,ems_write_ramw,ems_write_raml, - NULL, MEM_MAPPING_EXTERNAL, &t1000); - - /* Start them all off disabled */ - mem_mapping_disable(&t1000.mapping[pg]); - } - - /* System control functions, and add-on memory board */ - io_sethandler(0xe0, 16, - read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); - - machine_common_init(model); - - /* Non-volatile RAM for CONFIG.SYS */ - t1000.cfgsys_len = 2048; - t1000.cfgsys = (uint8_t *)malloc(t1000.cfgsys_len); - mem_mapping_add(&t1000.nvr_mapping, - 0x000f0000, t1000.cfgsys_len, - t1200_nvram_read,NULL,NULL, - t1200_nvram_write,NULL,NULL, - NULL, 0, &t1000); - cfgsys_load(&t1000); - - pit_set_out_func(&pit, 1, pit_refresh_timer_xt); - device_add(&keyboard_xt_device); - t1000.fdc = device_add(&fdc_xt_device); - nmi_init(); - - tc8521_init(&t1000.nvr, model->nvrsz); - - device_add(&t1200_video_device); -} - - -void -machine_xt_t1x00_close(void) + memset(nvr->regs, 0x00, 16); + nvr->regs[TC8521_WEEKDAY] = 0x01; + nvr->regs[TC8521_DAY1] = 0x01; + nvr->regs[TC8521_MONTH1] = 0x01; +} + + +static void +tc8521_init(nvr_t *nvr, int size) { - cfgsys_save(&t1000); -} - - -void -t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask) -{ - t1000.syskeys &= ~andmask; - t1000.syskeys |= ormask; - t1000.syskeys ^= xormask; -} + /* This is machine specific. */ + nvr->size = size; + nvr->irq = -1; + + /* Set up any local handlers here. */ + nvr->reset = tc8521_reset; + nvr->start = tc8521_start; + nvr->tick = tc8521_tick; + + /* Initialize the actual NVR. */ + nvr_init(nvr); + + io_sethandler(0x02c0, 16, + tc8521_read,NULL,NULL, tc8521_write,NULL,NULL, nvr); +} + + +/* Given an EMS page ID, return its physical address in RAM. */ +static uint32_t +ems_execaddr(t1000_t *sys, int pg, uint16_t val) +{ + if (!(val & 0x80)) return(0); /* Bit 7 reset => not mapped */ + if (!sys->ems_pages) return(0); /* No EMS available: all used by + * HardRAM or conventional RAM */ + val &= 0x7f; + +#if 0 + pclog("Select EMS page: %d of %d\n", val, sys->ems_pages); +#endif + if (val < sys->ems_pages) { + /* EMS is any memory above 512k, + with ems_base giving the start address */ + return((512 * 1024) + (sys->ems_base * 0x10000) + (0x4000 * val)); + } + + return(0); +} + + +static uint8_t +ems_in(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + +#if 0 + pclog("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]); +#endif + return(sys->ems_reg[(addr >> 14) & 3]); +} + + +static void +ems_out(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = (addr >> 14) & 3; + +#if 0 + pclog("ems_out(%04x, %02x) pg=%d\n", addr, val, pg); +#endif + sys->ems_reg[pg] = val; + sys->page_exec[pg] = ems_execaddr(sys, pg, val); + if (sys->page_exec[pg]) { + /* Page present */ + mem_mapping_enable(&sys->mapping[pg]); + mem_mapping_set_exec(&sys->mapping[pg], ram + sys->page_exec[pg]); + } else { + mem_mapping_disable(&sys->mapping[pg]); + } +} + + +/* Hardram size is in 64k units */ +static void +ems_set_hardram(t1000_t *sys, uint8_t val) +{ + int n; + + val &= 0x1f; /* Mask off pageframe address */ + if (val && mem_size > 512) + sys->ems_base = val; + else + sys->ems_base = 0; + +#if 0 + pclog("EMS base set to %02x\n", val); +#endif + sys->ems_pages = 48 - 4 * sys->ems_base; + if (sys->ems_pages < 0) sys->ems_pages = 0; + + /* Recalculate EMS mappings */ + for (n = 0; n < 4; n++) + ems_out(n << 14, sys->ems_reg[n], sys); +} + + +static void +ems_set_640k(t1000_t *sys, uint8_t val) +{ + if (val && mem_size >= 640) { + mem_mapping_set_addr(&ram_low_mapping, 0, 640 * 1024); + sys->is_640k = 1; + } else { + mem_mapping_set_addr(&ram_low_mapping, 0, 512 * 1024); + sys->is_640k = 0; + } +} + + +static void +ems_set_port(t1000_t *sys, uint8_t val) +{ + int n; + +#if 0 + pclog("ems_set_port(%d)", val & 0x0f); +#endif + if (sys->ems_port) { + for (n = 0; n <= 0xc000; n += 0x4000) { + io_removehandler(sys->ems_port+n, 1, + ems_in,NULL,NULL, ems_out,NULL,NULL, sys); + } + sys->ems_port = 0; + } + + val &= 0x0f; + sys->ems_port_index = val; + if (val == 7) { + /* No EMS */ + sys->ems_port = 0; + } else { + sys->ems_port = 0x208 | (val << 4); + for (n = 0; n <= 0xc000; n += 0x4000) { + io_sethandler(sys->ems_port+n, 1, + ems_in,NULL,NULL, ems_out,NULL,NULL, sys); + } + sys->ems_port = 0; + } + +#if 0 + pclog(" -> %04x\n", sys->ems_port); +#endif +} + + +static int +addr_to_page(uint32_t addr) +{ + return((addr - 0xd0000) / 0x4000); +} + + +/* Read RAM in the EMS page frame. */ +static uint8_t +ems_read_ram(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + addr = sys->page_exec[pg] + (addr & 0x3fff); + + return(ram[addr]); +} + + +static uint16_t +ems_read_ramw(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + +#if 0 + pclog("ems_read_ramw addr=%05x ", addr); +#endif + addr = sys->page_exec[pg] + (addr & 0x3FFF); + +#if 0 + pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); +#endif + + return(*(uint16_t *)&ram[addr]); +} + + +static uint32_t +ems_read_raml(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + addr = sys->page_exec[pg] + (addr & 0x3fff); + + return(*(uint32_t *)&ram[addr]); +} + + +/* Write RAM in the EMS page frame. */ +static void +ems_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + + addr = sys->page_exec[pg] + (addr & 0x3fff); + if (ram[addr] != val) nvr_dosave = 1; + + ram[addr] = val; +} + + +static void +ems_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + +#if 0 + pclog("ems_write_ramw addr=%05x ", addr); +#endif + addr = sys->page_exec[pg] + (addr & 0x3fff); + +#if 0 + pclog("-> %06x val=%04x\n", addr, val); +#endif + + if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; + + *(uint16_t *)&ram[addr] = val; +} + + +static void +ems_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + + addr = sys->page_exec[pg] + (addr & 0x3fff); + if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; + + *(uint32_t *)&ram[addr] = val; +} + + +static uint8_t +read_ctl(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + uint8_t ret = 0xff; + + switch (addr & 0x0f) { + case 1: + ret = sys->syskeys; + break; + + case 0x0f: /* Detect EMS board */ + switch (sys->sys_ctl[0x0e]) { + case 0x50: + if (mem_size > 512) break; + ret = (0x90 | sys->ems_port_index); + break; + + case 0x51: + /* 0x60 is the page frame address: + (0xd000 - 0xc400) / 0x20 */ + ret = (sys->ems_base | 0x60); + break; + + case 0x52: + ret = (sys->is_640k ? 0x80 : 0); + break; + } + break; + + default: + ret = (sys->sys_ctl[addr & 0x0f]); + } + + return(ret); +} + + +/* Load contents of "CONFIG.SYS" device from file. */ +static void +cfgsys_load(t1000_t *dev) +{ + char temp[128]; + FILE *f; + + /* Set up the file's name. */ + sprintf(temp, "%s_cfgsys.nvr", machine_get_internal_name()); + mbstowcs(dev->cfgsys_fn, temp, sizeof_w(dev->cfgsys_fn)); + + /* Now attempt to load the file. */ + memset(dev->cfgsys, 0x1a, dev->cfgsys_len); + f = plat_fopen(nvr_path(dev->cfgsys_fn), L"rb"); + if (f != NULL) { + pclog("NVR: loaded CONFIG.SYS from '%ls'\n", dev->cfgsys_fn); + (void)fread(dev->cfgsys, dev->cfgsys_len, 1, f); + fclose(f); + } + else pclog("NVR: initialized CONFIG.SYS for '%ls'\n", dev->cfgsys_fn); +} + + +/* Write the contents of "CONFIG.SYS" to file. */ +static void +cfgsys_save(t1000_t *dev) +{ + FILE *f; + + /* Avoids writing empty files. */ + if (dev->cfgsys_len < 160) return; + + f = plat_fopen(nvr_path(dev->cfgsys_fn), L"wb"); + if (f != NULL) { + pclog("NVR: saved CONFIG.SYS to '%ls'\n", dev->cfgsys_fn); + (void)fwrite(dev->cfgsys, dev->cfgsys_len, 1, f); + fclose(f); + } +} + + +#if NOTUSED +/* All RAM beyond 512K is non-volatile */ +static void +emsboard_load(t1000_t *dev) +{ + FILE *f; + + if (mem_size > 512) { + f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb"); + if (f != NULL) { + fread(&ram[512 * 1024], 1024, (mem_size - 512), f); + fclose(f); + } + } +} + + +static void +emsboard_save(t1000_t *dev) +{ + FILE *f; + + if (mem_size > 512) { + f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb"); + if (f != NULL) { + fwrite(&ram[512 * 1024], 1024, (mem_size - 512), f); + fclose(f); + } + } +} +#endif + + +static void +t1200_turbo_set(uint8_t value) +{ + if (value == t1000.turbo) return; + + t1000.turbo = value; + if (! value) + cpu_dynamic_switch(0); + else + cpu_dynamic_switch(cpu); +} + + +static void +write_ctl(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + sys->sys_ctl[addr & 0x0f] = val; + switch (addr & 0x0f) { + case 4: /* Video control */ + if (sys->sys_ctl[3] == 0x5A) { + t1000_video_options_set((val & 0x20) ? 1 : 0); + t1000_display_set((val & 0x40) ? 0 : 1); + if (romset == ROM_T1200) + t1200_turbo_set((val & 0x80) ? 1 : 0); + } + break; + + case 0x0f: /* EMS control */ + switch (sys->sys_ctl[0x0e]) { + case 0x50: + ems_set_port(sys, val); + break; + + case 0x51: + ems_set_hardram(sys, val); + break; + + case 0x52: + ems_set_640k(sys, val); + break; + } + break; + } +} + + +/* Ports 0xC0 to 0xC3 appear to have two purposes: + * + * > Access to the 160 bytes of non-volatile RAM containing CONFIG.SYS + * > Reading the floppy changeline. I don't know why the Toshiba doesn't + * use the normal port 0x3F7 for this, but it doesn't. + * + */ +static uint8_t +t1000_read_nvram(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + uint8_t tmp = 0xff; + + switch (addr) { + case 0xc2: /* Read next byte from NVRAM */ + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) + tmp = sys->cfgsys[sys->nvr_addr]; + sys->nvr_addr++; + break; + + case 0xc3: /* Read floppy changeline and NVRAM ready state */ + tmp = fdc_read(0x03f7, t1000.fdc); + + tmp = (tmp & 0x80) >> 3; /* Bit 4 is changeline */ + tmp |= (sys->nvr_active & 0xc0);/* Bits 6,7 are r/w mode */ + tmp |= 0x2e; /* Bits 5,3,2,1 always 1 */ + tmp |= (sys->nvr_active & 0x40) >> 6; /* Ready state */ + break; + } + + return(tmp); +} + + +static void +t1000_write_nvram(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + /* + * On the real T1000, port 0xC1 is only usable as the high byte + * of a 16-bit write to port 0xC0, with 0x5A in the low byte. + */ + switch (addr) { + case 0xc0: + sys->nvr_c0 = val; + break; + + case 0xc1: /* Write next byte to NVRAM */ + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) { + if (sys->cfgsys[sys->nvr_addr] != val) + nvr_dosave = 1; + sys->cfgsys[sys->nvr_addr] = val; + } + sys->nvr_addr++; + break; + + case 0xc2: + break; + + case 0xc3: + /* + * At start of NVRAM read / write, 0x80 is written to + * port 0xC3. This seems to reset the NVRAM address + * counter. A single byte is then written (0xff for + * write, 0x00 for read) which appears to be ignored. + * Simulate that by starting the address counter off + * at -1. + */ + sys->nvr_active = val; + if (val == 0x80) sys->nvr_addr = -1; + break; + } +} + + +/* Port 0xC8 controls the ROM drive */ +static uint8_t +t1000_read_rom_ctl(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + return(sys->rom_ctl); +} + + +static void +t1000_write_rom_ctl(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + sys->rom_ctl = val; + if (sys->romdrive && (val & 0x80)) { + /* Enable */ + sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMSIZE; + mem_mapping_set_addr(&sys->rom_mapping, 0xa0000, 0x10000); + mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + sys->rom_offset); + mem_mapping_enable(&sys->rom_mapping); + } else { + mem_mapping_disable(&sys->rom_mapping); + } +} + + +/* Read the ROM drive */ +static uint8_t +t1000_read_rom(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xff); + + return(sys->romdrive[sys->rom_offset + (addr & 0xffff)]); +} + + +static uint16_t +t1000_read_romw(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xffff); + + return(*(uint16_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); +} + + +static uint32_t +t1000_read_roml(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xffffffff); + + return(*(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); +} + + +const device_t * +t1000_get_device(void) +{ + return(&t1000_video_device); +} + + +void +machine_xt_t1000_init(const machine_t *model, void *arg) +{ + FILE *f; + int pg; + + memset(&t1000, 0x00, sizeof(t1000)); + t1000.turbo = 0xff; + t1000.ems_port_index = 7; /* EMS disabled */ + + /* Load the T1000 CGA Font ROM. */ + loadfont(L"roms/machines/toshiba/t1000/t1000font.rom", 2); + + /* + * The ROM drive is optional. + * + * If the file is missing, continue to boot; the BIOS will + * complain 'No ROM drive' but boot normally from floppy. + */ + f = rom_fopen(L"roms/machines/toshiba/t1000/t1000dos.rom"); + if (f != NULL) { + t1000.romdrive = malloc(T1000_ROMSIZE); + if (t1000.romdrive) { + memset(t1000.romdrive, 0xff, T1000_ROMSIZE); + fread(t1000.romdrive, T1000_ROMSIZE, 1, f); + } + fclose(f); + } + mem_mapping_add(&t1000.rom_mapping, 0xa0000, 0x10000, + t1000_read_rom,t1000_read_romw,t1000_read_roml, + NULL,NULL,NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); + mem_mapping_disable(&t1000.rom_mapping); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { + mem_mapping_add(&t1000.mapping[pg], 0xd0000 + (0x4000 * pg), 16384, + ems_read_ram,ems_read_ramw,ems_read_raml, + ems_write_ram,ems_write_ramw,ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, &t1000); + + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* Non-volatile RAM for CONFIG.SYS */ + t1000.cfgsys_len = 160; + t1000.cfgsys = (uint8_t *)malloc(t1000.cfgsys_len); + io_sethandler(0xc0, 4, + t1000_read_nvram,NULL,NULL, + t1000_write_nvram,NULL,NULL, &t1000); + cfgsys_load(&t1000); + + /* ROM drive */ + io_sethandler(0xc8, 1, + t1000_read_rom_ctl,NULL,NULL, + t1000_write_rom_ctl,NULL,NULL, &t1000); + + /* System control functions, and add-on memory board */ + io_sethandler(0xe0, 16, + read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); + + machine_common_init(model, arg); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_device); + t1000.fdc = device_add(&fdc_xt_device); + nmi_init(); + + tc8521_init(&t1000.nvr, model->nvrsz); + + device_add(&t1000_video_device); +} + + +static +uint8_t t1200_nvram_read(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + return(sys->cfgsys[addr & 0x7ff]); +} + + +static void +t1200_nvram_write(uint32_t addr, uint8_t value, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (sys->cfgsys[addr & 0x7ff] != value) + nvr_dosave = 1; + + sys->cfgsys[addr & 0x7ff] = value; +} + + +const device_t * +t1200_get_device(void) +{ + return(&t1200_video_device); +} + + +void +machine_xt_t1200_init(const machine_t *model, void *arg) +{ + int pg; + + memset(&t1000, 0x00, sizeof(t1000)); + t1000.ems_port_index = 7; /* EMS disabled */ + + /* Load the T1200 CGA Font ROM. */ + loadfont(L"roms/machines/toshiba/t1200/t1000font.bin", 2); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { + mem_mapping_add(&t1000.mapping[pg], + 0xd0000 + (0x4000 * pg), 16384, + ems_read_ram,ems_read_ramw,ems_read_raml, + ems_write_ram,ems_write_ramw,ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, &t1000); + + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* System control functions, and add-on memory board */ + io_sethandler(0xe0, 16, + read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); + + machine_common_init(model, arg); + + /* Non-volatile RAM for CONFIG.SYS */ + t1000.cfgsys_len = 2048; + t1000.cfgsys = (uint8_t *)malloc(t1000.cfgsys_len); + mem_mapping_add(&t1000.nvr_mapping, + 0x000f0000, t1000.cfgsys_len, + t1200_nvram_read,NULL,NULL, + t1200_nvram_write,NULL,NULL, + NULL, 0, &t1000); + cfgsys_load(&t1000); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_device); + t1000.fdc = device_add(&fdc_xt_device); + nmi_init(); + + tc8521_init(&t1000.nvr, model->nvrsz); + + device_add(&t1200_video_device); +} + + +void +machine_xt_t1x00_close(void) +{ + cfgsys_save(&t1000); +} + + +void +t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask) +{ + t1000.syskeys &= ~andmask; + t1000.syskeys |= ormask; + t1000.syskeys ^= xormask; +} diff --git a/src/machine/m_xt_xi8088.c b/src/machine/m_xt_xi8088.c index 59873ba..3224d61 100644 --- a/src/machine/m_xt_xi8088.c +++ b/src/machine/m_xt_xi8088.c @@ -8,7 +8,7 @@ * * Implementation of the Xi8088 open-source machine. * - * Version: @(#)m_xt_xi8088.c 1.0.3 2018/03/19 + * Version: @(#)m_xt_xi8088.c 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -166,7 +166,7 @@ xi8088_get_device(void) void -machine_xt_xi8088_init(const machine_t *model) +machine_xt_xi8088_init(const machine_t *model, void *arg) { if (biosmask < 0x010000) xi8088_bios_128kb_set(0); @@ -178,7 +178,7 @@ machine_xt_xi8088_init(const machine_t *model) * See if PCem always sets when we have > 640KB ram and avoids * conflicts when a peripheral uses the same memory space */ - machine_common_init(model); + machine_common_init(model, arg); nmi_init(); pic2_init(); diff --git a/src/machine/machine.c b/src/machine/machine.c index 48c6a74..ada19dc 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.c 1.0.9 2018/03/19 + * Version: @(#)machine.c 1.0.10 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -65,6 +65,7 @@ void machine_init(void) { wchar_t temp[1024]; + romdef_t r; pclog("Initializing as \"%s\"\n", machine_getname()); @@ -79,7 +80,7 @@ machine_init(void) wcscpy(temp, MACHINES_PATH); plat_append_slash(temp); wcscat(temp, machines[machine].bios_path); - if (! rom_load_bios(temp, 0)) return; + if (! rom_load_bios(&r, temp, 0)) return; /* Activate the ROM BIOS. */ mem_add_bios(); @@ -87,7 +88,7 @@ machine_init(void) ide_set_bus_master(NULL, NULL, NULL); /* All good, boot the machine! */ - machines[machine].init(&machines[machine]); + machines[machine].init(&machines[machine], &r); } @@ -105,12 +106,13 @@ int machine_available(int id) { wchar_t temp[1024]; + romdef_t r; int i; wcscpy(temp, MACHINES_PATH); plat_append_slash(temp); wcscat(temp, machines[id].bios_path); - i = rom_load_bios(temp, 1); + i = rom_load_bios(&r, temp, 1); return(i); } @@ -143,7 +145,7 @@ machine_detect(void) void -machine_common_init(const machine_t *model) +machine_common_init(const machine_t *model, UNUSED(void *arg)) { /* System devices first. */ dma_init(); diff --git a/src/machine/machine.h b/src/machine/machine.h index 2d13c09..e8d1a47 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -8,7 +8,7 @@ * * Handling of the emulated machines. * - * Version: @(#)machine.h 1.0.11 2018/03/18 + * Version: @(#)machine.h 1.0.12 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -214,7 +214,7 @@ typedef struct _machine_ { int min_ram, max_ram; int ram_granularity; int nvrsz; - void (*init)(const struct _machine_ *); + void (*init)(const struct _machine_ *, void *); #ifdef EMU_DEVICE_H const device_t *(*get_device)(void); #else @@ -253,104 +253,104 @@ extern void machine_close(void); /* Initialization functions for boards and systems. */ -extern void machine_common_init(const machine_t *); +extern void machine_common_init(const machine_t *, void *); -extern void machine_at_common_init(const machine_t *); -extern void machine_at_init(const machine_t *); -extern void machine_at_ps2_init(const machine_t *); -extern void machine_at_common_ide_init(const machine_t *); -extern void machine_at_ide_init(const machine_t *); -extern void machine_at_ps2_ide_init(const machine_t *); -extern void machine_at_top_remap_init(const machine_t *); -extern void machine_at_ide_top_remap_init(const machine_t *); +extern void machine_at_common_init(const machine_t *, void *); +extern void machine_at_init(const machine_t *, void *); +extern void machine_at_ps2_init(const machine_t *, void *); +extern void machine_at_common_ide_init(const machine_t *, void *); +extern void machine_at_ide_init(const machine_t *, void *); +extern void machine_at_ps2_ide_init(const machine_t *, void *); +extern void machine_at_top_remap_init(const machine_t *, void *); +extern void machine_at_ide_top_remap_init(const machine_t *, void *); -extern void machine_at_ibm_init(const machine_t *); +extern void machine_at_ibm_init(const machine_t *, void *); -extern void machine_at_t3100e_init(const machine_t *); +extern void machine_at_t3100e_init(const machine_t *, void *); -extern void machine_at_p54tp4xe_init(const machine_t *); -extern void machine_at_endeavor_init(const machine_t *); -extern void machine_at_zappa_init(const machine_t *); -extern void machine_at_mb500n_init(const machine_t *); -extern void machine_at_president_init(const machine_t *); -extern void machine_at_thor_init(const machine_t *); +extern void machine_at_p54tp4xe_init(const machine_t *, void *); +extern void machine_at_endeavor_init(const machine_t *, void *); +extern void machine_at_zappa_init(const machine_t *, void *); +extern void machine_at_mb500n_init(const machine_t *, void *); +extern void machine_at_president_init(const machine_t *, void *); +extern void machine_at_thor_init(const machine_t *, void *); -extern void machine_at_acerm3a_init(const machine_t *); -extern void machine_at_acerv35n_init(const machine_t *); -extern void machine_at_ap53_init(const machine_t *); -extern void machine_at_p55t2p4_init(const machine_t *); -extern void machine_at_p55t2s_init(const machine_t *); +extern void machine_at_acerm3a_init(const machine_t *, void *); +extern void machine_at_acerv35n_init(const machine_t *, void *); +extern void machine_at_ap53_init(const machine_t *, void *); +extern void machine_at_p55t2p4_init(const machine_t *, void *); +extern void machine_at_p55t2s_init(const machine_t *, void *); -extern void machine_at_batman_init(const machine_t *); -extern void machine_at_plato_init(const machine_t *); +extern void machine_at_batman_init(const machine_t *, void *); +extern void machine_at_plato_init(const machine_t *, void *); -extern void machine_at_p55tvp4_init(const machine_t *); -extern void machine_at_i430vx_init(const machine_t *); -extern void machine_at_p55va_init(const machine_t *); +extern void machine_at_p55tvp4_init(const machine_t *, void *); +extern void machine_at_i430vx_init(const machine_t *, void *); +extern void machine_at_p55va_init(const machine_t *, void *); #if defined(DEV_BRANCH) && defined(USE_I686) -extern void machine_at_i440fx_init(const machine_t *); -extern void machine_at_s1668_init(const machine_t *); +extern void machine_at_i440fx_init(const machine_t *, void *); +extern void machine_at_s1668_init(const machine_t *, void *); #endif -extern void machine_at_ali1429_init(const machine_t *); -extern void machine_at_cmdpc_init(const machine_t *); +extern void machine_at_ali1429_init(const machine_t *, void *); +extern void machine_at_cmdpc_init(const machine_t *, void *); -extern void machine_at_headland_init(const machine_t *); -extern void machine_at_neat_init(const machine_t *); -extern void machine_at_neat_ami_init(const machine_t *); -extern void machine_at_opti495_init(const machine_t *); -extern void machine_at_opti495_ami_init(const machine_t *); -extern void machine_at_scat_init(const machine_t *); -extern void machine_at_scatsx_init(const machine_t *); -extern void machine_at_compaq_init(const machine_t *); +extern void machine_at_headland_init(const machine_t *, void *); +extern void machine_at_neat_init(const machine_t *, void *); +extern void machine_at_neat_ami_init(const machine_t *, void *); +extern void machine_at_opti495_init(const machine_t *, void *); +extern void machine_at_opti495_ami_init(const machine_t *, void *); +extern void machine_at_scat_init(const machine_t *, void *); +extern void machine_at_scatsx_init(const machine_t *, void *); +extern void machine_at_compaq_init(const machine_t *, void *); -extern void machine_at_dtk486_init(const machine_t *); -extern void machine_at_r418_init(const machine_t *); +extern void machine_at_dtk486_init(const machine_t *, void *); +extern void machine_at_r418_init(const machine_t *, void *); -extern void machine_at_wd76c10_init(const machine_t *); +extern void machine_at_wd76c10_init(const machine_t *, void *); #if defined(DEV_BRANCH) && defined(USE_GREENB) -extern void machine_at_4gpv31_init(const machine_t *); +extern void machine_at_4gpv31_init(const machine_t *, void *); #endif -extern void machine_pcjr_init(const machine_t *); +extern void machine_pcjr_init(const machine_t *, void *); -extern void machine_ps1_m2011_init(const machine_t *); -extern void machine_ps1_m2121_init(const machine_t *); -extern void machine_ps1_m2133_init(const machine_t *); +extern void machine_ps1_m2011_init(const machine_t *, void *); +extern void machine_ps1_m2121_init(const machine_t *, void *); +extern void machine_ps1_m2133_init(const machine_t *, void *); -extern void machine_ps2_m30_286_init(const machine_t *); -extern void machine_ps2_model_50_init(const machine_t *); -extern void machine_ps2_model_55sx_init(const machine_t *); -extern void machine_ps2_model_70_type3_init(const machine_t *); -extern void machine_ps2_model_70_type4_init(const machine_t *); -extern void machine_ps2_model_80_init(const machine_t *); +extern void machine_ps2_m30_286_init(const machine_t *, void *); +extern void machine_ps2_model_50_init(const machine_t *, void *); +extern void machine_ps2_model_55sx_init(const machine_t *, void *); +extern void machine_ps2_model_70_type3_init(const machine_t *, void *); +extern void machine_ps2_model_70_type4_init(const machine_t *, void *); +extern void machine_ps2_model_80_init(const machine_t *, void *); -extern void machine_amstrad_init(const machine_t *); +extern void machine_amstrad_init(const machine_t *, void *); -extern void machine_europc_init(const machine_t *); +extern void machine_europc_init(const machine_t *, void *); #ifdef EMU_DEVICE_H extern const device_t europc_device, europc_hdc_device; #endif -extern void machine_olim24_init(const machine_t *); +extern void machine_olim24_init(const machine_t *, void *); extern void machine_olim24_video_init(void); -extern void machine_tandy1k_init(const machine_t *); +extern void machine_tandy1k_init(const machine_t *, void *); extern int tandy1k_eeprom_read(void); -extern void machine_xt_init(const machine_t *); -extern void machine_xt_compaq_init(const machine_t *); +extern void machine_xt_init(const machine_t *, void *); +extern void machine_xt_compaq_init(const machine_t *, void *); #if defined(DEV_BRANCH) && defined(USE_LASERXT) -extern void machine_xt_laserxt_init(const machine_t *); +extern void machine_xt_laserxt_init(const machine_t *, void *); #endif -extern void machine_xt_t1000_init(const machine_t *); -extern void machine_xt_t1200_init(const machine_t *); +extern void machine_xt_t1000_init(const machine_t *, void *); +extern void machine_xt_t1200_init(const machine_t *, void *); extern void machine_xt_t1x00_close(void); -extern void machine_xt_xi8088_init(const machine_t *); +extern void machine_xt_xi8088_init(const machine_t *, void *); #ifdef EMU_DEVICE_H extern const device_t *xi8088_get_device(void); diff --git a/src/mem.c b/src/mem.c index 4af38fd..f64840a 100644 --- a/src/mem.c +++ b/src/mem.c @@ -1,1896 +1,1896 @@ -/* - * VARCem Virtual ARchaeological Computer EMulator. - * An emulator of (mostly) x86-based PC systems and devices, - * using the ISA,EISA,VLB,MCA and PCI system buses, roughly - * spanning the era between 1981 and 1995. - * - * This file is part of the VARCem Project. - * - * Memory handling and MMU. - * - * NOTE: Experimenting with dynamically allocated lookup tables; - * the DYNAMIC_TABLES=1 enables this. Will eventually go - * away, either way... - * - * Version: @(#)mem.c 1.0.9 2018/03/18 - * - * Authors: Fred N. van Kempen, - * Miran Grca, - * Sarah Walker, - * - * Copyright 2017,2018 Fred N. van Kempen. - * Copyright 2016-2018 Miran Grca. - * Copyright 2008-2018 Sarah Walker. - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the: - * - * Free Software Foundation, Inc. - * 59 Temple Place - Suite 330 - * Boston, MA 02111-1307 - * USA. - */ -#include -#include -#include -#include -#include -#include "emu.h" -#include "cpu/cpu.h" -#include "cpu/x86_ops.h" -#include "cpu/x86.h" -#include "machine/machine.h" -#include "machine/m_xt_xi8088.h" -#include "config.h" -#include "io.h" -#include "mem.h" -#include "rom.h" -#ifdef USE_DYNAREC -# include "cpu/codegen.h" -#else -# define PAGE_MASK_INDEX_MASK 3 -# define PAGE_MASK_INDEX_SHIFT 10 -# define PAGE_MASK_MASK 63 -# define PAGE_MASK_SHIFT 4 -#endif - - -#define DYNAMIC_TABLES 0 /* experimental */ - - -mem_mapping_t ram_low_mapping; -mem_mapping_t ram_high_mapping; -mem_mapping_t ram_mid_mapping; -mem_mapping_t bios_mapping[8]; -mem_mapping_t bios_high_mapping[8]; -mem_mapping_t romext_mapping; - -page_t *pages, /* RAM page table */ - **page_lookup; /* pagetable lookup */ -uint32_t pages_sz; /* #pages in table */ - -uint8_t isram[0x10000]; - -uint8_t *ram; /* the virtual RAM */ -uint32_t rammask; - -uint8_t *rom; /* the virtual ROM */ -uint8_t romext[32768]; -uint32_t biosmask; - -uint32_t pccache; -uint8_t *pccache2; - -int readlnext; -int readlookup[256], - readlookupp[256]; -uintptr_t *readlookup2; -int writelnext; -int writelookup[256], - writelookupp[256]; -uintptr_t *writelookup2; - -uint32_t mem_logical_addr; - -int shadowbios = 0, - shadowbios_write; -int readlnum = 0, - writelnum = 0; -int pctrans = 0; -int cachesize = 256; - -uint32_t ram_mapped_addr[64]; - -int split_mapping_enabled = 0; - -uint32_t get_phys_virt, - get_phys_phys; - -int mem_a20_key = 0, - mem_a20_alt = 0, - mem_a20_state = 0; - -int mmuflush = 0; -int mmu_perm = 4; - - -/* FIXME: re-do this with a 'mem_ops' struct. */ -static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv); -static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv); -static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv); -static void (*_mem_write_b[0x40000])(uint32_t addr, uint8_t val, void *priv); -static void (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv); -static void (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv); -static uint8_t *_mem_exec[0x40000]; -static void *_mem_priv_r[0x40000]; -static void *_mem_priv_w[0x40000]; -static mem_mapping_t *_mem_mapping_r[0x40000]; -static mem_mapping_t *_mem_mapping_w[0x40000]; -static int _mem_state[0x40000]; - -static mem_mapping_t base_mapping; -static mem_mapping_t ram_remapped_mapping; -static mem_mapping_t ram_split_mapping; - -#if FIXME -static uint8_t ff_array[0x1000]; -#else -static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; -#endif - -static int port_92_reg = 0; - - -void -resetreadlookup(void) -{ - int c; - - /* This is NULL after app startup, when mem_init() has not yet run. */ -#if DYNAMIC_TABLES -pclog("MEM: reset_lookup: pages=%08lx, lookup=%08lx, pages_sz=%i\n", pages, page_lookup, pages_sz); -#endif - - /* Initialize the page lookup table. */ -#if DYNAMIC_TABLES - memset(page_lookup, 0x00, pages_sz*sizeof(page_t *)); -#else - memset(page_lookup, 0x00, (1<<20)*sizeof(page_t *)); -#endif - - /* Initialize the tables for lower (<= 1024K) RAM. */ - for (c = 0; c < 256; c++) { - readlookup[c] = 0xffffffff; - writelookup[c] = 0xffffffff; - } - - /* Initialize the tables for high (> 1024K) RAM. */ -#if DYNAMIC_TABLES - memset(readlookup2, 0xff, pages_sz*sizeof(uintptr_t)); - memset(writelookup2, 0xff, pages_sz*sizeof(uintptr_t)); -#else - memset(readlookup2, 0xff, (1<<20)*sizeof(uintptr_t)); - memset(writelookup2, 0xff, (1<<20)*sizeof(uintptr_t)); -#endif - - readlnext = 0; - writelnext = 0; - pccache = 0xffffffff; -} - - -void -flushmmucache(void) -{ - int c; - - for (c = 0; c < 256; c++) { - if (readlookup[c] != 0xffffffff) { - readlookup2[readlookup[c]] = -1; - readlookup[c] = 0xffffffff; - } - if (writelookup[c] != 0xffffffff) { - page_lookup[writelookup[c]] = NULL; - writelookup2[writelookup[c]] = -1; - writelookup[c] = 0xffffffff; - } - } - mmuflush++; - - pccache = (uint32_t)0xffffffff; - pccache2 = (uint8_t *)0xffffffff; - -#ifdef USE_DYNAREC - codegen_flush(); -#endif -} - - -void -flushmmucache_nopc(void) -{ - int c; - - for (c = 0; c < 256; c++) { - if (readlookup[c] != 0xffffffff) { - readlookup2[readlookup[c]] = -1; - readlookup[c] = 0xffffffff; - } - if (writelookup[c] != 0xffffffff) { - page_lookup[writelookup[c]] = NULL; - writelookup2[writelookup[c]] = -1; - writelookup[c] = 0xffffffff; - } - } -} - - -void -flushmmucache_cr3(void) -{ - int c; - - for (c = 0; c < 256; c++) { - if (readlookup[c] != 0xffffffff) { - readlookup2[readlookup[c]] = -1; - readlookup[c] = 0xffffffff; - } - if (writelookup[c] != 0xffffffff) { - page_lookup[writelookup[c]] = NULL; - writelookup2[writelookup[c]] = -1; - writelookup[c] = 0xffffffff; - } - } -} - - -void -mem_flush_write_page(uint32_t addr, uint32_t virt) -{ - page_t *page_target = &pages[addr >> 12]; - int c; - - for (c = 0; c < 256; c++) { - if (writelookup[c] != 0xffffffff) { - uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; - - if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { - writelookup2[writelookup[c]] = -1; - page_lookup[writelookup[c]] = NULL; - writelookup[c] = 0xffffffff; - } - } - } -} - - -#define mmutranslate_read(addr) mmutranslatereal(addr,0) -#define mmutranslate_write(addr) mmutranslatereal(addr,1) -#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> 14]))[((x) >> 2) & 0xfff] - -uint32_t -mmutranslatereal(uint32_t addr, int rw) -{ - uint32_t temp,temp2,temp3; - uint32_t addr2; - - if (cpu_state.abrt) return -1; - - addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); - temp = temp2 = rammap(addr2); - if (! (temp&1)) { - cr2 = addr; - temp &= 1; - if (CPL == 3) temp |= 4; - if (rw) temp |= 2; - cpu_state.abrt = ABRT_PF; - abrt_error = temp; - return -1; - } - - if ((temp & 0x80) && (cr4 & CR4_PSE)) { - /*4MB page*/ - if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3 && !cpl_override) || cr0 & WP_FLAG))) { - cr2 = addr; - temp &= 1; - if (CPL == 3) - temp |= 4; - if (rw) - temp |= 2; - cpu_state.abrt = ABRT_PF; - abrt_error = temp; - - return -1; - } - - mmu_perm = temp & 4; - rammap(addr2) |= 0x20; - - return (temp & ~0x3fffff) + (addr & 0x3fffff); - } - - temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); - temp3 = temp & temp2; - if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && ((CPL == 3 && !cpl_override) || cr0&WP_FLAG))) { - cr2 = addr; - temp &= 1; - if (CPL == 3) temp |= 4; - if (rw) temp |= 2; - cpu_state.abrt = ABRT_PF; - abrt_error = temp; - return -1; - } - - mmu_perm = temp & 4; - rammap(addr2) |= 0x20; - rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw?0x60:0x20); - - return (temp&~0xfff)+(addr&0xfff); -} - - -uint32_t -mmutranslate_noabrt(uint32_t addr, int rw) -{ - uint32_t temp,temp2,temp3; - uint32_t addr2; - - if (cpu_state.abrt) - return -1; - - addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); - temp = temp2 = rammap(addr2); - - if (! (temp & 1)) - return -1; - - if ((temp & 0x80) && (cr4 & CR4_PSE)) { - /*4MB page*/ - if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (CPL == 3 || cr0 & WP_FLAG))) - return -1; - - return (temp & ~0x3fffff) + (addr & 0x3fffff); - } - - temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); - temp3 = temp & temp2; - - if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) - return -1; - - return (temp & ~0xfff) + (addr & 0xfff); -} - - -void -mmu_invalidate(uint32_t addr) -{ - flushmmucache_cr3(); -} - - -uint8_t -mem_addr_range_match(uint32_t addr, uint32_t start, uint32_t len) -{ - if (addr < start) - return 0; - else if (addr >= (start + len)) - return 0; - else - return 1; -} - - -uint32_t -mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len) -{ - uint32_t mask = len - 1; - - return chunk_start + (addr & mask); -} - - -void -addreadlookup(uint32_t virt, uint32_t phys) -{ - if (virt == 0xffffffff) return; - - if (readlookup2[virt>>12] != -1) return; - - if (readlookup[readlnext] != 0xffffffff) - readlookup2[readlookup[readlnext]] = -1; - - readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; - - readlookupp[readlnext] = mmu_perm; - readlookup[readlnext++] = virt >> 12; - readlnext &= (cachesize-1); - - cycles -= 9; -} - - -void -addwritelookup(uint32_t virt, uint32_t phys) -{ - if (virt == 0xffffffff) return; - - if (page_lookup[virt >> 12]) return; - - if (writelookup[writelnext] != -1) { - page_lookup[writelookup[writelnext]] = NULL; - writelookup2[writelookup[writelnext]] = -1; - } - -#ifdef USE_DYNAREC - if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page) -#else - if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3]) -#endif - page_lookup[virt >> 12] = &pages[phys >> 12]; - else - writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; - - writelookupp[writelnext] = mmu_perm; - writelookup[writelnext++] = virt >> 12; - writelnext &= (cachesize - 1); - - cycles -= 9; -} - - -uint8_t * -getpccache(uint32_t a) -{ - uint32_t a2; - - a2 = a; - - if (a2 < 0x100000 && ram_mapped_addr[a2 >> 14]) { - a = (ram_mapped_addr[a2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? a2 : (ram_mapped_addr[a2 >> 14] & ~0x3FFF) + (a2 & 0x3FFF); - return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; - } - - a2 = a; - - if (cr0 >> 31) { - pctrans=1; - a = mmutranslate_read(a); - pctrans = 0; - - if (a == 0xffffffff) return ram; - } - a &= rammask; - - if (_mem_exec[a >> 14]) { - if (_mem_mapping_r[a >> 14]->flags & MEM_MAPPING_ROM) - cpu_prefetch_cycles = cpu_rom_prefetch_cycles; - else - cpu_prefetch_cycles = cpu_mem_prefetch_cycles; - - return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xfff)]; - } - - pclog("Bad getpccache %08X\n", a); - -#if 0 - return &ff_array[0-(uintptr_t)(a2 & ~0xfff)]; -#else - return (uint8_t *)&ff_pccache; -#endif -} - - -uint8_t -readmembl(uint32_t addr) -{ - mem_logical_addr = addr; - - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if(addr < mem_size * 1024) return ram[addr]; - return 0xff; - } - - if (cr0 >> 31) { - addr = mmutranslate_read(addr); - if (addr == 0xffffffff) return 0xff; - } - addr &= rammask; - - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); - - return 0xff; -} - - -void -writemembl(uint32_t addr, uint8_t val) -{ - mem_logical_addr = addr; - - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < mem_size * 1024) - ram[addr] = val; - return; - } - - if (page_lookup[addr>>12]) { - page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); - - return; - } - - if (cr0 >> 31) { - addr = mmutranslate_write(addr); - if (addr == 0xffffffff) return; - } - addr &= rammask; - - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -} - - -uint8_t -readmemb386l(uint32_t seg, uint32_t addr) -{ - if (seg == -1) { - x86gpf("NULL segment", 0); - - return -1; - } - - mem_logical_addr = addr = addr + seg; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < mem_size * 1024) - return ram[addr]; - return 0xff; - } - - if (cr0 >> 31) { - addr = mmutranslate_read(addr); - if (addr == 0xffffffff) - return 0xff; - } - - addr &= rammask; - - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); - - return 0xff; -} - - -void -writememb386l(uint32_t seg, uint32_t addr, uint8_t val) -{ - if (seg == -1) { - x86gpf("NULL segment", 0); - return; - } - - mem_logical_addr = addr = addr + seg; - if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { - addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); - if (addr < mem_size * 1024) - ram[addr] = val; - return; - } - - if (page_lookup[addr>>12]) { - page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); - - return; - } - - if (cr0 >> 31) { - addr = mmutranslate_write(addr); - if (addr == 0xffffffff) return; - } - - addr &= rammask; - - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -} - - -uint16_t -readmemwl(uint32_t seg, uint32_t addr) -{ - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (seg == -1) { - x86gpf("NULL segment", 0); - return -1; - } - - if (addr2 & 1) { - if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - cycles -= timing_misaligned; - if ((addr2 & 0xFFF) > 0xffe) { - if (cr0 >> 31) { - if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; - if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; - } - if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8); - else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8); - } - else if (readlookup2[addr2 >> 12] != -1) - return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - return *((uint16_t *)&ram[addr]); - return 0xffff; - } - - if (cr0 >> 31) { - addr2 = mmutranslate_read(addr2); - if (addr2 == 0xffffffff) - return 0xFFFF; - } - - addr2 &= rammask; - - if (_mem_read_w[addr2 >> 14]) - return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); - - if (_mem_read_b[addr2 >> 14]) { - if (AT) - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8); - else - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14]) << 8); - } - - return 0xffff; -} - - -void -writememwl(uint32_t seg, uint32_t addr, uint16_t val) -{ - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (seg == -1) { - x86gpf("NULL segment", 0); - return; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint16_t *)&ram[addr]) = val; - return; - } - - if (addr2 & 1) { - if (!cpu_cyrix_alignment || (addr2 & 7) == 7) - cycles -= timing_misaligned; - if ((addr2 & 0xFFF) > 0xffe) { - if (cr0 >> 31) { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+1) == 0xffffffff) return; - } - if (is386) { - writememb386l(seg,addr,val); - writememb386l(seg,addr+1,val>>8); - } else { - writemembl(seg+addr,val); - writemembl(seg+addr+1,val>>8); - } - return; - } else if (writelookup2[addr2 >> 12] != -1) { - *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val; - return; - } - } - - if (page_lookup[addr2>>12]) { - page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]); - return; - } - - if (cr0 >> 31) { - addr2 = mmutranslate_write(addr2); - if (addr2 == 0xffffffff) return; - } - - addr2 &= rammask; - -#if 0 - if (addr2 >= 0xa0000 && addr2 < 0xc0000) - pclog("writememwl %08X %02X\n", addr2, val); -#endif - - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - return; - } - - if (_mem_write_b[addr2 >> 14]) { - _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); - return; - } -} - - -uint32_t -readmemll(uint32_t seg, uint32_t addr) -{ - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (seg == -1) { - x86gpf("NULL segment", 0); - return -1; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - return *((uint32_t *)&ram[addr]); - return 0xffffffff; - } - - if (addr2 & 3) { - if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - cycles -= timing_misaligned; - if ((addr2 & 0xfff) > 0xffc) { - if (cr0 >> 31) { - if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; - if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; - } - return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); - } else if (readlookup2[addr2 >> 12] != -1) - return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2); - } - - if (cr0 >> 31) { - addr2 = mmutranslate_read(addr2); - if (addr2 == 0xffffffff) - return 0xffffffff; - } - - addr2 &= rammask; - - if (_mem_read_l[addr2 >> 14]) - return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); - - if (_mem_read_w[addr2 >> 14]) - return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16); - - if (_mem_read_b[addr2 >> 14]) - return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8) | (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16) | (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14]) << 24); - - return 0xffffffff; -} - - -void -writememll(uint32_t seg, uint32_t addr, uint32_t val) -{ - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (seg == -1) { - x86gpf("NULL segment", 0); - return; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint32_t *)&ram[addr]) = val; - return; - } - - if (addr2 & 3) { - if (!cpu_cyrix_alignment || (addr2 & 7) > 4) - cycles -= timing_misaligned; - if ((addr2 & 0xfff) > 0xffc) { - if (cr0 >> 31) { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+3) == 0xffffffff) return; - } - writememwl(seg,addr,val); - writememwl(seg,addr+2,val>>16); - return; - } else if (writelookup2[addr2 >> 12] != -1) { - *(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val; - return; - } - } - - if (page_lookup[addr2>>12]) { - page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); - return; - } - - if (cr0 >> 31) { - addr2 = mmutranslate_write(addr2); - if (addr2 == 0xffffffff) return; - } - - addr2 &= rammask; - - if (_mem_write_l[addr2 >> 14]) { - _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - return; - } - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); - return; - } - if (_mem_write_b[addr2 >> 14]) { - _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); - return; - } -} - - -uint64_t -readmemql(uint32_t seg, uint32_t addr) -{ - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (seg == -1) { - x86gpf("NULL segment", 0); - return -1; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - return *((uint64_t *)&ram[addr]); - return -1; - } - - if (addr2 & 7) { - cycles -= timing_misaligned; - if ((addr2 & 0xfff) > 0xff8) { - if (cr0 >> 31) { - if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; - if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff; - } - return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); - } else if (readlookup2[addr2 >> 12] != -1) - return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2); - } - - if (cr0 >> 31) { - addr2 = mmutranslate_read(addr2); - if (addr2 == 0xffffffff) - return -1; - } - - addr2 &= rammask; - - if (_mem_read_l[addr2 >> 14]) - return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | - ((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32); - - return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); -} - - -void -writememql(uint32_t seg, uint32_t addr, uint64_t val) -{ - uint32_t addr2 = mem_logical_addr = seg + addr; - - if (seg == -1) { - x86gpf("NULL segment", 0); - return; - } - - if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { - addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); - if (addr < mem_size * 1024) - *((uint64_t *)&ram[addr]) = val; - return; - } - - if (addr2 & 7) { - cycles -= timing_misaligned; - if ((addr2 & 0xfff) > 0xff8) { - if (cr0 >> 31) { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+7) == 0xffffffff) return; - } - writememll(seg, addr, val); - writememll(seg, addr+4, val >> 32); - return; - } else if (writelookup2[addr2 >> 12] != -1) { - *(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val; - return; - } - } - - if (page_lookup[addr2>>12]) { - page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); - page_lookup[addr2>>12]->write_l(addr2 + 4, val >> 32, page_lookup[addr2>>12]); - return; - } - - if (cr0 >> 31) { - addr2 = mmutranslate_write(addr2); - if (addr2 == 0xffffffff) return; - } - - addr2 &= rammask; - - if (_mem_write_l[addr2 >> 14]) { - _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_l[addr2 >> 14](addr2+4, val >> 32, _mem_priv_w[addr2 >> 14]); - return; - } - if (_mem_write_w[addr2 >> 14]) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); - _mem_write_w[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); - return; - } - if (_mem_write_b[addr2 >> 14]) { - _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 5, val >> 40, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); - _mem_write_b[addr2 >> 14](addr2 + 7, val >> 56, _mem_priv_w[addr2 >> 14]); - return; - } -} - - -uint8_t -mem_readb_phys(uint32_t addr) -{ - mem_logical_addr = 0xffffffff; - - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); - - return 0xff; -} - - -/* - * Version of mem_readby_phys that doesn't go through - * the CPU paging mechanism. - */ -uint8_t -mem_readb_phys_dma(uint32_t addr) -{ -#if 0 - mem_logical_addr = 0xffffffff; -#endif - - if (_mem_exec[addr >> 14]) - return _mem_exec[addr >> 14][addr & 0x3fff]; - else if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); - else - return 0xff; -} - - -uint16_t -mem_readw_phys(uint32_t addr) -{ - mem_logical_addr = 0xffffffff; - - if (_mem_read_w[addr >> 14]) - return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); - - return 0xff; -} - - -void -mem_writeb_phys(uint32_t addr, uint8_t val) -{ - mem_logical_addr = 0xffffffff; - - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -} - - -/* - * Version of mem_readby_phys that doesn't go through - * the CPU paging mechanism. - */ -void -mem_writeb_phys_dma(uint32_t addr, uint8_t val) -{ -#if 0 - mem_logical_addr = 0xffffffff; -#endif - - if (_mem_exec[addr >> 14]) - _mem_exec[addr >> 14][addr & 0x3fff] = val; - else if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -} - - -void -mem_writew_phys(uint32_t addr, uint16_t val) -{ - mem_logical_addr = 0xffffffff; - - if (_mem_write_w[addr >> 14]) - _mem_write_w[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); -} - - -uint8_t -mem_read_ram(uint32_t addr, void *priv) -{ - addreadlookup(mem_logical_addr, addr); - - return ram[addr]; -} - - -uint16_t -mem_read_ramw(uint32_t addr, void *priv) -{ - addreadlookup(mem_logical_addr, addr); - - return *(uint16_t *)&ram[addr]; -} - - -uint32_t -mem_read_raml(uint32_t addr, void *priv) -{ - addreadlookup(mem_logical_addr, addr); - - return *(uint32_t *)&ram[addr]; -} - - -void -mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) -{ -#ifdef USE_DYNAREC - if (val != p->mem[addr & 0xfff] || codegen_in_recompile) { -#else - if (val != p->mem[addr & 0xfff]) { -#endif - uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; - p->mem[addr & 0xfff] = val; - } -} - - -void -mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) -{ -#ifdef USE_DYNAREC - if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { -#else - if (val != *(uint16_t *)&p->mem[addr & 0xfff]) { -#endif - uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - if ((addr & 0xf) == 0xf) - mask |= (mask << 1); - p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; - *(uint16_t *)&p->mem[addr & 0xfff] = val; - } -} - - -void -mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) -{ -#ifdef USE_DYNAREC - if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { -#else - if (val != *(uint32_t *)&p->mem[addr & 0xfff]) { -#endif - uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - if ((addr & 0xf) >= 0xd) - mask |= (mask << 1); - p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; - *(uint32_t *)&p->mem[addr & 0xfff] = val; - } -} - - -void -mem_write_ram(uint32_t addr, uint8_t val, void *priv) -{ - addwritelookup(mem_logical_addr, addr); - mem_write_ramb_page(addr, val, &pages[addr >> 12]); -} - - -void -mem_write_ramw(uint32_t addr, uint16_t val, void *priv) -{ - addwritelookup(mem_logical_addr, addr); - mem_write_ramw_page(addr, val, &pages[addr >> 12]); -} - - -void -mem_write_raml(uint32_t addr, uint32_t val, void *priv) -{ - addwritelookup(mem_logical_addr, addr); - mem_write_raml_page(addr, val, &pages[addr >> 12]); -} - - -uint8_t -mem_read_bios(uint32_t addr, void *priv) -{ - return rom[addr & biosmask]; -} - - -uint16_t -mem_read_biosw(uint32_t addr, void *priv) -{ - return *(uint16_t *)&rom[addr & biosmask]; -} - - -uint32_t -mem_read_biosl(uint32_t addr, void *priv) -{ - return *(uint32_t *)&rom[addr & biosmask]; -} - - -uint8_t -mem_read_romext(uint32_t addr, void *priv) -{ - return romext[addr & 0x7fff]; -} - - -uint16_t -mem_read_romextw(uint32_t addr, void *priv) -{ - uint16_t *p = (uint16_t *)&romext[addr & 0x7fff]; - - return *p; -} - - -uint32_t -mem_read_romextl(uint32_t addr, void *priv) -{ - uint32_t *p = (uint32_t *)&romext[addr & 0x7fff]; - - return *p; -} - - -void -mem_write_null(uint32_t addr, uint8_t val, void *p) -{ -} - - -void -mem_write_nullw(uint32_t addr, uint16_t val, void *p) -{ -} - - -void -mem_write_nulll(uint32_t addr, uint32_t val, void *p) -{ -} - - -void -mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) -{ - start_addr &= ~PAGE_MASK_MASK; - end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; - - for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { - uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); - - pages[start_addr >> 12].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; - } -} - - -static __inline int -mem_mapping_read_allowed(uint32_t flags, int state) -{ - switch (state & MEM_READ_MASK) { - case MEM_READ_ANY: - return 1; - - case MEM_READ_EXTERNAL: - return !(flags & MEM_MAPPING_INTERNAL); - - case MEM_READ_INTERNAL: - return !(flags & MEM_MAPPING_EXTERNAL); - - default: - fatal("mem_mapping_read_allowed : bad state %x\n", state); - } - - return 0; -} - - -static __inline int -mem_mapping_write_allowed(uint32_t flags, int state) -{ - switch (state & MEM_WRITE_MASK) { - case MEM_WRITE_DISABLED: - return 0; - case MEM_WRITE_ANY: - return 1; - case MEM_WRITE_EXTERNAL: - return !(flags & MEM_MAPPING_INTERNAL); - case MEM_WRITE_INTERNAL: - return !(flags & MEM_MAPPING_EXTERNAL); - default: - fatal("mem_mapping_write_allowed : bad state %x\n", state); - } - - return 0; -} - - -static void -mem_mapping_recalc(uint64_t base, uint64_t size) -{ - mem_mapping_t *mapping = base_mapping.next; - uint64_t c; - - if (! size) return; - - /* Clear out old mappings. */ - for (c = base; c < base + size; c += 0x4000) { - _mem_read_b[c >> 14] = NULL; - _mem_read_w[c >> 14] = NULL; - _mem_read_l[c >> 14] = NULL; - _mem_priv_r[c >> 14] = NULL; - _mem_mapping_r[c >> 14] = NULL; - _mem_write_b[c >> 14] = NULL; - _mem_write_w[c >> 14] = NULL; - _mem_write_l[c >> 14] = NULL; - _mem_priv_w[c >> 14] = NULL; - _mem_mapping_w[c >> 14] = NULL; - } - - /* Walk mapping list. */ - while (mapping != NULL) { - /*In range?*/ - if (mapping->enable && (uint64_t)mapping->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)mapping->base + (uint64_t)mapping->size) > (uint64_t)base) { - uint64_t start = (mapping->base < base) ? mapping->base : base; - uint64_t end = (((uint64_t)mapping->base + (uint64_t)mapping->size) < (base + size)) ? ((uint64_t)mapping->base + (uint64_t)mapping->size) : (base + size); - if (start < mapping->base) - start = mapping->base; - - for (c = start; c < end; c += 0x4000) { - if ((mapping->read_b || mapping->read_w || mapping->read_l) && - mem_mapping_read_allowed(mapping->flags, _mem_state[c >> 14])) { - _mem_read_b[c >> 14] = mapping->read_b; - _mem_read_w[c >> 14] = mapping->read_w; - _mem_read_l[c >> 14] = mapping->read_l; - if (mapping->exec) - _mem_exec[c >> 14] = mapping->exec + (c - mapping->base); - else - _mem_exec[c >> 14] = NULL; - _mem_priv_r[c >> 14] = mapping->p; - _mem_mapping_r[c >> 14] = mapping; - } - if ((mapping->write_b || mapping->write_w || mapping->write_l) && - mem_mapping_write_allowed(mapping->flags, _mem_state[c >> 14])) { - _mem_write_b[c >> 14] = mapping->write_b; - _mem_write_w[c >> 14] = mapping->write_w; - _mem_write_l[c >> 14] = mapping->write_l; - _mem_priv_w[c >> 14] = mapping->p; - _mem_mapping_w[c >> 14] = mapping; - } - } - } - mapping = mapping->next; - } - - flushmmucache_cr3(); -} - - -void -mem_mapping_add(mem_mapping_t *mapping, - uint32_t base, - uint32_t size, - uint8_t (*read_b)(uint32_t addr, void *p), - uint16_t (*read_w)(uint32_t addr, void *p), - uint32_t (*read_l)(uint32_t addr, void *p), - void (*write_b)(uint32_t addr, uint8_t val, void *p), - void (*write_w)(uint32_t addr, uint16_t val, void *p), - void (*write_l)(uint32_t addr, uint32_t val, void *p), - uint8_t *exec, - uint32_t flags, - void *p) -{ - mem_mapping_t *dest = &base_mapping; - - /* Add mapping to the end of the list.*/ - while (dest->next) - dest = dest->next; - dest->next = mapping; - mapping->prev = dest; - - if (size) - mapping->enable = 1; - else - mapping->enable = 0; - mapping->base = base; - mapping->size = size; - mapping->read_b = read_b; - mapping->read_w = read_w; - mapping->read_l = read_l; - mapping->write_b = write_b; - mapping->write_w = write_w; - mapping->write_l = write_l; - mapping->exec = exec; - mapping->flags = flags; - mapping->p = p; - mapping->next = NULL; - - mem_mapping_recalc(mapping->base, mapping->size); -} - - -void -mem_mapping_set_handler(mem_mapping_t *mapping, - uint8_t (*read_b)(uint32_t addr, void *p), - uint16_t (*read_w)(uint32_t addr, void *p), - uint32_t (*read_l)(uint32_t addr, void *p), - void (*write_b)(uint32_t addr, uint8_t val, void *p), - void (*write_w)(uint32_t addr, uint16_t val, void *p), - void (*write_l)(uint32_t addr, uint32_t val, void *p)) -{ - mapping->read_b = read_b; - mapping->read_w = read_w; - mapping->read_l = read_l; - mapping->write_b = write_b; - mapping->write_w = write_w; - mapping->write_l = write_l; - - mem_mapping_recalc(mapping->base, mapping->size); -} - - -void -mem_mapping_set_addr(mem_mapping_t *mapping, uint32_t base, uint32_t size) -{ - /* Remove old mapping. */ - mapping->enable = 0; - mem_mapping_recalc(mapping->base, mapping->size); - - /* Set new mapping. */ - mapping->enable = 1; - mapping->base = base; - mapping->size = size; - - mem_mapping_recalc(mapping->base, mapping->size); -} - - -void -mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec) -{ - mapping->exec = exec; - - mem_mapping_recalc(mapping->base, mapping->size); -} - - -void -mem_mapping_set_p(mem_mapping_t *mapping, void *p) -{ - mapping->p = p; -} - - -void -mem_mapping_disable(mem_mapping_t *mapping) -{ - mapping->enable = 0; - - mem_mapping_recalc(mapping->base, mapping->size); -} - - -void -mem_mapping_enable(mem_mapping_t *mapping) -{ - mapping->enable = 1; - - mem_mapping_recalc(mapping->base, mapping->size); -} - - -void -mem_set_mem_state(uint32_t base, uint32_t size, int state) -{ - uint32_t c; - - for (c = 0; c < size; c += 0x4000) - _mem_state[(c + base) >> 14] = state; - - mem_mapping_recalc(base, size); -} - - -void -mem_add_bios(void) -{ - if (AT || (romset == ROM_XI8088 && xi8088_bios_128kb())) { - mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom,MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x4000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x8000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0xc000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - } - - mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x10000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x14000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x18000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x1c000 & biosmask), - MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); - - mem_mapping_add(&bios_high_mapping[0], - (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom, MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[1], - (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x4000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[2], - (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x8000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[3], - (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0xc000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[4], - (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x10000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[5], - (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x14000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[6], - (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x18000 & biosmask), MEM_MAPPING_ROM, 0); - mem_mapping_add(&bios_high_mapping[7], - (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, - mem_read_bios,mem_read_biosw,mem_read_biosl, - mem_write_null,mem_write_nullw,mem_write_nulll, - rom + (0x1c000 & biosmask), MEM_MAPPING_ROM, 0); -} - - -void -mem_a20_init(void) -{ - if (AT) { - rammask = cpu_16bitbus ? 0xefffff : 0xffefffff; - flushmmucache(); - mem_a20_state = mem_a20_key | mem_a20_alt; - } else { - rammask = 0xfffff; - flushmmucache(); - mem_a20_key = mem_a20_alt = mem_a20_state = 0; - } -} - - -/* Reset the memory state. */ -void -mem_reset(void) -{ - uint32_t c, m; - - split_mapping_enabled = 0; - - /* Free the ROM memory and reset size mask. */ - if (rom != NULL) { - free(rom); - rom = NULL; - } - biosmask = 0xffff; - - /* - * Always allocate the full 16 MB memory space if memory size - * is smaller, we'll need this for stupid things like the PS/2 - * split mapping. - */ - if (mem_size < 16384) - m = 1024UL * 16384; - else - m = 1024UL * (mem_size + 384); /* 386 extra kB for top remapping */ - if (ram != NULL) free(ram); - ram = (uint8_t *)malloc(m); /* allocate and clear the RAM block */ - memset(ram, 0x00, m); - - /* - * Allocate the page table based on how much RAM we have. - * We re-allocate the table on each (hard) reset, as the - * memory amount could have changed. - */ - if (AT) { - if (cpu_16bitbus) { - /* 80186/286; maximum address space is 16MB. */ - m = 4096; - } else { - /* 80386+; maximum address space is 4GB. */ - m = (mem_size + 384) >> 2; - if ((m << 2) < (mem_size + 384)) - m++; - if (m < 4096) - m = 4096; - } - } else { - /* 8088/86; maximum address space is 1MB. */ - m = 256; - } - - /* - * Allocate and initialize the (new) page table. - * We only do this if the size of the page table has changed. - */ -#if DYNAMIC_TABLES -pclog("MEM: reset: previous pages=%08lx, pages_sz=%i\n", pages, pages_sz); -#endif - if (pages_sz != m) { - pages_sz = m; - free(pages); - pages = (page_t *)malloc(m*sizeof(page_t)); - memset(pages, 0x00, m*sizeof(page_t)); -#if DYNAMIC_TABLES -pclog("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); -#endif - -#if DYNAMIC_TABLES - /* Allocate the (new) lookup tables. */ - if (page_lookup != NULL) free(page_lookup); - page_lookup = (page_t **)malloc(pages_sz*sizeof(page_t *)); - - if (readlookup2 != NULL) free(readlookup2); - readlookup2 = malloc(pages_sz*sizeof(uintptr_t)); - - if (writelookup2 != NULL) free(writelookup2); - writelookup2 = malloc(pages_sz*sizeof(uintptr_t)); -#endif - } - - /* Initialize the page table. */ - for (c = 0; c < m; c++) { - pages[c].mem = &ram[c << 12]; - pages[c].write_b = mem_write_ramb_page; - pages[c].write_w = mem_write_ramw_page; - pages[c].write_l = mem_write_raml_page; - } - - /* Initialize the tables. */ - resetreadlookup(); - - memset(isram, 0x00, sizeof(isram)); - for (c = 0; c < (mem_size / 64); c++) { - isram[c] = 1; - if ((c >= 0xa && c <= 0xf) || - (cpu_16bitbus && c >= 0xfe && c <= 0xff)) - isram[c] = 0; - } - - memset(_mem_read_b, 0x00, sizeof(_mem_read_b)); - memset(_mem_read_w, 0x00, sizeof(_mem_read_w)); - memset(_mem_read_l, 0x00, sizeof(_mem_read_l)); - memset(_mem_write_b, 0x00, sizeof(_mem_write_b)); - memset(_mem_write_w, 0x00, sizeof(_mem_write_w)); - memset(_mem_write_l, 0x00, sizeof(_mem_write_l)); - memset(_mem_exec, 0x00, sizeof(_mem_exec)); - - memset(&base_mapping, 0x00, sizeof(base_mapping)); - - memset(_mem_state, 0x00, sizeof(_mem_state)); - - mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_set_mem_state(0x0c0000, 0x40000, - MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); - - mem_mapping_add(&ram_low_mapping, 0x00000, - (mem_size > 640) ? 0xa0000 : mem_size * 1024, - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram, MEM_MAPPING_INTERNAL, NULL); - - if (mem_size > 1024) { - if (cpu_16bitbus && mem_size > 16256) { - mem_set_mem_state(0x100000, (16256 - 1024) * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_add(&ram_high_mapping, 0x100000, - ((16256 - 1024) * 1024), - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); - } else { - mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_add(&ram_high_mapping, 0x100000, - ((mem_size - 1024) * 1024), - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); - } - } - - if (mem_size > 768) - mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); - - if (romset == ROM_IBMPS1_2011) - mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, - mem_read_romext,mem_read_romextw,mem_read_romextl, - NULL,NULL, NULL, romext, 0, NULL); - - mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 384 * 1024, - mem_read_ram,mem_read_ramw,mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + (1 << 20), MEM_MAPPING_INTERNAL, NULL); - mem_mapping_disable(&ram_remapped_mapping); - - mem_mapping_add(&ram_split_mapping, mem_size * 1024, 384 * 1024, - mem_read_ram, mem_read_ramw, mem_read_raml, - mem_write_ram,mem_write_ramw,mem_write_raml, - ram + (1 << 20), MEM_MAPPING_INTERNAL, NULL); - mem_mapping_disable(&ram_split_mapping); - - mem_a20_init(); -} - - -void -mem_init(void) -{ - /* Perform a one-time init. */ - ram = rom = NULL; - pages = NULL; -#if DYNAMIC_TABLES - page_lookup = NULL; - readlookup2 = NULL; - writelookup2 = NULL; - -#else - /* Allocate the lookup tables. */ - page_lookup = (page_t **)malloc((1<<20)*sizeof(page_t *)); - - readlookup2 = malloc((1<<20)*sizeof(uintptr_t)); - - writelookup2 = malloc((1<<20)*sizeof(uintptr_t)); -#endif - - memset(ram_mapped_addr, 0x00, 64 * sizeof(uint32_t)); - -#if FIXME - memset(ff_array, 0xff, sizeof(ff_array)); -#endif - - /* Reset the memory state. */ - mem_reset(); -} - - -static void -mem_remap_top(int max_size) -{ - int c; - - if (mem_size > 640) { - uint32_t start = (mem_size >= 1024) ? mem_size : 1024; - int size = mem_size - 640; - if (size > max_size) - size = max_size; - - for (c = (start / 64); c < ((start + size - 1) / 64); c++) - isram[c] = 1; - - mem_set_mem_state(start * 1024, size * 1024, - MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_set_addr(&ram_remapped_mapping, - start * 1024, size * 1024); - mem_mapping_set_exec(&ram_split_mapping, ram + (start * 1024)); - - flushmmucache(); - } -} - - -void -mem_remap_top_256k(void) -{ - mem_remap_top(256); -} - - -void -mem_remap_top_384k(void) -{ - mem_remap_top(384); -} - - -void -mem_reset_page_blocks(void) -{ - int c; - - if (pages == NULL) return; - - for (c = 0; c < ((mem_size * 1024) >> 12); c++) { - pages[c].write_b = mem_write_ramb_page; - pages[c].write_w = mem_write_ramw_page; - pages[c].write_l = mem_write_raml_page; - pages[c].block[0] = pages[c].block[1] = pages[c].block[2] = pages[c].block[3] = NULL; - pages[c].block_2[0] = pages[c].block_2[1] = pages[c].block_2[2] = pages[c].block_2[3] = NULL; - } -} - - -void -mem_a20_recalc(void) -{ - int state; - - if (! AT) { - rammask = 0xfffff; - flushmmucache(); - mem_a20_key = mem_a20_alt = mem_a20_state = 0; - - return; - } - - state = mem_a20_key | mem_a20_alt; - if (state && !mem_a20_state) { - rammask = (AT && cpu_16bitbus) ? 0xffffff : 0xffffffff; - flushmmucache(); - } else if (!state && mem_a20_state) { - rammask = (AT && cpu_16bitbus) ? 0xefffff : 0xffefffff; - flushmmucache(); - } - - mem_a20_state = state; -} - - -uint8_t -port_92_read(uint16_t port, void *priv) -{ - return port_92_reg; -} - - -void -port_92_write(uint16_t port, uint8_t val, void *priv) -{ - if ((mem_a20_alt ^ val) & 2) { - mem_a20_alt = (val & 2); - mem_a20_recalc(); - } - - if ((~port_92_reg & val) & 1) { - softresetx86(); - cpu_set_edx(); - } - - port_92_reg = val; -} - - -void -port_92_clear_reset(void) -{ - port_92_reg &= 2; -} - - -void -port_92_add(void) -{ - io_sethandler(0x0092, 1, - port_92_read,NULL,NULL, port_92_write, NULL,NULL,NULL); -} - - -void -port_92_remove(void) -{ - io_removehandler(0x0092, 1, - port_92_read,NULL,NULL, port_92_write,NULL,NULL, NULL); -} - - -void -port_92_reset(void) -{ - port_92_reg = 0; - mem_a20_alt = 0; - mem_a20_recalc(); - - flushmmucache(); -} +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Memory handling and MMU. + * + * NOTE: Experimenting with dynamically allocated lookup tables; + * the DYNAMIC_TABLES=1 enables this. Will eventually go + * away, either way... + * + * Version: @(#)mem.c 1.0.9 2018/03/18 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "emu.h" +#include "cpu/cpu.h" +#include "cpu/x86_ops.h" +#include "cpu/x86.h" +#include "machine/machine.h" +#include "machine/m_xt_xi8088.h" +#include "config.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#ifdef USE_DYNAREC +# include "cpu/codegen.h" +#else +# define PAGE_MASK_INDEX_MASK 3 +# define PAGE_MASK_INDEX_SHIFT 10 +# define PAGE_MASK_MASK 63 +# define PAGE_MASK_SHIFT 4 +#endif + + +#define DYNAMIC_TABLES 0 /* experimental */ + + +mem_mapping_t ram_low_mapping; +mem_mapping_t ram_high_mapping; +mem_mapping_t ram_mid_mapping; +mem_mapping_t bios_mapping[8]; +mem_mapping_t bios_high_mapping[8]; +mem_mapping_t romext_mapping; + +page_t *pages, /* RAM page table */ + **page_lookup; /* pagetable lookup */ +uint32_t pages_sz; /* #pages in table */ + +uint8_t isram[0x10000]; + +uint8_t *ram; /* the virtual RAM */ +uint32_t rammask; + +uint8_t *rom; /* the virtual ROM */ +uint8_t romext[32768]; +uint32_t biosmask; + +uint32_t pccache; +uint8_t *pccache2; + +int readlnext; +int readlookup[256], + readlookupp[256]; +uintptr_t *readlookup2; +int writelnext; +int writelookup[256], + writelookupp[256]; +uintptr_t *writelookup2; + +uint32_t mem_logical_addr; + +int shadowbios = 0, + shadowbios_write; +int readlnum = 0, + writelnum = 0; +int pctrans = 0; +int cachesize = 256; + +uint32_t ram_mapped_addr[64]; + +int split_mapping_enabled = 0; + +uint32_t get_phys_virt, + get_phys_phys; + +int mem_a20_key = 0, + mem_a20_alt = 0, + mem_a20_state = 0; + +int mmuflush = 0; +int mmu_perm = 4; + + +/* FIXME: re-do this with a 'mem_ops' struct. */ +static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv); +static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv); +static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv); +static void (*_mem_write_b[0x40000])(uint32_t addr, uint8_t val, void *priv); +static void (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv); +static void (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv); +static uint8_t *_mem_exec[0x40000]; +static void *_mem_priv_r[0x40000]; +static void *_mem_priv_w[0x40000]; +static mem_mapping_t *_mem_mapping_r[0x40000]; +static mem_mapping_t *_mem_mapping_w[0x40000]; +static int _mem_state[0x40000]; + +static mem_mapping_t base_mapping; +static mem_mapping_t ram_remapped_mapping; +static mem_mapping_t ram_split_mapping; + +#if FIXME +static uint8_t ff_array[0x1000]; +#else +static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; +#endif + +static int port_92_reg = 0; + + +void +resetreadlookup(void) +{ + int c; + + /* This is NULL after app startup, when mem_init() has not yet run. */ +#if DYNAMIC_TABLES +pclog("MEM: reset_lookup: pages=%08lx, lookup=%08lx, pages_sz=%i\n", pages, page_lookup, pages_sz); +#endif + + /* Initialize the page lookup table. */ +#if DYNAMIC_TABLES + memset(page_lookup, 0x00, pages_sz*sizeof(page_t *)); +#else + memset(page_lookup, 0x00, (1<<20)*sizeof(page_t *)); +#endif + + /* Initialize the tables for lower (<= 1024K) RAM. */ + for (c = 0; c < 256; c++) { + readlookup[c] = 0xffffffff; + writelookup[c] = 0xffffffff; + } + + /* Initialize the tables for high (> 1024K) RAM. */ +#if DYNAMIC_TABLES + memset(readlookup2, 0xff, pages_sz*sizeof(uintptr_t)); + memset(writelookup2, 0xff, pages_sz*sizeof(uintptr_t)); +#else + memset(readlookup2, 0xff, (1<<20)*sizeof(uintptr_t)); + memset(writelookup2, 0xff, (1<<20)*sizeof(uintptr_t)); +#endif + + readlnext = 0; + writelnext = 0; + pccache = 0xffffffff; +} + + +void +flushmmucache(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } + mmuflush++; + + pccache = (uint32_t)0xffffffff; + pccache2 = (uint8_t *)0xffffffff; + +#ifdef USE_DYNAREC + codegen_flush(); +#endif +} + + +void +flushmmucache_nopc(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } +} + + +void +flushmmucache_cr3(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } +} + + +void +mem_flush_write_page(uint32_t addr, uint32_t virt) +{ + page_t *page_target = &pages[addr >> 12]; + int c; + + for (c = 0; c < 256; c++) { + if (writelookup[c] != 0xffffffff) { + uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; + + if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { + writelookup2[writelookup[c]] = -1; + page_lookup[writelookup[c]] = NULL; + writelookup[c] = 0xffffffff; + } + } + } +} + + +#define mmutranslate_read(addr) mmutranslatereal(addr,0) +#define mmutranslate_write(addr) mmutranslatereal(addr,1) +#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> 14]))[((x) >> 2) & 0xfff] + +uint32_t +mmutranslatereal(uint32_t addr, int rw) +{ + uint32_t temp,temp2,temp3; + uint32_t addr2; + + if (cpu_state.abrt) return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + if (! (temp&1)) { + cr2 = addr; + temp &= 1; + if (CPL == 3) temp |= 4; + if (rw) temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return -1; + } + + if ((temp & 0x80) && (cr4 & CR4_PSE)) { + /*4MB page*/ + if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3 && !cpl_override) || cr0 & WP_FLAG))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + + return -1; + } + + mmu_perm = temp & 4; + rammap(addr2) |= 0x20; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && ((CPL == 3 && !cpl_override) || cr0&WP_FLAG))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) temp |= 4; + if (rw) temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return -1; + } + + mmu_perm = temp & 4; + rammap(addr2) |= 0x20; + rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw?0x60:0x20); + + return (temp&~0xfff)+(addr&0xfff); +} + + +uint32_t +mmutranslate_noabrt(uint32_t addr, int rw) +{ + uint32_t temp,temp2,temp3; + uint32_t addr2; + + if (cpu_state.abrt) + return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + + if (! (temp & 1)) + return -1; + + if ((temp & 0x80) && (cr4 & CR4_PSE)) { + /*4MB page*/ + if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (CPL == 3 || cr0 & WP_FLAG))) + return -1; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) + return -1; + + return (temp & ~0xfff) + (addr & 0xfff); +} + + +void +mmu_invalidate(uint32_t addr) +{ + flushmmucache_cr3(); +} + + +uint8_t +mem_addr_range_match(uint32_t addr, uint32_t start, uint32_t len) +{ + if (addr < start) + return 0; + else if (addr >= (start + len)) + return 0; + else + return 1; +} + + +uint32_t +mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len) +{ + uint32_t mask = len - 1; + + return chunk_start + (addr & mask); +} + + +void +addreadlookup(uint32_t virt, uint32_t phys) +{ + if (virt == 0xffffffff) return; + + if (readlookup2[virt>>12] != -1) return; + + if (readlookup[readlnext] != 0xffffffff) + readlookup2[readlookup[readlnext]] = -1; + + readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + + readlookupp[readlnext] = mmu_perm; + readlookup[readlnext++] = virt >> 12; + readlnext &= (cachesize-1); + + cycles -= 9; +} + + +void +addwritelookup(uint32_t virt, uint32_t phys) +{ + if (virt == 0xffffffff) return; + + if (page_lookup[virt >> 12]) return; + + if (writelookup[writelnext] != -1) { + page_lookup[writelookup[writelnext]] = NULL; + writelookup2[writelookup[writelnext]] = -1; + } + +#ifdef USE_DYNAREC + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page) +#else + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3]) +#endif + page_lookup[virt >> 12] = &pages[phys >> 12]; + else + writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + + writelookupp[writelnext] = mmu_perm; + writelookup[writelnext++] = virt >> 12; + writelnext &= (cachesize - 1); + + cycles -= 9; +} + + +uint8_t * +getpccache(uint32_t a) +{ + uint32_t a2; + + a2 = a; + + if (a2 < 0x100000 && ram_mapped_addr[a2 >> 14]) { + a = (ram_mapped_addr[a2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? a2 : (ram_mapped_addr[a2 >> 14] & ~0x3FFF) + (a2 & 0x3FFF); + return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; + } + + a2 = a; + + if (cr0 >> 31) { + pctrans=1; + a = mmutranslate_read(a); + pctrans = 0; + + if (a == 0xffffffff) return ram; + } + a &= rammask; + + if (_mem_exec[a >> 14]) { + if (_mem_mapping_r[a >> 14]->flags & MEM_MAPPING_ROM) + cpu_prefetch_cycles = cpu_rom_prefetch_cycles; + else + cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + + return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xfff)]; + } + + pclog("Bad getpccache %08X\n", a); + +#if 0 + return &ff_array[0-(uintptr_t)(a2 & ~0xfff)]; +#else + return (uint8_t *)&ff_pccache; +#endif +} + + +uint8_t +readmembl(uint32_t addr) +{ + mem_logical_addr = addr; + + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); + if(addr < mem_size * 1024) return ram[addr]; + return 0xff; + } + + if (cr0 >> 31) { + addr = mmutranslate_read(addr); + if (addr == 0xffffffff) return 0xff; + } + addr &= rammask; + + if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + + +void +writemembl(uint32_t addr, uint8_t val) +{ + mem_logical_addr = addr; + + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); + if (addr < mem_size * 1024) + ram[addr] = val; + return; + } + + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + + return; + } + + if (cr0 >> 31) { + addr = mmutranslate_write(addr); + if (addr == 0xffffffff) return; + } + addr &= rammask; + + if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +uint8_t +readmemb386l(uint32_t seg, uint32_t addr) +{ + if (seg == -1) { + x86gpf("NULL segment", 0); + + return -1; + } + + mem_logical_addr = addr = addr + seg; + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); + if (addr < mem_size * 1024) + return ram[addr]; + return 0xff; + } + + if (cr0 >> 31) { + addr = mmutranslate_read(addr); + if (addr == 0xffffffff) + return 0xff; + } + + addr &= rammask; + + if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + + +void +writememb386l(uint32_t seg, uint32_t addr, uint8_t val) +{ + if (seg == -1) { + x86gpf("NULL segment", 0); + return; + } + + mem_logical_addr = addr = addr + seg; + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); + if (addr < mem_size * 1024) + ram[addr] = val; + return; + } + + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + + return; + } + + if (cr0 >> 31) { + addr = mmutranslate_write(addr); + if (addr == 0xffffffff) return; + } + + addr &= rammask; + + if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +uint16_t +readmemwl(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == -1) { + x86gpf("NULL segment", 0); + return -1; + } + + if (addr2 & 1) { + if (!cpu_cyrix_alignment || (addr2 & 7) == 7) + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xffe) { + if (cr0 >> 31) { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; + if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; + } + if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8); + else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8); + } + else if (readlookup2[addr2 >> 12] != -1) + return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + return *((uint16_t *)&ram[addr]); + return 0xffff; + } + + if (cr0 >> 31) { + addr2 = mmutranslate_read(addr2); + if (addr2 == 0xffffffff) + return 0xFFFF; + } + + addr2 &= rammask; + + if (_mem_read_w[addr2 >> 14]) + return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + + if (_mem_read_b[addr2 >> 14]) { + if (AT) + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8); + else + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14]) << 8); + } + + return 0xffff; +} + + +void +writememwl(uint32_t seg, uint32_t addr, uint16_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == -1) { + x86gpf("NULL segment", 0); + return; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + *((uint16_t *)&ram[addr]) = val; + return; + } + + if (addr2 & 1) { + if (!cpu_cyrix_alignment || (addr2 & 7) == 7) + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xffe) { + if (cr0 >> 31) { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+1) == 0xffffffff) return; + } + if (is386) { + writememb386l(seg,addr,val); + writememb386l(seg,addr+1,val>>8); + } else { + writemembl(seg+addr,val); + writemembl(seg+addr+1,val>>8); + } + return; + } else if (writelookup2[addr2 >> 12] != -1) { + *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } + + if (page_lookup[addr2>>12]) { + page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]); + return; + } + + if (cr0 >> 31) { + addr2 = mmutranslate_write(addr2); + if (addr2 == 0xffffffff) return; + } + + addr2 &= rammask; + +#if 0 + if (addr2 >= 0xa0000 && addr2 < 0xc0000) + pclog("writememwl %08X %02X\n", addr2, val); +#endif + + if (_mem_write_w[addr2 >> 14]) { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + return; + } + + if (_mem_write_b[addr2 >> 14]) { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + return; + } +} + + +uint32_t +readmemll(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == -1) { + x86gpf("NULL segment", 0); + return -1; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + return *((uint32_t *)&ram[addr]); + return 0xffffffff; + } + + if (addr2 & 3) { + if (!cpu_cyrix_alignment || (addr2 & 7) > 4) + cycles -= timing_misaligned; + if ((addr2 & 0xfff) > 0xffc) { + if (cr0 >> 31) { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; + } + return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); + } else if (readlookup2[addr2 >> 12] != -1) + return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2); + } + + if (cr0 >> 31) { + addr2 = mmutranslate_read(addr2); + if (addr2 == 0xffffffff) + return 0xffffffff; + } + + addr2 &= rammask; + + if (_mem_read_l[addr2 >> 14]) + return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + + if (_mem_read_w[addr2 >> 14]) + return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16); + + if (_mem_read_b[addr2 >> 14]) + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8) | (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16) | (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14]) << 24); + + return 0xffffffff; +} + + +void +writememll(uint32_t seg, uint32_t addr, uint32_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == -1) { + x86gpf("NULL segment", 0); + return; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + *((uint32_t *)&ram[addr]) = val; + return; + } + + if (addr2 & 3) { + if (!cpu_cyrix_alignment || (addr2 & 7) > 4) + cycles -= timing_misaligned; + if ((addr2 & 0xfff) > 0xffc) { + if (cr0 >> 31) { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+3) == 0xffffffff) return; + } + writememwl(seg,addr,val); + writememwl(seg,addr+2,val>>16); + return; + } else if (writelookup2[addr2 >> 12] != -1) { + *(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } + + if (page_lookup[addr2>>12]) { + page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); + return; + } + + if (cr0 >> 31) { + addr2 = mmutranslate_write(addr2); + if (addr2 == 0xffffffff) return; + } + + addr2 &= rammask; + + if (_mem_write_l[addr2 >> 14]) { + _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_w[addr2 >> 14]) { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_b[addr2 >> 14]) { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + return; + } +} + + +uint64_t +readmemql(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == -1) { + x86gpf("NULL segment", 0); + return -1; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + return *((uint64_t *)&ram[addr]); + return -1; + } + + if (addr2 & 7) { + cycles -= timing_misaligned; + if ((addr2 & 0xfff) > 0xff8) { + if (cr0 >> 31) { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff; + } + return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); + } else if (readlookup2[addr2 >> 12] != -1) + return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2); + } + + if (cr0 >> 31) { + addr2 = mmutranslate_read(addr2); + if (addr2 == 0xffffffff) + return -1; + } + + addr2 &= rammask; + + if (_mem_read_l[addr2 >> 14]) + return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32); + + return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); +} + + +void +writememql(uint32_t seg, uint32_t addr, uint64_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == -1) { + x86gpf("NULL segment", 0); + return; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + *((uint64_t *)&ram[addr]) = val; + return; + } + + if (addr2 & 7) { + cycles -= timing_misaligned; + if ((addr2 & 0xfff) > 0xff8) { + if (cr0 >> 31) { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+7) == 0xffffffff) return; + } + writememll(seg, addr, val); + writememll(seg, addr+4, val >> 32); + return; + } else if (writelookup2[addr2 >> 12] != -1) { + *(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } + + if (page_lookup[addr2>>12]) { + page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); + page_lookup[addr2>>12]->write_l(addr2 + 4, val >> 32, page_lookup[addr2>>12]); + return; + } + + if (cr0 >> 31) { + addr2 = mmutranslate_write(addr2); + if (addr2 == 0xffffffff) return; + } + + addr2 &= rammask; + + if (_mem_write_l[addr2 >> 14]) { + _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_l[addr2 >> 14](addr2+4, val >> 32, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_w[addr2 >> 14]) { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_b[addr2 >> 14]) { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 5, val >> 40, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 7, val >> 56, _mem_priv_w[addr2 >> 14]); + return; + } +} + + +uint8_t +mem_readb_phys(uint32_t addr) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + + +/* + * Version of mem_readby_phys that doesn't go through + * the CPU paging mechanism. + */ +uint8_t +mem_readb_phys_dma(uint32_t addr) +{ +#if 0 + mem_logical_addr = 0xffffffff; +#endif + + if (_mem_exec[addr >> 14]) + return _mem_exec[addr >> 14][addr & 0x3fff]; + else if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + else + return 0xff; +} + + +uint16_t +mem_readw_phys(uint32_t addr) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_read_w[addr >> 14]) + return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + + +void +mem_writeb_phys(uint32_t addr, uint8_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +/* + * Version of mem_readby_phys that doesn't go through + * the CPU paging mechanism. + */ +void +mem_writeb_phys_dma(uint32_t addr, uint8_t val) +{ +#if 0 + mem_logical_addr = 0xffffffff; +#endif + + if (_mem_exec[addr >> 14]) + _mem_exec[addr >> 14][addr & 0x3fff] = val; + else if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +void +mem_writew_phys(uint32_t addr, uint16_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_w[addr >> 14]) + _mem_write_w[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +uint8_t +mem_read_ram(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return ram[addr]; +} + + +uint16_t +mem_read_ramw(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return *(uint16_t *)&ram[addr]; +} + + +uint32_t +mem_read_raml(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return *(uint32_t *)&ram[addr]; +} + + +void +mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) +{ +#ifdef USE_DYNAREC + if (val != p->mem[addr & 0xfff] || codegen_in_recompile) { +#else + if (val != p->mem[addr & 0xfff]) { +#endif + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + p->mem[addr & 0xfff] = val; + } +} + + +void +mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) +{ +#ifdef USE_DYNAREC + if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { +#else + if (val != *(uint16_t *)&p->mem[addr & 0xfff]) { +#endif + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0xf) == 0xf) + mask |= (mask << 1); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + *(uint16_t *)&p->mem[addr & 0xfff] = val; + } +} + + +void +mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) +{ +#ifdef USE_DYNAREC + if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { +#else + if (val != *(uint32_t *)&p->mem[addr & 0xfff]) { +#endif + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0xf) >= 0xd) + mask |= (mask << 1); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + *(uint32_t *)&p->mem[addr & 0xfff] = val; + } +} + + +void +mem_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} + + +void +mem_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} + + +void +mem_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + + +uint8_t +mem_read_bios(uint32_t addr, void *priv) +{ + return rom[addr & biosmask]; +} + + +uint16_t +mem_read_biosw(uint32_t addr, void *priv) +{ + return *(uint16_t *)&rom[addr & biosmask]; +} + + +uint32_t +mem_read_biosl(uint32_t addr, void *priv) +{ + return *(uint32_t *)&rom[addr & biosmask]; +} + + +uint8_t +mem_read_romext(uint32_t addr, void *priv) +{ + return romext[addr & 0x7fff]; +} + + +uint16_t +mem_read_romextw(uint32_t addr, void *priv) +{ + uint16_t *p = (uint16_t *)&romext[addr & 0x7fff]; + + return *p; +} + + +uint32_t +mem_read_romextl(uint32_t addr, void *priv) +{ + uint32_t *p = (uint32_t *)&romext[addr & 0x7fff]; + + return *p; +} + + +void +mem_write_null(uint32_t addr, uint8_t val, void *p) +{ +} + + +void +mem_write_nullw(uint32_t addr, uint16_t val, void *p) +{ +} + + +void +mem_write_nulll(uint32_t addr, uint32_t val, void *p) +{ +} + + +void +mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) +{ + start_addr &= ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + + for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { + uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + pages[start_addr >> 12].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + } +} + + +static __inline int +mem_mapping_read_allowed(uint32_t flags, int state) +{ + switch (state & MEM_READ_MASK) { + case MEM_READ_ANY: + return 1; + + case MEM_READ_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + + case MEM_READ_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + + default: + fatal("mem_mapping_read_allowed : bad state %x\n", state); + } + + return 0; +} + + +static __inline int +mem_mapping_write_allowed(uint32_t flags, int state) +{ + switch (state & MEM_WRITE_MASK) { + case MEM_WRITE_DISABLED: + return 0; + case MEM_WRITE_ANY: + return 1; + case MEM_WRITE_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + case MEM_WRITE_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + default: + fatal("mem_mapping_write_allowed : bad state %x\n", state); + } + + return 0; +} + + +static void +mem_mapping_recalc(uint64_t base, uint64_t size) +{ + mem_mapping_t *mapping = base_mapping.next; + uint64_t c; + + if (! size) return; + + /* Clear out old mappings. */ + for (c = base; c < base + size; c += 0x4000) { + _mem_read_b[c >> 14] = NULL; + _mem_read_w[c >> 14] = NULL; + _mem_read_l[c >> 14] = NULL; + _mem_priv_r[c >> 14] = NULL; + _mem_mapping_r[c >> 14] = NULL; + _mem_write_b[c >> 14] = NULL; + _mem_write_w[c >> 14] = NULL; + _mem_write_l[c >> 14] = NULL; + _mem_priv_w[c >> 14] = NULL; + _mem_mapping_w[c >> 14] = NULL; + } + + /* Walk mapping list. */ + while (mapping != NULL) { + /*In range?*/ + if (mapping->enable && (uint64_t)mapping->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)mapping->base + (uint64_t)mapping->size) > (uint64_t)base) { + uint64_t start = (mapping->base < base) ? mapping->base : base; + uint64_t end = (((uint64_t)mapping->base + (uint64_t)mapping->size) < (base + size)) ? ((uint64_t)mapping->base + (uint64_t)mapping->size) : (base + size); + if (start < mapping->base) + start = mapping->base; + + for (c = start; c < end; c += 0x4000) { + if ((mapping->read_b || mapping->read_w || mapping->read_l) && + mem_mapping_read_allowed(mapping->flags, _mem_state[c >> 14])) { + _mem_read_b[c >> 14] = mapping->read_b; + _mem_read_w[c >> 14] = mapping->read_w; + _mem_read_l[c >> 14] = mapping->read_l; + if (mapping->exec) + _mem_exec[c >> 14] = mapping->exec + (c - mapping->base); + else + _mem_exec[c >> 14] = NULL; + _mem_priv_r[c >> 14] = mapping->p; + _mem_mapping_r[c >> 14] = mapping; + } + if ((mapping->write_b || mapping->write_w || mapping->write_l) && + mem_mapping_write_allowed(mapping->flags, _mem_state[c >> 14])) { + _mem_write_b[c >> 14] = mapping->write_b; + _mem_write_w[c >> 14] = mapping->write_w; + _mem_write_l[c >> 14] = mapping->write_l; + _mem_priv_w[c >> 14] = mapping->p; + _mem_mapping_w[c >> 14] = mapping; + } + } + } + mapping = mapping->next; + } + + flushmmucache_cr3(); +} + + +void +mem_mapping_add(mem_mapping_t *mapping, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t flags, + void *p) +{ + mem_mapping_t *dest = &base_mapping; + + /* Add mapping to the end of the list.*/ + while (dest->next) + dest = dest->next; + dest->next = mapping; + mapping->prev = dest; + + if (size) + mapping->enable = 1; + else + mapping->enable = 0; + mapping->base = base; + mapping->size = size; + mapping->read_b = read_b; + mapping->read_w = read_w; + mapping->read_l = read_l; + mapping->write_b = write_b; + mapping->write_w = write_w; + mapping->write_l = write_l; + mapping->exec = exec; + mapping->flags = flags; + mapping->p = p; + mapping->next = NULL; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_set_handler(mem_mapping_t *mapping, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)) +{ + mapping->read_b = read_b; + mapping->read_w = read_w; + mapping->read_l = read_l; + mapping->write_b = write_b; + mapping->write_w = write_w; + mapping->write_l = write_l; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_set_addr(mem_mapping_t *mapping, uint32_t base, uint32_t size) +{ + /* Remove old mapping. */ + mapping->enable = 0; + mem_mapping_recalc(mapping->base, mapping->size); + + /* Set new mapping. */ + mapping->enable = 1; + mapping->base = base; + mapping->size = size; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec) +{ + mapping->exec = exec; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_set_p(mem_mapping_t *mapping, void *p) +{ + mapping->p = p; +} + + +void +mem_mapping_disable(mem_mapping_t *mapping) +{ + mapping->enable = 0; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_enable(mem_mapping_t *mapping) +{ + mapping->enable = 1; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_set_mem_state(uint32_t base, uint32_t size, int state) +{ + uint32_t c; + + for (c = 0; c < size; c += 0x4000) + _mem_state[(c + base) >> 14] = state; + + mem_mapping_recalc(base, size); +} + + +void +mem_add_bios(void) +{ + if (AT || (romset == ROM_XI8088 && xi8088_bios_128kb())) { + mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom,MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x4000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x8000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0xc000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + } + + mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x10000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x14000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x18000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x1c000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + + mem_mapping_add(&bios_high_mapping[0], + (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[1], + (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x4000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[2], + (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x8000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[3], + (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0xc000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[4], + (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x10000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[5], + (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x14000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[6], + (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x18000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[7], + (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x1c000 & biosmask), MEM_MAPPING_ROM, 0); +} + + +void +mem_a20_init(void) +{ + if (AT) { + rammask = cpu_16bitbus ? 0xefffff : 0xffefffff; + flushmmucache(); + mem_a20_state = mem_a20_key | mem_a20_alt; + } else { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + } +} + + +/* Reset the memory state. */ +void +mem_reset(void) +{ + uint32_t c, m; + + split_mapping_enabled = 0; + + /* Free the ROM memory and reset size mask. */ + if (rom != NULL) { + free(rom); + rom = NULL; + } + biosmask = 0xffff; + + /* + * Always allocate the full 16 MB memory space if memory size + * is smaller, we'll need this for stupid things like the PS/2 + * split mapping. + */ + if (mem_size < 16384) + m = 1024UL * 16384; + else + m = 1024UL * (mem_size + 384); /* 386 extra kB for top remapping */ + if (ram != NULL) free(ram); + ram = (uint8_t *)malloc(m); /* allocate and clear the RAM block */ + memset(ram, 0x00, m); + + /* + * Allocate the page table based on how much RAM we have. + * We re-allocate the table on each (hard) reset, as the + * memory amount could have changed. + */ + if (AT) { + if (cpu_16bitbus) { + /* 80186/286; maximum address space is 16MB. */ + m = 4096; + } else { + /* 80386+; maximum address space is 4GB. */ + m = (mem_size + 384) >> 2; + if ((m << 2) < (mem_size + 384)) + m++; + if (m < 4096) + m = 4096; + } + } else { + /* 8088/86; maximum address space is 1MB. */ + m = 256; + } + + /* + * Allocate and initialize the (new) page table. + * We only do this if the size of the page table has changed. + */ +#if DYNAMIC_TABLES +pclog("MEM: reset: previous pages=%08lx, pages_sz=%i\n", pages, pages_sz); +#endif + if (pages_sz != m) { + pages_sz = m; + free(pages); + pages = (page_t *)malloc(m*sizeof(page_t)); + memset(pages, 0x00, m*sizeof(page_t)); +#if DYNAMIC_TABLES +pclog("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); +#endif + +#if DYNAMIC_TABLES + /* Allocate the (new) lookup tables. */ + if (page_lookup != NULL) free(page_lookup); + page_lookup = (page_t **)malloc(pages_sz*sizeof(page_t *)); + + if (readlookup2 != NULL) free(readlookup2); + readlookup2 = malloc(pages_sz*sizeof(uintptr_t)); + + if (writelookup2 != NULL) free(writelookup2); + writelookup2 = malloc(pages_sz*sizeof(uintptr_t)); +#endif + } + + /* Initialize the page table. */ + for (c = 0; c < m; c++) { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + /* Initialize the tables. */ + resetreadlookup(); + + memset(isram, 0x00, sizeof(isram)); + for (c = 0; c < (mem_size / 64); c++) { + isram[c] = 1; + if ((c >= 0xa && c <= 0xf) || + (cpu_16bitbus && c >= 0xfe && c <= 0xff)) + isram[c] = 0; + } + + memset(_mem_read_b, 0x00, sizeof(_mem_read_b)); + memset(_mem_read_w, 0x00, sizeof(_mem_read_w)); + memset(_mem_read_l, 0x00, sizeof(_mem_read_l)); + memset(_mem_write_b, 0x00, sizeof(_mem_write_b)); + memset(_mem_write_w, 0x00, sizeof(_mem_write_w)); + memset(_mem_write_l, 0x00, sizeof(_mem_write_l)); + memset(_mem_exec, 0x00, sizeof(_mem_exec)); + + memset(&base_mapping, 0x00, sizeof(base_mapping)); + + memset(_mem_state, 0x00, sizeof(_mem_state)); + + mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0x0c0000, 0x40000, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + mem_mapping_add(&ram_low_mapping, 0x00000, + (mem_size > 640) ? 0xa0000 : mem_size * 1024, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram, MEM_MAPPING_INTERNAL, NULL); + + if (mem_size > 1024) { + if (cpu_16bitbus && mem_size > 16256) { + mem_set_mem_state(0x100000, (16256 - 1024) * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_high_mapping, 0x100000, + ((16256 - 1024) * 1024), + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + } else { + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_high_mapping, 0x100000, + ((mem_size - 1024) * 1024), + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + } + } + + if (mem_size > 768) + mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); + + if (romset == ROM_IBMPS1_2011) + mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, + mem_read_romext,mem_read_romextw,mem_read_romextl, + NULL,NULL, NULL, romext, 0, NULL); + + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 384 * 1024, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + (1 << 20), MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&ram_remapped_mapping); + + mem_mapping_add(&ram_split_mapping, mem_size * 1024, 384 * 1024, + mem_read_ram, mem_read_ramw, mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + (1 << 20), MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&ram_split_mapping); + + mem_a20_init(); +} + + +void +mem_init(void) +{ + /* Perform a one-time init. */ + ram = rom = NULL; + pages = NULL; +#if DYNAMIC_TABLES + page_lookup = NULL; + readlookup2 = NULL; + writelookup2 = NULL; + +#else + /* Allocate the lookup tables. */ + page_lookup = (page_t **)malloc((1<<20)*sizeof(page_t *)); + + readlookup2 = malloc((1<<20)*sizeof(uintptr_t)); + + writelookup2 = malloc((1<<20)*sizeof(uintptr_t)); +#endif + + memset(ram_mapped_addr, 0x00, 64 * sizeof(uint32_t)); + +#if FIXME + memset(ff_array, 0xff, sizeof(ff_array)); +#endif + + /* Reset the memory state. */ + mem_reset(); +} + + +static void +mem_remap_top(int max_size) +{ + int c; + + if (mem_size > 640) { + uint32_t start = (mem_size >= 1024) ? mem_size : 1024; + int size = mem_size - 640; + if (size > max_size) + size = max_size; + + for (c = (start / 64); c < ((start + size - 1) / 64); c++) + isram[c] = 1; + + mem_set_mem_state(start * 1024, size * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_set_addr(&ram_remapped_mapping, + start * 1024, size * 1024); + mem_mapping_set_exec(&ram_split_mapping, ram + (start * 1024)); + + flushmmucache(); + } +} + + +void +mem_remap_top_256k(void) +{ + mem_remap_top(256); +} + + +void +mem_remap_top_384k(void) +{ + mem_remap_top(384); +} + + +void +mem_reset_page_blocks(void) +{ + int c; + + if (pages == NULL) return; + + for (c = 0; c < ((mem_size * 1024) >> 12); c++) { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + pages[c].block[0] = pages[c].block[1] = pages[c].block[2] = pages[c].block[3] = NULL; + pages[c].block_2[0] = pages[c].block_2[1] = pages[c].block_2[2] = pages[c].block_2[3] = NULL; + } +} + + +void +mem_a20_recalc(void) +{ + int state; + + if (! AT) { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + + return; + } + + state = mem_a20_key | mem_a20_alt; + if (state && !mem_a20_state) { + rammask = (AT && cpu_16bitbus) ? 0xffffff : 0xffffffff; + flushmmucache(); + } else if (!state && mem_a20_state) { + rammask = (AT && cpu_16bitbus) ? 0xefffff : 0xffefffff; + flushmmucache(); + } + + mem_a20_state = state; +} + + +uint8_t +port_92_read(uint16_t port, void *priv) +{ + return port_92_reg; +} + + +void +port_92_write(uint16_t port, uint8_t val, void *priv) +{ + if ((mem_a20_alt ^ val) & 2) { + mem_a20_alt = (val & 2); + mem_a20_recalc(); + } + + if ((~port_92_reg & val) & 1) { + softresetx86(); + cpu_set_edx(); + } + + port_92_reg = val; +} + + +void +port_92_clear_reset(void) +{ + port_92_reg &= 2; +} + + +void +port_92_add(void) +{ + io_sethandler(0x0092, 1, + port_92_read,NULL,NULL, port_92_write, NULL,NULL,NULL); +} + + +void +port_92_remove(void) +{ + io_removehandler(0x0092, 1, + port_92_read,NULL,NULL, port_92_write,NULL,NULL, NULL); +} + + +void +port_92_reset(void) +{ + port_92_reg = 0; + mem_a20_alt = 0; + mem_a20_recalc(); + + flushmmucache(); +} diff --git a/src/nvr.c b/src/nvr.c index d092cb6..148f699 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -10,7 +10,7 @@ * * NOTE: I should re-do 'intclk' using a TM struct. * - * Version: @(#)nvr.c 1.0.2 2018/03/11 + * Version: @(#)nvr.c 1.0.3 2018/03/20 * * Author: Fred N. van Kempen, * @@ -249,7 +249,7 @@ nvr_save(void) FILE *f; /* Make sure we have been initialized. */ - if (saved_nvr == NULL) return(0); + if (config_ro || saved_nvr == NULL) return(0); if (saved_nvr->size != 0) { pclog("NVR: saving to '%ls'\n", nvr_path(saved_nvr->fn)); diff --git a/src/pc.c b/src/pc.c index 0a8d9a7..9755fb0 100644 --- a/src/pc.c +++ b/src/pc.c @@ -8,7 +8,7 @@ * * Main emulator module where most things are controlled. * - * Version: @(#)pc.c 1.0.13 2018/03/19 + * Version: @(#)pc.c 1.0.14 2018/03/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -109,6 +109,7 @@ uint64_t source_hwnd = 0; /* (O) -H hwnd */ int video_fps = RENDER_FPS; /* (O) render speed in fps */ #endif int settings_only = 0; /* (O) only the settings dlg */ +int config_ro = 0; /* (O) dont modify cfg file */ wchar_t log_path[1024] = { L'\0'}; /* (O) full path of logfile */ /* Configuration values. */ @@ -175,8 +176,9 @@ int atfullspeed; int cpuspeed2; int clockrate; -char emu_title[128]; /* full name of application */ -char emu_version[128]; /* version ID string */ +char emu_title[64]; /* full name of application */ +char emu_version[32]; /* short version ID string */ +char emu_fullversion[128]; /* full version ID string */ wchar_t emu_path[1024]; /* emu installation path */ wchar_t usr_path[1024]; /* path (dir) of user data */ wchar_t cfg_path[1024]; /* full path of config file */ @@ -301,23 +303,24 @@ pc_version(const char *platform) sprintf(emu_title, "%s for %s", EMU_NAME, platform); - sprintf(emu_version, "%s", EMU_VERSION); + sprintf(emu_version, "v%s", EMU_VERSION); + strcpy(emu_fullversion, emu_version); #ifdef BUILD sprintf(temp, " (Build %d", BUILD); - strcat(emu_version, temp); + strcat(emu_fullversion, temp); #endif #ifdef COMMIT sprintf(temp, " [Commit #%x]", COMMIT); - strcat(emu_version, temp); + strcat(emu_fullversion, temp); #endif #ifdef BUILD - strcat(emu_version, ")"); + strcat(emu_fullversion, ")"); #endif #ifdef UPSTREAM sprintf(temp, " [Upstream #%x]", UPSTREAM); - strcat(emu_version, temp); + strcat(emu_fullversion, temp); #endif } @@ -384,7 +387,7 @@ pc_init(int argc, wchar_t *argv[]) if (!wcscasecmp(argv[c], L"--help") || !wcscasecmp(argv[c], L"-?")) { usage: - printf("\n%s version %s\n", emu_title, emu_version); + printf("\n%s %s\n", emu_title, emu_fullversion); printf("\nUsage: varcem [options] [cfg-file]\n\n"); printf("Valid options are:\n\n"); printf(" -? or --help - show this information\n"); @@ -403,6 +406,7 @@ usage: #ifdef _WIN32 printf(" -H or --hwnd id,hwnd - sends back the main dialog's hwnd\n"); #endif + printf(" -W or --readonly - do not modify the config file\n"); printf("\nA config file can be specified. If none is, the default file will be used.\n"); return(0); } else if (!wcscasecmp(argv[c], L"--dumpcfg") || @@ -447,6 +451,9 @@ usage: wcstombs(temp, argv[++c], sizeof(temp)); sscanf(temp, "%016" PRIX64 ",%016" PRIX64, &unique_id, &source_hwnd); #endif + } else if (!wcscasecmp(argv[c], L"--readonly") || + !wcscasecmp(argv[c], L"-W")) { + config_ro = 1; } else if (!wcscasecmp(argv[c], L"--test")) { /* some (undocumented) test function here.. */ @@ -537,8 +544,8 @@ usage: (void)time(&now); info = localtime(&now); strftime(temp, sizeof(temp), "%Y/%m/%d %H:%M:%S", info); - pclog("#\n# %s v%s\n#\n# Logfile created %s\n#\n", - emu_title, emu_version, temp); + pclog("#\n# %s %s\n#\n# Logfile created %s\n#\n", + emu_title, emu_fullversion, temp); pclog("# Emulator path: %ls\n", emu_path); pclog("# Userfiles path: %ls\n", usr_path); pclog("# Configuration file: %ls\n#\n\n", cfg_path); @@ -1076,14 +1083,20 @@ pc_thread(void *param) if (title_update) { swprintf(temp, sizeof_w(temp), #ifdef _WIN32 - L"%S v%S - %i%% - %S - %S - %s", + L"%S %S - %i%% - %S - %S", #else - L"%s v%s - %i%% - %s - %s - %s", + L"%s %s - %i%% - %s - %s", #endif EMU_NAME,emu_version,fps,machine_getname(), - machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name, - (!mouse_capture) ? plat_get_string(IDS_2077) - : (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); + machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name); + if (mouse_type != MOUSE_TYPE_NONE) { + wcscat(temp, L" - "); + if (!mouse_capture) { + wcscat(temp, plat_get_string(IDS_2077)); + } else { + wcscat(temp, (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); + } + } ui_window_title(temp); diff --git a/src/rom.h b/src/rom.h index c682e12..3e46561 100644 --- a/src/rom.h +++ b/src/rom.h @@ -8,7 +8,7 @@ * * Definitions for the ROM image handler. * - * Version: @(#)rom.h 1.0.6 2018/03/09 + * Version: @(#)rom.h 1.0.7 2018/03/21 * * Authors: Fred N. van Kempen, * @@ -58,10 +58,14 @@ typedef struct { } rom_t; typedef struct { - int mode; - int nfiles; + int8_t mode; + int8_t fontnum; + int16_t nfiles; + uint32_t vidsz; uint32_t offset; uint32_t total; + wchar_t fontfn[1024]; + wchar_t vidfn[1024]; struct romfile { wchar_t path[1024]; int mode; @@ -91,7 +95,7 @@ extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, int size, int mask, int file_offset, uint32_t flags); -extern int rom_load_bios(wchar_t *fn, int test_only); +extern int rom_load_bios(romdef_t *r, wchar_t *fn, int test_only); #endif /*EMU_ROM_H*/ diff --git a/src/rom_load.c b/src/rom_load.c index f874d33..15f5243 100644 --- a/src/rom_load.c +++ b/src/rom_load.c @@ -17,7 +17,7 @@ * or to use a generic handler, and then pass it a pointer * to a command table. For now, we don't. * - * Version: @(#)rom_load.c 1.0.3 2018/03/07 + * Version: @(#)rom_load.c 1.0.5 2018/03/21 * * Author: Fred N. van Kempen, * @@ -100,6 +100,12 @@ process(int ln, int argc, char **argv, romdef_t *r) } else r->files[r->nfiles].offset = r->offset; r->nfiles++; + } else if (! strcmp(argv[0], "font")) { + r->fontnum = atoi(argv[1]); + mbstowcs(r->fontfn, argv[2], sizeof_w(r->fontfn)); + } else if (! strcmp(argv[0], "video")) { + mbstowcs(r->vidfn, argv[1], sizeof_w(r->vidfn)); + sscanf(argv[2], "%i", &r->vidsz); } else { pclog("ROM: invalid command '%s' on line %d.\n", argv[0], ln); return(0); @@ -305,11 +311,10 @@ parser(FILE *fp, romdef_t *r) /* Load a BIOS ROM image into memory. */ int -rom_load_bios(wchar_t *fn, int test_only) +rom_load_bios(romdef_t *r, wchar_t *fn, int test_only) { wchar_t path[1024], script[1024]; wchar_t temp[1024]; - romdef_t r; FILE *fp; int c, i; @@ -342,60 +347,80 @@ rom_load_bios(wchar_t *fn, int test_only) } /* Clear ROM definition. */ - memset(&r, 0x00, sizeof(r)); + memset(r, 0x00, sizeof(romdef_t)); + r->fontnum = -1; /* Parse and process the file. */ - i = parser(fp, &r); + i = parser(fp, r); (void)fclose(fp); /* Show the resulting data. */ if (! test_only) { - pclog("Size : %lu\n", r.total); - pclog("Offset : 0x%06lx (%lu)\n", r.offset, r.offset); - pclog("Mode : %s\n", (r.mode == 1)?"interleaved":"linear"); - pclog("Files : %d\n", r.nfiles); - for (c=0; ctotal); + pclog("Offset : 0x%06lx (%lu)\n", r->offset, r->offset); + pclog("Mode : %s\n", (r->mode == 1)?"interleaved":"linear"); + pclog("Files : %d\n", r->nfiles); + for (c=0; cnfiles; c++) { pclog(" [%d] : '%ls', %d, 0x%06lx\n", c+1, - r.files[c].path, r.files[c].skip, r.files[c].offset); + r->files[c].path, r->files[c].skip, r->files[c].offset); } + if (r->fontnum != -1) + pclog("Font : %i, '%ls'\n", r->fontnum, r->fontfn); + if (r->vidsz != 0) + pclog("VideoBIOS: '%ls', %i\n", r->vidfn, r->vidsz); /* Actually perform the work. */ - switch(r.mode) { + switch(r->mode) { case 0: /* linear file(s) */ /* We loop on all files. */ - for (c=0; cnfiles; c++) { wcscpy(script, path); - wcscat(script, r.files[c].path); + wcscat(script, r->files[c].path); i = rom_load_linear(script, - r.files[c].offset, - r.total, - r.files[c].skip, rom); + r->files[c].offset, + r->total, + r->files[c].skip, rom); if (i != 0) break; } - if (r.total >= 0x010000) - biosmask = (r.total - 1); + if (r->total >= 0x010000) + biosmask = (r->total - 1); break; case 1: /* interleaved file(s) */ /* We loop on all files. */ - for (c=0; cnfiles/2; c+=2) { wcscpy(script, path); - wcscat(script, r.files[c].path); + wcscat(script, r->files[c].path); wcscpy(temp, path); - wcscat(temp, r.files[c+1].path); + wcscat(temp, r->files[c+1].path); i = rom_load_interleaved(script, temp, - r.files[c].offset, - r.total, - r.files[c].skip, rom); + r->files[c].offset, + r->total, + r->files[c].skip, rom); if (i != 0) break; } - if (r.total >= 0x010000) - biosmask = (r.total - 1); + if (r->total >= 0x010000) + biosmask = (r->total - 1); break; } - pclog("ROM: status %d, tot %u, mask 0x%06lx\n", i, r.total, biosmask); + /* Create a full pathname for the video font file. */ + if (r->fontnum != -1) { + wcscpy(temp, path); + wcscat(temp, r->fontfn); + wcscpy(r->fontfn, temp); + } + + /* Create a full pathname for the video BIOS file. */ + if (r->vidsz != 0) { + wcscpy(temp, path); + wcscat(temp, r->vidfn); + wcscpy(r->vidfn, temp); + } + + pclog("ROM: status %d, tot %u, mask 0x%06lx\n", + i, r->total, biosmask); } return(i); diff --git a/src/scsi/scsi.h b/src/scsi/scsi.h index 5434262..a5a2aa2 100644 --- a/src/scsi/scsi.h +++ b/src/scsi/scsi.h @@ -8,7 +8,7 @@ * * SCSI controller handler header. * - * Version: @(#)scsi.h 1.0.3 2018/03/19 + * Version: @(#)scsi.h 1.0.4 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -67,6 +67,7 @@ #define GPCMD_START_STOP_UNIT 0x1b #define GPCMD_SEND_DIAGNOSTIC 0x1d #define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 #define GPCMD_READ_CDROM_CAPACITY 0x25 #define GPCMD_READ_10 0x28 #define GPCMD_WRITE_10 0x2a diff --git a/src/version.h b/src/version.h index 78cfd36..0dce06a 100644 --- a/src/version.h +++ b/src/version.h @@ -8,7 +8,7 @@ * * Define application version and build info. * - * Version: @(#)version.h 1.0.1 2018/03/07 + * Version: @(#)version.h 1.0.2 2018/03/20 * * Author: Fred N. van Kempen, * @@ -54,7 +54,7 @@ /* Version info. */ #define EMU_VER_MAJOR 0 #define EMU_VER_MINOR 1 -#define EMU_VER_REV 2 +#define EMU_VER_REV 3 /* Standard C preprocessor macros. */ @@ -69,9 +69,4 @@ #define EMU_VERSION_4 STR(EMU_VER_NUM_4) -/* Global variables. */ - - - - #endif /*EMU_VERSION_H*/ diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 86d0776..b84c743 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,7 +9,7 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, 5430, 5434 and 5436 are supported). * - * Version: @(#)vid_cl54xx.c 1.0.10 2018/03/20 + * Version: @(#)vid_cl54xx.c 1.0.11 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -2019,13 +2019,13 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; break; case CIRRUS_BLTMODE_PIXELWIDTH16: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 24)]; + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 31)]; break; case CIRRUS_BLTMODE_PIXELWIDTH32: - src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~3)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; break; } mask = 1; diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index 3d5b96f..d9d051f 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -10,7 +10,7 @@ * * NOTE: ROM images need more/better organization per chipset. * - * Version: @(#)vid_s3.c 1.0.5 2018/03/15 + * Version: @(#)vid_s3.c 1.0.6 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -182,6 +182,9 @@ typedef struct s3_t uint64_t status_time; uint8_t subsys_cntl, subsys_stat; + + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; } s3_t; #define INT_VSY (1 << 0) @@ -838,15 +841,16 @@ void s3_out(uint16_t addr, uint8_t val, void *p) break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - if (s3->chip == S3_VISION864) - { - sdac_ramdac_out(addr, val, &s3->ramdac, svga); - return; - } - else - { - break; - } + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + svga_out(addr, val, svga); + else + { + if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2)) + sdac_ramdac_out((addr & 3) | 4, val, &s3->ramdac, svga); + else + sdac_ramdac_out(addr & 3, val, &s3->ramdac, svga); + } + return; case 0x3D4: svga->crtcreg = val & 0x7f; @@ -926,6 +930,37 @@ void s3_out(uint16_t addr, uint8_t val, void *p) svga->hwcursor.x <<= 1; break; + case 0x4a: + switch (s3->hwc_col_stack_pos) + { + case 0: + s3->hwc_fg_col = (s3->hwc_fg_col & 0xffff00) | val; + break; + case 1: + s3->hwc_fg_col = (s3->hwc_fg_col & 0xff00ff) | (val << 8); + break; + case 2: + s3->hwc_fg_col = (s3->hwc_fg_col & 0x00ffff) | (val << 16); + break; + } + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + break; + case 0x4b: + switch (s3->hwc_col_stack_pos) + { + case 0: + s3->hwc_bg_col = (s3->hwc_bg_col & 0xffff00) | val; + break; + case 1: + s3->hwc_bg_col = (s3->hwc_bg_col & 0xff00ff) | (val << 8); + break; + case 2: + s3->hwc_bg_col = (s3->hwc_bg_col & 0x00ffff) | (val << 16); + break; + } + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + break; + case 0x53: case 0x58: case 0x59: case 0x5a: s3_updatemapping(s3); @@ -979,14 +1014,11 @@ uint8_t s3_in(uint16_t addr, void *p) break; case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: - if (s3->chip == S3_VISION864) - { - return sdac_ramdac_in(addr, &s3->ramdac, svga); - } - else - { - break; - } + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + return svga_in(addr, svga); + if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2)) + return sdac_ramdac_in((addr & 3) | 4, &s3->ramdac, svga); + return sdac_ramdac_in(addr & 3, &s3->ramdac, svga); case 0x3d4: return svga->crtcreg; @@ -999,6 +1031,7 @@ uint8_t s3_in(uint16_t addr, void *p) case 0x30: return s3->id; /*Chip ID*/ case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); + case 0x45: s3->hwc_col_stack_pos = 0; break; case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); case 0x69: return s3->ma_ext; case 0x6a: return s3->bank; @@ -2000,6 +2033,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat void s3_hwcursor_draw(svga_t *svga, int displine) { + s3_t *s3 = (s3_t *)svga->p; int x; uint16_t dat[2]; int xx; @@ -2007,6 +2041,39 @@ void s3_hwcursor_draw(svga_t *svga, int displine) int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + uint32_t fg = 0, bg = 0; + + switch (svga->bpp) + { + case 15: + fg = video_15to32[s3->hwc_fg_col & 0xffff]; + bg = video_15to32[s3->hwc_bg_col & 0xffff]; + break; + + case 16: + fg = video_16to32[s3->hwc_fg_col & 0xffff]; + bg = video_16to32[s3->hwc_bg_col & 0xffff]; + break; + + case 24: case 32: + fg = s3->hwc_fg_col; + bg = s3->hwc_bg_col; + break; + + default: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + fg = svga->pallook[s3->hwc_fg_col & 0xff]; + bg = svga->pallook[s3->hwc_bg_col & 0xff]; + } + else + { + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; + } + break; + } + if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += 16; @@ -2019,7 +2086,7 @@ void s3_hwcursor_draw(svga_t *svga, int displine) if (offset >= svga->hwcursor_latch.x) { if (!(dat[0] & 0x8000)) - ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? 0xffffff : 0; + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; else if (dat[1] & 0x8000) ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; } @@ -2291,6 +2358,7 @@ void *s3_vision864_init(const device_t *info, wchar_t *bios_fn) s3->getclock = sdac_getclock; s3->getclock_p = &s3->ramdac; + sdac_init(&s3->ramdac); return s3; } diff --git a/src/video/vid_sdac_ramdac.c b/src/video/vid_sdac_ramdac.c index 246f5fe..8d6efad 100644 --- a/src/video/vid_sdac_ramdac.c +++ b/src/video/vid_sdac_ramdac.c @@ -10,7 +10,7 @@ * * Misidentifies as AT&T 21C504. * - * Version: @(#)vid_sdac_ramdac.c 1.0.2 2018/03/08 + * Version: @(#)vid_sdac_ramdac.c 1.0.3 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -49,71 +49,91 @@ #include "vid_sdac_ramdac.h" -/* Returning divider * 2 */ -int sdac_get_clock_divider(sdac_ramdac_t *ramdac) +static void sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val) { - switch (ramdac->command >> 4) + ramdac->command = val; + switch (val >> 4) { - case 0x1: return 1; - case 0x0: case 0x3: case 0x5: return 2; - case 0x9: return 3; - case 0x2: case 0x6: case 0x7: case 0x8: case 0xa: case 0xc: return 4; - case 0x4: case 0xe: return 6; - default: return 2; + case 0x2: case 0x3: case 0xa: svga->bpp = 15; break; + case 0x4: case 0xe: svga->bpp = 24; break; + case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; + case 0x7: svga->bpp = 32; break; + + case 0: case 1: default: svga->bpp = 8; break; } } +static void sdac_reg_write(sdac_ramdac_t *ramdac, int reg, uint8_t val) +{ + if ((reg >= 2 && reg <= 7) || (reg == 0xa) || (reg == 0xe)) + { + if (!ramdac->reg_ff) + ramdac->regs[reg] = (ramdac->regs[reg] & 0xff00) | val; + else + ramdac->regs[reg] = (ramdac->regs[reg] & 0x00ff) | (val << 8); + } + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + ramdac->windex++; +} + +static uint8_t sdac_reg_read(sdac_ramdac_t *ramdac, int reg) +{ + uint8_t temp; + + if (!ramdac->reg_ff) + temp = ramdac->regs[reg] & 0xff; + else + temp = ramdac->regs[reg] >> 8; + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + ramdac->rindex++; + + return temp; +} + void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga) { switch (addr) { - case 0x3C6: - if (val == 0xff) - { - ramdac->rs2 = 0; - ramdac->magic_count = 0; - break; - } - if (ramdac->magic_count < 4) break; + case 2: if (ramdac->magic_count == 4) - { - ramdac->command = val; - switch (val >> 4) - { - case 0x2: case 0x3: case 0x8: case 0xa: svga->bpp = 15; break; - case 0x4: case 0x9: case 0xe: svga->bpp = 24; break; - case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; - case 0x7: case 0xd: svga->bpp = 32; break; - - case 0: case 1: default: svga->bpp = 8; break; - } - svga_recalctimings(svga); - pclog("RAMDAC: Mode: %i, BPP: %i\n", val >> 4, svga->bpp); - } + sdac_control_write(ramdac, svga, val); + ramdac->magic_count = 0; break; - case 0x3C7: + case 3: ramdac->magic_count = 0; - if (ramdac->rs2) - ramdac->rindex = val; break; - case 0x3C8: + case 0: ramdac->magic_count = 0; - if (ramdac->rs2) - ramdac->windex = val; break; - case 0x3C9: + case 1: ramdac->magic_count = 0; - if (ramdac->rs2) - { - if (!ramdac->reg_ff) ramdac->regs[ramdac->windex & 0xff] = (ramdac->regs[ramdac->windex & 0xff] & 0xff00) | val; - else ramdac->regs[ramdac->windex & 0xff] = (ramdac->regs[ramdac->windex & 0xff] & 0x00ff) | (val << 8); - ramdac->reg_ff = !ramdac->reg_ff; - if (!ramdac->reg_ff) ramdac->windex++; - } + break; + + case 4: + ramdac->windex = val; + ramdac->reg_ff = 0; + break; + case 5: + sdac_reg_write(ramdac, ramdac->windex & 0xff, val); + break; + case 6: + sdac_control_write(ramdac, svga, val); + break; + case 7: + ramdac->rindex = val; + ramdac->reg_ff = 0; break; } - svga_out(addr, val, svga); + if (!(addr & 4)) + { + if (addr < 2) + svga_out(addr + 0x3c8, val, svga); + else + svga_out(addr + 0x3c4, val, svga); + } } uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) @@ -121,10 +141,9 @@ uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) uint8_t temp; switch (addr) { - case 0x3C6: - ramdac->reg_ff = 0; + case 2: if (ramdac->magic_count < 5) - ramdac->magic_count++; + ramdac->magic_count++; if (ramdac->magic_count == 4) { temp = 0x70; /*SDAC ID*/ @@ -136,31 +155,32 @@ uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) ramdac->magic_count = 0; } return temp; - case 0x3C7: - ramdac->magic_count=0; - if (ramdac->rs2) return ramdac->rindex; + case 3: + ramdac->magic_count=0; break; - case 0x3C8: - ramdac->magic_count=0; - if (ramdac->rs2) return ramdac->windex; + case 0: + ramdac->magic_count=0; break; - case 0x3C9: - ramdac->magic_count=0; - if (ramdac->rs2) - { - if (!ramdac->reg_ff) temp = ramdac->regs[ramdac->rindex & 0xff] & 0xff; - else temp = ramdac->regs[ramdac->rindex & 0xff] >> 8; - ramdac->reg_ff = !ramdac->reg_ff; - if (!ramdac->reg_ff) - { - ramdac->rindex++; - ramdac->magic_count = 0; - } - return temp; - } + case 1: + ramdac->magic_count=0; break; + case 4: + return ramdac->windex; + case 5: + return sdac_reg_read(ramdac, ramdac->rindex & 0xff); + case 6: + return ramdac->command; + case 7: + return ramdac->rindex; } - return svga_in(addr, svga); + if (!(addr & 4)) + { + if (addr < 2) + return svga_in(addr + 0x3c8, svga); + else + return svga_in(addr + 0x3c4, svga); + } + return 0xff; } float sdac_getclock(int clock, void *p) @@ -177,3 +197,9 @@ float sdac_getclock(int clock, void *p) t = (14318184.0f * (float)m / (float)n1) / (float)(1 << n2); return t; } + +void sdac_init(sdac_ramdac_t *ramdac) +{ + ramdac->regs[0] = 0x6128; + ramdac->regs[1] = 0x623d; +} diff --git a/src/video/vid_sdac_ramdac.h b/src/video/vid_sdac_ramdac.h index 6bf7f1e..d91cc5a 100644 --- a/src/video/vid_sdac_ramdac.h +++ b/src/video/vid_sdac_ramdac.h @@ -8,7 +8,7 @@ * * Definitions for the SDAC driver. * - * Version: @(#)vid_sdac_ramdac.h 1.0.1 2018/02/14 + * Version: @(#)vid_sdac_ramdac.h 1.0.2 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -55,5 +55,7 @@ uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga); float sdac_getclock(int clock, void *p); +void sdac_init(sdac_ramdac_t *ramdac); + #endif /*VIDEO_SDAC_RAMDAC_H*/ diff --git a/src/video/vid_table.c b/src/video/vid_table.c index df27bac..2d323d4 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -8,7 +8,7 @@ * * Define all known video cards. * - * Version: @(#)vid_table.c 1.0.11 2018/03/20 + * Version: @(#)vid_table.c 1.0.12 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -217,7 +217,6 @@ video_reset(int card) loadfont(L"roms/video/ibm/mda/mda.rom", 0); loadfont(L"roms/video/wyse/wyse700/wy700.rom", 3); loadfont(L"roms/video/mdsi/genius/8x12.bin", 4); - loadfont(FONT_ATIKOR_PATH, 6); /* Do not initialize internal cards here. */ if ((card == VID_NONE) || \ diff --git a/src/video/video.c b/src/video/video.c index 88d845a..a608027 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -40,7 +40,7 @@ * W = 3 bus clocks * L = 4 bus clocks * - * Version: @(#)video.c 1.0.7 2018/03/18 + * Version: @(#)video.c 1.0.8 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -128,7 +128,7 @@ int video_timing_write_b = 0, int video_res_x = 0, video_res_y = 0, video_bpp = 0; -int video_timing[6][4] = { +const int video_timing[6][4] = { { VIDEO_ISA, 8, 16, 32 }, { VIDEO_ISA, 6, 8, 16 }, { VIDEO_ISA, 3, 3, 6 }, @@ -744,7 +744,7 @@ loadfont(wchar_t *s, int format) for (c=0; c<256; c++) { for (d=0; d<8; d++) fontdat[c][d] = fgetc(f); - for (d=0; d<8; d++) (void)fgetc(f); + for (d=0; d<8; d++) (void)fgetc(f); } break; diff --git a/src/win/Makefile.MSVC b/src/win/Makefile.MSVC deleted file mode 100644 index dd2ab92..0000000 --- a/src/win/Makefile.MSVC +++ /dev/null @@ -1,591 +0,0 @@ -# -# 86Box A hypervisor and IBM PC system emulator that specializes in -# running old operating systems and software designed for IBM -# PC systems and compatibles from 1981 through fairly recent -# system designs based on the PCI bus. -# -# This file is part of the 86Box distribution. -# -# Makefile for Microsoft Visual Studio (2008) environment. -# -# Version: @(#)Makefile.MSVS 1.0.1 2017/11/25 -# -# Author: Fred N. van Kempen, -# - -# Various compile-time options. -ifndef STUFF -STUFF := -endif - -# Add feature selections here. -ifndef EXTRAS -EXTRAS := -endif - -# Defaults for several build options (possibly defined in a chained file.) -ifndef AUTODEP -AUTODEP := n -endif -ifndef CRASHDUMP -CRASHCUMP := n -endif -ifndef DEBUG -DEBUG := n -endif -ifndef OPTIM -OPTIM := n -endif -ifndef RELEASE -RELEASE := n -endif -ifndef X64 -X64 := n -endif -ifndef WX -WX := n -endif -ifndef USB -USB := n -endif -ifndef VNC -VNC := n -endif -ifndef RDP -RDP := n -endif -ifndef DEV_BUILD -DEV_BUILD := n -endif -ifndef DEV_BRANCH -DEV_BRANCH := n -endif -ifndef CIRRUS -CIRRUS := n -endif -ifndef NE1000 -NE1000 := n -endif -ifndef NV_RIVA -NV_RIVA := n -endif -ifndef OPENAL -OPENAL := y -endif -ifndef FLUIDSYNTH -FLUIDSYNTH := y -endif -ifndef MUNT -MUNT := y -endif -ifndef PAS16 -PAS16 := n -endif -ifndef DYNAREC -DYNAREC := y -endif - - -# Name of the executable. -ifndef PROG - ifneq ($(WX), n) - PROG := Wx86Box - else - PROG := 86Box - endif -endif - -ifeq ($(DEV_BUILD), y) -DEBUG := y -DEV_BRANCH := y -CIRRUS := y -NE1000 := y -NV_RIVA := y -PAS16 := y -VNC := y -endif - -# WxWidgets basic info. Extract using the config program. -ifneq ($(WX), n) - EXPATH += wx - WX_CONFIG := wx-config.exe - ifeq ($(WX), y) - WX_PATH := C:/MinGW32/WxWidgets - WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ - -I$(WX_PATH)/include/wx-3.0 \ - -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread -# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma - WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ - -lwx_mswu-3.0.dll \ - -lrpcrt4 -loleaut32 -lole32 -luuid \ - -lwinspool -lwinmm -lshell32 -lcomctl32 \ - -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 - endif - ifeq ($(WX), static) - WX_PATH := C:/MinGW32/WxWidgets - WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ - -I$(WX_PATH)/include/wx-3.0 \ - -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread -# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma - WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ - -lwx_mswu-3.0 -lwxscintilla-3.0 \ - -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 \ - -lwxregexu-3.0 -lwxexpat-3.0 \ - -lrpcrt4 -loleaut32 -lole32 -luuid \ - -lwinspool -lwinmm -lshell32 -lcomctl32 \ - -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 - endif -endif - - -# Where is the the DirectX SDK? -DIRECTX = N:\DEV\Windows\DX9 -DXINC = -I$(DIRECTX)\Include -DXLIB = -L$(DIRECTX)\Lib - - -######################################################################### -# Nothing should need changing from here on.. # -######################################################################### -VPATH := $(EXPATH) . cpu \ - cdrom disk floppy game machine \ - sound \ - sound/munt sound/munt/c_interface sound/munt/sha1 \ - sound/munt/srchelper \ - sound/resid-fp \ - scsi video lzf network network/slirp win - - -# Set up the correct toolchain flags. -# Microsoft Windows, Intel PC, Microsoft Visual Studio 2008. -OPTS = -D_CRT_SECURE_NO_WARNINGS -D__MSC__ -D_WIN32 \ - -Dinline= -ifeq ($(X64), y) -OPTS += -D_WIN64 -CPP := cl -CC := cl -else -CPP := cl -CC := cl -endif -LD = link -nologo -AR = lib -RC = rc -nologo -DEPS = -MMD -MF $*.d -c $< -DEPFILE := win/.depends - -OPTS += -nologo $(EXTRAS) $(STUFF) -LOPTS := -nologo -ifdef EXFLAGS -OPTS += $(EXFLAGS) -endif -ifdef EXINC -OPTS += -I$(EXINC) -endif -ifeq ($(X64), y) - ifeq ($(OPTIM), y) - DFLAGS := #-march=native - else - DFLAGS := - endif -else - ifeq ($(OPTIM), y) - DFLAGS := #-march=native - else - DFLAGS := #-march=i686 - endif -endif -ifeq ($(DEBUG), y) - DFLAGS += -Z7 -DDEBUG - LOPTS += -debug - AOPTIM := - ifndef COPTIM - COPTIM := -Od - endif -else - ifeq ($(OPTIM), y) - AOPTIM := #-mtune=native - ifndef COPTIM - COPTIM := -O2 - endif - else - ifndef COPTIM - COPTIM := -O2 - endif - endif -endif -AFLAGS := #-msse -msse2 -mfpmath=sse -RFLAGS := -ifeq ($(CRASHDUMP), y) -OPTS += -DUSE_CRASHDUMP -endif -ifeq ($(RELEASE), y) -OPTS += -DRELEASE_BUILD -RFLAGS += -DRELEASE_BUILD -endif -ifeq ($(VRAMDUMP), y) -OPTS += -DENABLE_VRAM_DUMP -RFLAGS += -DENABLE_VRAM_DUMP -endif -ifeq ($(X64), y) -PLATCG := codegen_x86-64.obj -CGOPS := codegen_ops_x86-64.h -VCG := vid_voodoo_codegen_x86-64.h -else -PLATCG := codegen_x86.obj -CGOPS := codegen_ops_x86.h -VCG := vid_voodoo_codegen_x86.h -endif - -# Optional modules. -ifeq ($(DYNAREC), y) -OPTS += -DUSE_DYNAREC -RFLAGS += -DUSE_DYNAREC -DYNARECOBJ := 386_dynarec_ops.obj \ - codegen.obj \ - codegen_ops.obj \ - codegen_timing_common.obj codegen_timing_486.obj \ - codegen_timing_686.obj codegen_timing_pentium.obj \ - codegen_timing_winchip.obj $(PLATCG) -endif - -ifneq ($(WX), n) - OPTS += -DUSE_WX $(WX_FLAGS) - LIBS += $(WX_LIBS) - UIOBJ := wx_main.obj wx_ui.obj wx_stbar.obj wx_render.obj -else - UIOBJ := win_ui.obj win_ddraw.obj win_d3d.obj win_png.obj \ - win_dialog.obj win_about.obj win_status.obj win_stbar.obj \ - win_settings.obj win_devconf.obj win_jsconf.obj -endif - -ifeq ($(OPENAL), y) -OPTS += -DUSE_OPENAL -endif -ifeq ($(FLUIDSYNTH), y) -OPTS += -DUSE_FLUIDSYNTH -FSYNTHOBJ := midi_fluidsynth.obj -endif - -ifeq ($(MUNT), y) -OPTS += -DUSE_MUNT -MUNTOBJ := midi_mt32.obj \ - Analog.obj BReverbModel.obj File.obj FileStream.obj LA32Ramp.obj \ - LA32FloatWaveGenerator.obj LA32WaveGenerator.obj \ - MidiStreamParser.obj Part.obj Partial.obj PartialManager.obj \ - Poly.obj ROMInfo.obj SampleRateConverter_dummy.obj Synth.obj \ - Tables.obj TVA.obj TVF.obj TVP.obj sha1.obj c_interface.obj -endif - -ifeq ($(VNC), y) -OPTS += -DUSE_VNC -RFLAGS += -DUSE_VNC - ifneq ($(VNC_PATH), ) - OPTS += -I$(VNC_PATH)\INCLUDE - VNCLIB := -L$(VNC_PATH)\LIB - endif -VNCLIB += -lvncserver -VNCOBJ := vnc.obj vnc_keymap.obj -endif - -ifeq ($(RDP), y) -OPTS += -DUSE_RDP -RFLAGS += -DUSE_RDP - ifneq ($(RDP_PATH), ) - OPTS += -I$(RDP_PATH)\INCLUDE - RDPLIB := -L$(RDP_PATH)\LIB - endif -RDPLIB += -lrdp -RDPOBJ := rdp.obj -endif - -# Options for the DEV branch. -ifeq ($(DEV_BRANCH), y) -OPTS += -DDEV_BRANCH -DEVBROBJ := - -ifeq ($(CIRRUS), y) -OPTS += -DUSE_CIRRUS -DEVBROBJ += vid_cl_gd.obj vid_cl_gd_blit.obj vid_cl_ramdac.obj -endif - -ifeq ($(NE1000), y) -OPTS += -DUSE_NE1000 -endif - -ifeq ($(NV_RIVA), y) -OPTS += -DUSE_RIVA -DEVBROBJ += vid_nv_riva128.obj -endif - -ifeq ($(PAS16), y) -OPTS += -DUSE_PAS16 -DEVBROBJ += snd_pas16.obj -endif - -endif - - -# Options for works-in-progress. -ifndef SERIAL -SERIAL := serial.obj -endif - - -# Final versions of the toolchain flags. -CFLAGS := -Iwin/msvs $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ - $(AFLAGS) -W4 -Gs -CXXFLAGS := -Iwin/msvs $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ - $(AFLAGS) -fno-strict-aliasing -fvisibility=hidden \ - -Wall -Wundef -fvisibility-inlines-hidden \ - -Wunused-parameter -Wno-ctor-dtor-privacy \ - -Woverloaded-virtual - - -######################################################################### -# Create the (final) list of objects to build. # -######################################################################### -MAINOBJ := pc.obj config.obj random.obj timer.obj io.obj dma.obj nmi.obj pic.obj \ - pit.obj ppi.obj pci.obj mca.obj mcr.obj mem.obj memregs.obj rom.obj \ - device.obj nvr.obj nvr_at.obj nvr_ps2.obj $(VNCOBJ) $(RDPOBJ) \ - intel.obj intel_flash.obj intel_piix.obj intel_piix4.obj intel_sio.obj - -CPUOBJ := cpu.obj cpu_table.obj \ - 808x.obj 386.obj x86seg.obj x87.obj \ - 386_dynarec.obj $(DYNARECOBJ) - -MCHOBJ := machine.obj machine_table.obj \ - m_amstrad.obj m_europc.obj m_europc_hdc.obj \ - m_olivetti_m24.obj m_tandy.obj \ - m_xt.obj m_xt_compaq.obj m_xt_laserxt.obj \ - m_at.obj m_at_ali1429.obj m_at_commodore.obj \ - m_at_neat.obj m_at_headland.obj \ - m_at_opti495.obj m_at_scat.obj \ - m_at_compaq.obj m_at_wd76c10.obj \ - m_at_sis_85c471.obj m_at_sis_85c496.obj \ - m_at_430lx_nx.obj m_at_430fx.obj \ - m_at_430hx.obj m_at_430vx.obj \ - m_at_440fx.obj \ - m_pcjr.obj m_ps1.obj m_ps2_isa.obj m_ps2_mca.obj - -DEVOBJ := bugger.obj lpt.obj $(SERIAL) \ - sio_detect.obj \ - sio_fdc37c66x.obj sio_fdc37c669.obj sio_fdc37c93x.obj \ - sio_pc87306.obj sio_w83877f.obj sio_um8669f.obj \ - keyboard.obj \ - keyboard_xt.obj keyboard_at.obj \ - gameport.obj \ - joystick_standard.obj joystick_ch_flightstick_pro.obj \ - joystick_sw_pad.obj joystick_tm_fcs.obj \ - mouse.obj \ - mouse_serial.obj mouse_ps2.obj mouse_bus.obj - -FDDOBJ := fdd.obj fdc.obj fdi2raw.obj \ - floppy.obj floppy_common.obj floppy_86f.obj \ - floppy_fdi.obj floppy_imd.obj floppy_img.obj floppy_json.obj \ - floppy_td0.obj - -HDDOBJ := hdd.obj \ - hdd_image.obj hdd_table.obj \ - hdc.obj \ - hdc_esdi_at.obj hdc_esdi_mca.obj hdc_ide.obj hdc_mfm_at.obj \ - hdc_mfm_xt.obj hdc_xtide.obj - -CDROMOBJ := cdrom.obj \ - cdrom_dosbox.obj cdrom_image.obj cdrom_null.obj - -ifeq ($(USB), y) -USBOBJ := usb.obj -endif - -SCSIOBJ := scsi.obj \ - scsi_bus.obj scsi_device.obj \ - scsi_disk.obj \ - scsi_x54x.obj \ - scsi_buslogic.obj scsi_aha154x.obj \ - scsi_ncr5380.obj - -NETOBJ := network.obj \ - net_pcap.obj \ - net_slirp.obj \ - bootp.obj ip_icmp.obj misc.obj socket.obj tcp_timer.obj cksum.obj \ - ip_input.obj queue.obj tcp_input.obj debug.obj ip_output.obj \ - sbuf.obj tcp_output.obj udp.obj if.obj mbuf.obj slirp.obj tcp_subr.obj \ - net_ne2000.obj - -SNDOBJ := sound.obj \ - openal.obj \ - dbopl.obj nukedopl.obj \ - snd_resid.obj \ - convolve.obj convolve-sse.obj envelope.obj extfilt.obj \ - filter.obj pot.obj sid.obj voice.obj wave6581__ST.obj \ - wave6581_P_T.obj wave6581_PS_.obj wave6581_PST.obj \ - wave8580__ST.obj wave8580_P_T.obj wave8580_PS_.obj \ - wave8580_PST.obj wave.obj \ - midi.obj $(FSYNTHOBJ) $(MUNTOBJ) \ - midi_system.obj \ - snd_speaker.obj \ - snd_pssj.obj \ - snd_lpt_dac.obj snd_lpt_dss.obj \ - snd_adlib.obj snd_adlibgold.obj snd_ad1848.obj snd_audiopci.obj \ - snd_sb.obj snd_sb_dsp.obj snd_cms.obj snd_dbopl.obj \ - snd_emu8k.obj snd_gus.obj snd_opl.obj \ - snd_mpu401.obj \ - snd_sn76489.obj snd_ssi2001.obj snd_wss.obj \ - snd_ym7128.obj - -VIDOBJ := video.obj \ - vid_table.obj \ - vid_cga.obj vid_cga_comp.obj vid_mda.obj \ - vid_ega.obj vid_ega_render.obj \ - vid_vga.obj vid_svga.obj vid_svga_render.obj \ - vid_hercules.obj vid_herculesplus.obj vid_incolor.obj \ - vid_colorplus.obj \ - vid_genius.obj \ - vid_s3.obj vid_s3_virge.obj \ - vid_et4000.obj vid_et4000w32.obj vid_icd2061.obj \ - vid_oti067.obj \ - vid_paradise.obj \ - vid_tvga.obj vid_tgui9440.obj vid_tkd8001_ramdac.obj \ - vid_ati_eeprom.obj vid_ati18800.obj vid_ati28800.obj \ - vid_ati68860_ramdac.obj vid_ati_mach64.obj \ - vid_ics2595.obj \ - vid_sc1502x_ramdac.obj \ - vid_sdac_ramdac.obj \ - vid_stg_ramdac.obj \ - vid_ti_cf62011.obj \ - vid_wy700.obj \ - vid_voodoo.obj - -PLATOBJ := win.obj \ - win_crashdump.obj win_dynld.obj win_thread.obj $(WSERIAL) \ - win_cdrom.obj win_cdrom_ioctl.obj win_keyboard.obj \ - win_mouse.obj win_joystick.obj win_midi.obj - -OBJ := $(MAINOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ - $(FDDOBJ) $(CDROMOBJ) $(HDDOBJ) \ - $(USBOBJ) $(NETOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ - $(PLATOBJ) $(UIOBJ) $(DEVBROBJ) -ifdef EXOBJ -OBJ += $(EXOBJ) -endif - -LZFOBJ := lzf_c.obj lzf_d.obj - -LIBS := -mwindows \ - -lopenal.dll -lopelal \ - -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 \ - -lcomctl32 -lwinmm -ifeq ($(VNC), y) -LIBS += $(VNCLIB) -lws2_32 -lz -endif -ifeq ($(RDP), y) -LIBS += $(RDPLIB) -endif -ifneq ($(WX), n) -LIBS += $(WX_LIBS) -lz -lm -endif -LIBS += -lkernel32 -lwsock32 -liphlpapi -lpsapi -LIBS += -lpthread -static -lstdc++ -lgcc -LIBS += -Wl,--large-address-aware - - -# Build module rules. -ifeq ($(AUTODEP), y) -%.obj: %.c - @echo $< - @$(CC) $(CFLAGS) $(DEPS) -c $< - -%.obj: %.cc - @echo $< - @$(CPP) $(CXXFLAGS) $(DEPS) -c $< - -%.obj: %.cpp - @echo $< - @$(CPP) $(CXXFLAGS) $(DEPS) -c $< -else -%.obj: %.c - @echo $< - @$(CC) $(CFLAGS) -c $< - -%.obj: %.cc - @echo $< - @$(CPP) $(CXXFLAGS) -c $< - -%.obj: %.cpp - @echo $< - @$(CPP) $(CXXFLAGS) -c $< - -%.d: %.c $(wildcard $*.d) - @echo $< - @$(CC) $(CFLAGS) $(DEPS) -E $< >NUL - -%.d: %.cc $(wildcard $*.d) - @echo $< - @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL - -%.d: %.cpp $(wildcard $*.d) - @echo $< - @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL -endif - - -all: $(PROG).exe pcap_if.exe - - -86Box.res: 86Box.rc - @echo Processing $< - @$(RC) $(RFLAGS) $(EXTRAS) -r $< - -$(PROG).exe: $(OBJ) $(LZFOBJ) 86Box.res - @echo Linking $(PROG).exe .. - @$(LD) -OUT:$(PROG) $(OBJ) $(LZFOBJ) 86Box.res $(LIBS) - -pcap_if.res: pcap_if.rc - @echo Processing $< - @$(RC) $(RFLAGS) $(EXTRAS) -r $< - -pcap_if.exe: pcap_if.obj win_dynld.obj pcap_if.res - @echo Linking pcap_if.exe .. - @$(LD) -OUT:pcap_if pcap_if.obj win_dynld.obj pcap_if.res - -hello.exe: hello.obj - $(CXX) $(LDFLAGS) -o hello.exe hello.obj $(WXLIBS) $(LIBS) - - -clean: - @echo Cleaning objects.. - @-rm -f *.obj 2>NUL - @-rm -f *.res 2>NUL - -clobber: clean - @echo Cleaning executables.. - @-rm -f *.d 2>NUL - @-rm -f *.exe 2>NUL -# @-rm -f $(DEPFILE) 2>NUL - -ifneq ($(AUTODEP), y) -depclean: - @-rm -f $(DEPFILE) 2>NUL - @echo Creating dependencies.. - @echo # Run "make depends" to re-create this file. >$(DEPFILE) - -depends: DEPOBJ=$(OBJ:%.obj=%.d) -depends: depclean $(OBJ:%.obj=%.d) - @-cat $(DEPOBJ) >>$(DEPFILE) - @-rm -f $(DEPOBJ) - -$(DEPFILE): -endif - - -# Module dependencies. -ifeq ($(AUTODEP), y) -#-include $(OBJ:%.obj=%.d) (better, but sloooowwwww) --include *.d -else -include $(wildcard $(DEPFILE)) -endif - - -# End of Makefile.MSVS. diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 4491d98..1d6cb85 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -8,7 +8,7 @@ # # Makefile for Windows systems using the MinGW32 environment. # -# Version: @(#)Makefile.mingw 1.0.14 2018/03/17 +# Version: @(#)Makefile.mingw 1.0.15 2018/03/20 # # Author: Fred N. van Kempen, # @@ -472,10 +472,10 @@ CXXFLAGS := $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ ######################################################################### # Create the (final) list of objects to build. # ######################################################################### -MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \ - pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \ - rom_load.o device.o nvr.o nvr_at.o nvr_ps2.o \ - $(VNCOBJ) $(RDPOBJ) +MAINOBJ := pc.o config.o \ + random.o timer.o io.o dma.o nmi.o pic.o pit.o ppi.o \ + pci.o mca.o mcr.o mem.o memregs.o rom.o rom_load.o \ + device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) INTELOBJ := intel.o \ intel_flash.o \ diff --git a/src/win/win.c b/src/win/win.c index d2e6838..5df4f1d 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -8,7 +8,7 @@ * * Platform main support module for Windows. * - * Version: @(#)win.c 1.0.8 2018/03/17 + * Version: @(#)win.c 1.0.9 2018/03/20 * * Authors: Fred N. van Kempen, * Miran Grca, diff --git a/src/win/win_about.c b/src/win/win_about.c index e596fd3..e06c762 100644 --- a/src/win/win_about.c +++ b/src/win/win_about.c @@ -8,7 +8,7 @@ * * Handle the About dialog. * - * Version: @(#)win_about.c 1.0.3 2018/03/07 + * Version: @(#)win_about.c 1.0.5 2018/03/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -42,6 +42,7 @@ #include #include #include "../emu.h" +#include "../version.h" #include "../plat.h" #include "win.h" @@ -93,7 +94,7 @@ AboutDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) (WPARAM)NULL, (LPARAM)emu_title); set_font_bold(hdlg, IDT_TITLE); - sprintf(temp, "v%s", emu_version); + sprintf(temp, "%s", emu_fullversion); SendDlgItemMessage(hdlg, IDT_VERSION, WM_SETTEXT, (WPARAM)NULL, (LPARAM)temp); break; diff --git a/src/win/win_cdrom_ioctl.c b/src/win/win_cdrom_ioctl.c index fa6d778..c2149eb 100644 --- a/src/win/win_cdrom_ioctl.c +++ b/src/win/win_cdrom_ioctl.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM host drive IOCTL interface for * Windows using SCSI Passthrough Direct. * - * Version: @(#)cdrom_ioctl.c 1.0.7 2018/03/20 + * Version: @(#)cdrom_ioctl.c 1.0.8 2018/03/21 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -44,8 +44,10 @@ #include #include #include +#include #include #include +#define HAVE_STDARG_H #include "../emu.h" #include "../device.h" #include "../scsi/scsi.h" @@ -72,8 +74,8 @@ typedef struct { cdrom_ioctl_windows_t cdrom_ioctl_windows[CDROM_NUM]; -#ifdef ENABLE_CDROM_LOG -int cdrom_ioctl_do_log = ENABLE_CDROM_LOG; +#ifdef ENABLE_CDROM_IOCTL_LOG +int cdrom_ioctl_do_log = ENABLE_CDROM_IOCTL_LOG; #endif @@ -83,13 +85,13 @@ static CDROM ioctl_cdrom; static void cdrom_ioctl_log(const char *format, ...) { -#ifdef ENABLE_CDROM_LOG +#ifdef ENABLE_CDROM_IOCTL_LOG + va_list ap; + if (cdrom_ioctl_do_log) { - va_list ap; va_start(ap, format); - vfprintf(stdlog, format, ap); + pclog_ex(format, ap); va_end(ap); - fflush(stdlog); } #endif } @@ -107,15 +109,19 @@ void ioctl_audio_callback(uint8_t id, int16_t *output, int len) if (dev->cd_state == CD_PLAYING) { dev->seek_pos += (len >> 11); - } + cdrom_ioctl_log("ioctl_audio_callback(): playing but mute\n"); + } else + cdrom_ioctl_log("ioctl_audio_callback(): not playing\n"); + cdrom_ioctl_windows[id].is_playing = 0; memset(output, 0, len * 2); return; } + cdrom_ioctl_log("ioctl_audio_callback(): dev->cd_buflen = %i, len = %i\n", dev->cd_buflen, len); while (dev->cd_buflen < len) { if (dev->seek_pos < dev->cd_end) { - in.DiskOffset.LowPart = (dev->seek_pos - 150) * 2048; + in.DiskOffset.LowPart = dev->seek_pos * 2048; in.DiskOffset.HighPart = 0; in.SectorCount = 1; in.TrackMode = CDDA; @@ -126,11 +132,13 @@ void ioctl_audio_callback(uint8_t id, int16_t *output, int len) ioctl_close(id); dev->cd_state = CD_STOPPED; dev->cd_buflen = len; + cdrom_ioctl_log("ioctl_audio_callback(): read sector error, stopped\n"); } else { dev->seek_pos++; dev->cd_buflen += (2352 / 2); + cdrom_ioctl_log("ioctl_audio_callback(): dev->seek_pos = %i\n", dev->seek_pos); } } else @@ -140,6 +148,7 @@ void ioctl_audio_callback(uint8_t id, int16_t *output, int len) ioctl_close(id); dev->cd_state = CD_STOPPED; dev->cd_buflen = len; + cdrom_ioctl_log("ioctl_audio_callback(): reached the end\n"); } } memcpy(output, dev->cd_buffer, len * 2); @@ -165,27 +174,32 @@ static int get_track_nr(uint8_t id, uint32_t pos) if (dev->disc_changed) { return 0; + cdrom_ioctl_log("get_track_nr(): disc changed\n"); } if (cdrom_ioctl[id].last_track_pos == pos) { + cdrom_ioctl_log("get_track_nr(): cdrom_ioctl[id].last_track_pos == pos\n"); return cdrom_ioctl[id].last_track_nr; } - for (c = cdrom_ioctl_windows[id].toc.FirstTrack; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) + /* for (c = cdrom_ioctl_windows[id].toc.FirstTrack; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) */ + for (c = 0; c < cdrom_ioctl_windows[id].toc.LastTrack; c++) { - uint32_t track_address = cdrom_ioctl_windows[id].toc.TrackData[c].Address[3] + - (cdrom_ioctl_windows[id].toc.TrackData[c].Address[2] * 75) + - (cdrom_ioctl_windows[id].toc.TrackData[c].Address[1] * 75 * 60); + uint32_t track_address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[c].Address[1], + cdrom_ioctl_windows[id].toc.TrackData[c].Address[2], + cdrom_ioctl_windows[id].toc.TrackData[c].Address[3]) - 150; if (track_address <= pos) { + cdrom_ioctl_log("get_track_nr(): track = %i\n", c); track = c; } } cdrom_ioctl[id].last_track_pos = pos; cdrom_ioctl[id].last_track_nr = track; + cdrom_ioctl_log("get_track_nr(): return %i\n", track); return track; } @@ -218,6 +232,7 @@ static void ioctl_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) { return; } + cdrom_ioctl_log("Play audio - %08X %08X %i\n", pos, len, ismsf); if (ismsf == 2) { start_msf = get_track_msf(id, pos); @@ -233,11 +248,11 @@ static void ioctl_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) m = (start_msf >> 16) & 0xff; s = (start_msf >> 8) & 0xff; f = start_msf & 0xff; - pos = MSFtoLBA(m, s, f); + pos = MSFtoLBA(m, s, f) - 150; m = (end_msf >> 16) & 0xff; s = (end_msf >> 8) & 0xff; f = end_msf & 0xff; - len = MSFtoLBA(m, s, f); + len = MSFtoLBA(m, s, f) - 150; } else if (ismsf == 1) { @@ -252,13 +267,13 @@ static void ioctl_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) } else { - pos = MSFtoLBA(m, s, f); + pos = MSFtoLBA(m, s, f) - 150; } m = (len >> 16) & 0xff; s = (len >> 8) & 0xff; f = len & 0xff; - len = MSFtoLBA(m, s, f); + len = MSFtoLBA(m, s, f) - 150; } else if (ismsf == 0) { @@ -271,11 +286,7 @@ static void ioctl_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) } dev->seek_pos = pos; dev->cd_end = len; - if (dev->seek_pos < 150) - { - /* Adjust because the host expects a minimum adjusted LBA of 0 which is equivalent to an absolute LBA of 150. */ - dev->seek_pos = 150; - } + if (!cdrom_ioctl_windows[id].is_playing) { ioctl_hopen(id); @@ -485,9 +496,11 @@ static uint8_t ioctl_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) if (dev->cd_state == CD_PLAYING || dev->cd_state == CD_PAUSED) { track = get_track_nr(id, cdpos); - track_address = cdrom_ioctl_windows[id].toc.TrackData[track].Address[3] + (cdrom_ioctl_windows[id].toc.TrackData[track].Address[2] * 75) + (cdrom_ioctl_windows[id].toc.TrackData[track].Address[1] * 75 * 60); + track_address = MSFtoLBA(cdrom_ioctl_windows[id].toc.TrackData[track].Address[1], + cdrom_ioctl_windows[id].toc.TrackData[track].Address[2], + cdrom_ioctl_windows[id].toc.TrackData[track].Address[3]) - 150; - cdrom_ioctl_log("cdpos = %i, track = %i, track_address = %i\n", cdpos, track, track_address); + cdrom_ioctl_log("ioctl_getcurrentsubchannel(): cdpos = %i, track = %i, track_address = %i\n", cdpos, track, track_address); b[pos++] = sub.CurrentPosition.Control; b[pos++] = track + 1; @@ -501,7 +514,7 @@ static uint8_t ioctl_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) b[pos + 1] = (uint8_t)dat; b[pos] = 0; pos += 4; - dat = cdpos - track_address - 150; + dat = cdpos - track_address; b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; b[pos + 1] = (uint8_t)dat; @@ -545,12 +558,12 @@ static uint8_t ioctl_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) } else { - uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]); + uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]) - 150; b[pos++] = temp >> 24; b[pos++] = temp >> 16; b[pos++] = temp >> 8; b[pos++] = temp; - temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]); + temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]) - 150; b[pos++] = temp >> 24; b[pos++] = temp >> 16; b[pos++] = temp >> 8; @@ -1296,6 +1309,7 @@ int ioctl_open(uint8_t id, char d) cdrom_ioctl_windows[id].hIOCTL = CreateFile(cdrom_ioctl[id].ioctl_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); cdrom_drives[id].handler = &ioctl_cdrom; dev->handler_inited = 1; + cdrom_ioctl_windows[id].is_playing = 0; cdrom_ioctl[id].capacity_read=0; /* With these two lines, we read the READ CAPACITY command output from the host drive into our cache buffer. */ ioctl_read_capacity(id, NULL); pclog(rcs, drb[0], drb[1], drb[2], drb[3], drb[4], drb[5], drb[6], drb[7], diff --git a/src/win/win_crashdump.c b/src/win/win_crashdump.c index ad0d997..cbe006a 100644 --- a/src/win/win_crashdump.c +++ b/src/win/win_crashdump.c @@ -8,7 +8,7 @@ * * Handle generation of crash-dump reports. * - * Version: @(#)win_crashdump.c 1.0.5 2018/03/08 + * Version: @(#)win_crashdump.c 1.0.6 2018/03/20 * * Authors: Fred N. van Kempen, * Riley (Rai-chan), @@ -174,12 +174,12 @@ MakeCrashDump(PEXCEPTION_POINTERS ExceptionInfo) /* Start to put the crash-dump string into the buffer. */ sprintf(ExceptionHandlerBuffer, - "#\r\n# %s\r\n#\r\n" + "#\r\n# %s %s\r\n#\r\n" "# Crash on %d-%02d-%02d at %02d:%02d:%02d.%03d\r\n#\r\n" "\r\n" "Exception details:\r\n" " NTSTATUS code: 0x%08lx\r\n Address: 0x%p", - emu_version, + emu_title, emu_fullversion, SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wMilliseconds, diff --git a/src/win/win_ui.c b/src/win/win_ui.c index e4e55b7..3eea816 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -8,7 +8,7 @@ * * Implement the user Interface module. * - * Version: @(#)win_ui.c 1.0.6 2018/03/18 + * Version: @(#)win_ui.c 1.0.7 2018/03/20 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -46,6 +46,7 @@ #include #include #include "../emu.h" +#include "../version.h" #include "../config.h" #include "../device.h" #include "../keyboard.h" @@ -815,7 +816,7 @@ ui_init(int nCmdShow) menuMain = LoadMenu(hinstance, MENU_NAME); /* Now create our main window. */ - mbstowcs(title, emu_version, sizeof_w(title)); + wsprintf(title, L"%S", emu_version, sizeof_w(title)); hwnd = CreateWindowEx ( 0, /* no extended possibilites */ CLASS_NAME, /* class name */