diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index d3e8103..2b3a38b 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.5 2018/03/16 + * Version: @(#)cdrom.c 1.0.6 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -909,12 +909,6 @@ static void cdrom_unit_attention(uint8_t id) cdrom_log("CD-ROM %i: UNIT ATTENTION\n", id); } -static void cdrom_bus_master_error(uint8_t id) -{ - cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; - cdrom_cmd_error(id); -} - static void cdrom_not_ready(uint8_t id) { cdrom_sense_key = SENSE_NOT_READY; @@ -2745,21 +2739,22 @@ int cdrom_read_from_ide_dma(uint8_t channel) return 0; if (ide_bus_master_write) { - if (ide_bus_master_write(channel >> 1, cdbufferb, cdrom[id].packet_len)) { - cdrom_bus_master_error(id); - cdrom_phase_callback(id); + if (ide_bus_master_write(channel >> 1, cdbufferb, cdrom[id].packet_len)) return 0; - } else + else return 1; - } else { - cdrom_bus_master_error(id); - cdrom_phase_callback(id); + } else return 0; - } return 0; } +void cdrom_irq_raise(uint8_t id) +{ + if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) + ide_irq_raise(&(ide_drives[cdrom_drives[id].ide_channel])); +} + int cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) { uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; @@ -2793,40 +2788,34 @@ int cdrom_read_from_dma(uint8_t id) cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", id, cdrom[id].packet_len); ret = cdrom_phase_data_out(id); - if (!ret) { - cdrom_phase_callback(id); - return 0; - } else - return 1; - return 0; + if (ret || (cdrom_drives[id].bus_type == CDROM_BUS_SCSI)) { + cdrom_buf_free(id); + cdrom[id].packet_status = CDROM_PHASE_COMPLETE; + cdrom[id].status = READY_STAT; + cdrom[id].phase = 3; + ui_sb_update_icon(SB_CDROM | id, 0); + cdrom_irq_raise(id); + if (ret) + return 1; + else + return 0; + } else + return 0; } int cdrom_write_to_ide_dma(uint8_t channel) { uint8_t id = atapi_cdrom_drives[channel]; - if (id > CDROM_NUM) { - cdrom_log("CD-ROM %i: Drive not found\n", id); + if (id > CDROM_NUM) return 0; - } if (ide_bus_master_read) { - if (ide_bus_master_read(channel >> 1, cdbufferb, cdrom[id].packet_len)) { - cdrom_log("CD-ROM %i: ATAPI DMA error\n", id); - cdrom_bus_master_error(id); - cdrom_phase_callback(id); + if (ide_bus_master_read(channel >> 1, cdbufferb, cdrom[id].packet_len)) return 0; - } - else { - cdrom_log("CD-ROM %i: ATAPI DMA success\n", id); + else return 1; - } - } else { - cdrom_log("CD-ROM %i: No bus master\n", id); - cdrom_bus_master_error(id); - cdrom_phase_callback(id); - return 0; } return 0; @@ -2857,16 +2846,19 @@ int cdrom_write_to_dma(uint8_t id) } else ret = cdrom_write_to_ide_dma(cdrom_drives[id].ide_channel); - if (!ret) + if (ret || (cdrom_drives[id].bus_type == CDROM_BUS_SCSI)) { + cdrom_buf_free(id); + cdrom[id].packet_status = CDROM_PHASE_COMPLETE; + cdrom[id].status = READY_STAT; + cdrom[id].phase = 3; + ui_sb_update_icon(SB_CDROM | id, 0); + cdrom_irq_raise(id); + if (ret) + return 1; + else + return 0; + } else return 0; - - return 1; -} - -void cdrom_irq_raise(uint8_t id) -{ - if (cdrom_drives[id].bus_type < CDROM_BUS_SCSI) - ide_irq_raise(&(ide_drives[cdrom_drives[id].ide_channel])); } /* If the result is 1, issue an IRQ, otherwise not. */ @@ -2902,12 +2894,6 @@ void cdrom_phase_callback(uint8_t id) case CDROM_PHASE_DATA_OUT_DMA: cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA\n", id); cdrom_read_from_dma(id); - cdrom_buf_free(id); - cdrom[id].packet_status = CDROM_PHASE_COMPLETE; - cdrom[id].status = READY_STAT; - cdrom[id].phase = 3; - ui_sb_update_icon(SB_CDROM | id, 0); - cdrom_irq_raise(id); return; case CDROM_PHASE_DATA_IN: cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN\n", id); @@ -2918,12 +2904,6 @@ void cdrom_phase_callback(uint8_t id) case CDROM_PHASE_DATA_IN_DMA: cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", id); cdrom_write_to_dma(id); - cdrom_buf_free(id); - cdrom[id].packet_status = CDROM_PHASE_COMPLETE; - cdrom[id].status = READY_STAT; - cdrom[id].phase = 3; - ui_sb_update_icon(SB_CDROM | id, 0); - cdrom_irq_raise(id); return; case CDROM_PHASE_ERROR: cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", id); diff --git a/src/cdrom/cdrom.h b/src/cdrom/cdrom.h index de8e7d4..466ba9e 100644 --- a/src/cdrom/cdrom.h +++ b/src/cdrom/cdrom.h @@ -8,7 +8,7 @@ * * Definitions for the CDROM module.. * - * Version: @(#)cdrom.h 1.0.4 2018/03/08 + * Version: @(#)cdrom.h 1.0.5 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -172,6 +172,8 @@ typedef struct { int block_descriptor_len; int init_length; + + int16_t cd_buffer[BUF_SIZE]; } cdrom_t; typedef struct { @@ -211,7 +213,6 @@ typedef struct { int cd_state; uint32_t cd_pos; uint32_t cd_end; - int16_t cd_buffer[BUF_SIZE]; int cd_buflen; } cdrom_image_t; diff --git a/src/cdrom/cdrom_image.cpp b/src/cdrom/cdrom_image.cpp index 0505a3c..8f7831a 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.3 2018/02/22 + * Version: @(#)cdrom_image.cpp 1.0.4 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -112,9 +112,9 @@ void image_audio_callback(uint8_t id, int16_t *output, int len) { if (cdrom[id].seek_pos < cdrom_image[id].cd_end) { - if (!cdimg[id]->ReadSector((unsigned char*)&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], true, cdrom[id].seek_pos)) + if (!cdimg[id]->ReadSector((unsigned char*)&cdrom[id].cd_buffer[cdrom_image[id].cd_buflen], true, cdrom[id].seek_pos)) { - memset(&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); + memset(&cdrom[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); cdrom_image[id].cd_state = CD_STOPPED; cdrom_image[id].cd_buflen = len; } @@ -126,13 +126,13 @@ void image_audio_callback(uint8_t id, int16_t *output, int len) } else { - memset(&cdrom_image[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); + memset(&cdrom[id].cd_buffer[cdrom_image[id].cd_buflen], 0, (BUF_SIZE - cdrom_image[id].cd_buflen) * 2); cdrom_image[id].cd_state = CD_STOPPED; cdrom_image[id].cd_buflen = len; } } - memcpy(output, cdrom_image[id].cd_buffer, len * 2); - memmove(cdrom_image[id].cd_buffer, &cdrom_image[id].cd_buffer[len], (BUF_SIZE - len) * 2); + memcpy(output, cdrom[id].cd_buffer, len * 2); + memmove(cdrom[id].cd_buffer, &cdrom[id].cd_buffer[len], (BUF_SIZE - len) * 2); cdrom_image[id].cd_buflen -= len; } diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 0e1f2c2..cd9c015 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.9 2018/03/16 + * Version: @(#)hdc_ide.c 1.0.10 2018/03/17 * * Authors: Miran Grca, * Sarah Walker, @@ -110,6 +110,14 @@ #define WIN_SET_FEATURES 0xEF #define WIN_READ_NATIVE_MAX 0xF8 +#define FEATURE_SET_TRANSFER_MODE 0x03 +#define FEATURE_ENABLE_IRQ_OVERLAPPED 0x5d +#define FEATURE_ENABLE_IRQ_SERVICE 0x5e +#define FEATURE_DISABLE_REVERT 0x66 +#define FEATURE_ENABLE_REVERT 0xcc +#define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd +#define FEATURE_DISABLE_IRQ_SERVICE 0xde + enum { IDE_NONE = 0, @@ -417,11 +425,13 @@ static void ide_identify(IDE *ide) if (ide->buffer[49] & (1 << 8)) { - ide->buffer[52] = 2 << 8; /*DMA timing mode*/ + ide->buffer[51] = 120; + ide->buffer[52] = 120; /*DMA timing mode*/ ide->buffer[53] |= 6; ide->buffer[62] = 7; ide->buffer[63] = 7; + ide->buffer[64] = 3; /*PIO Modes 3 & 4*/ ide->buffer[88] = 7; if (ide->mdma_mode != -1) { @@ -431,7 +441,10 @@ static void ide_identify(IDE *ide) ide->buffer[88] |= d; else if ((ide->mdma_mode & 0x300) == 0x100) ide->buffer[63] |= d; - else + else if ((ide->mdma_mode & 0x300) == 0x400) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else ide->buffer[62] |= d; ide_log(" IDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); } @@ -472,10 +485,12 @@ static void ide_atapi_identify(IDE *ide) if (PCI && (ide->board < 2) && (cdrom_drives[cdrom_id].bus_type == CDROM_BUS_ATAPI_PIO_AND_DMA)) { ide->buffer[49] |= 0x100; /* DMA supported */ - ide->buffer[52] = 2 << 8; /*DMA timing mode*/ + ide->buffer[51] = 120; + ide->buffer[52] = 120; /*DMA timing mode*/ ide->buffer[53] = 7; ide->buffer[62] = 7; ide->buffer[63] = 7; + ide->buffer[64] = 3; /*PIO Modes 3 & 4*/ ide->buffer[88] = 7; if (ide->mdma_mode != -1) { @@ -485,12 +500,16 @@ static void ide_atapi_identify(IDE *ide) ide->buffer[88] |= d; else if ((ide->mdma_mode & 0x300) == 0x100) ide->buffer[63] |= d; - else + else if ((ide->mdma_mode & 0x300) == 0x400) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else ide->buffer[62] |= d; ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); } - ide->buffer[65] = 0xb4; - ide->buffer[66] = 0xb4; + ide->buffer[65] = 120; + ide->buffer[66] = 120; + ide->buffer[67] = 120; ide->buffer[71] = 30; ide->buffer[72] = 30; ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ @@ -526,26 +545,42 @@ static void ide_atapi_zip_identify(IDE *ide) if (PCI && (ide->board < 2) && (zip_drives[zip_id].bus_type == ZIP_BUS_ATAPI_PIO_AND_DMA)) { ide->buffer[49] |= 0x100; /* DMA supported */ - ide->buffer[52] = 0 << 8; /*DMA timing mode*/ - ide->buffer[53] = 6; - ide->buffer[63] = 3; - ide->buffer[88] = 7; - if (ide->mdma_mode != -1) + if (zip_drives[zip_id].is_250) { + ide->buffer[52] = 0 << 8; /*DMA timing mode*/ + ide->buffer[53] = 6; + ide->buffer[63] = 3; + ide->buffer[88] = 7; + ide->buffer[64] = 0x0001; /*PIO Mode 3*/ + ide->buffer[65] = 0x96; + ide->buffer[66] = 0x96; + ide->buffer[67] = 0xb4; + ide->buffer[68] = 0xb4; + ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ + ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ + } else { + ide->buffer[51] = 120; + ide->buffer[52] = 120; + ide->buffer[53] = 2; /*Words 64-70 are valid*/ + ide->buffer[63] = 0x0003; /*Multi-word DMA 0 & 1*/ + ide->buffer[64] = 0x0001; /*PIO Mode 3*/ + ide->buffer[65] = 120; + ide->buffer[66] = 120; + ide->buffer[67] = 120; + } + + if (ide->mdma_mode != -1) { d = (ide->mdma_mode & 0xff); d <<= 8; if ((ide->mdma_mode & 0x300) == 0x200) ide->buffer[88] |= d; - else + else if ((ide->mdma_mode & 0x300) == 0x400) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else ide->buffer[63] |= d; ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); } - ide->buffer[65] = 0x96; - ide->buffer[66] = 0x96; - ide->buffer[67] = 0xb4; - ide->buffer[68] = 0xb4; - ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/ - ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/ } } @@ -651,14 +686,25 @@ static int ide_set_features(IDE *ide) if (ide_drive_is_zip(ide)) { bus = zip_drives[atapi_zip_drives[ide->channel]].bus_type; dma = (bus == ZIP_BUS_ATAPI_PIO_AND_DMA); - max_pio = 0; + if (!PCI || !dma || (ide->board >= 2)) + max_pio = 0; + else + max_pio = 3; max_mdma = 1; } else if (ide_drive_is_cdrom(ide)) { bus = cdrom_drives[atapi_cdrom_drives[ide->channel]].bus_type; dma = (bus == CDROM_BUS_ATAPI_PIO_AND_DMA); + if (!PCI || !dma || (ide->board >= 2)) + max_pio = 0; + else + max_pio = 4; } else { bus = hdd[ide->hdd_num].bus; dma = (bus == HDD_BUS_IDE_PIO_AND_DMA); + if (!PCI || !dma || (ide->board >= 2)) + max_pio = 0; + else + max_pio = 2; } ide_log("Features code %02X\n", features); @@ -667,7 +713,7 @@ static int ide_set_features(IDE *ide) switch(features) { - case 0x03: /* Set transfer mode. */ + case FEATURE_SET_TRANSFER_MODE: /* Set transfer mode. */ ide_log("Transfer mode %02X\n", features_data >> 3); mode = (features_data >> 3); @@ -680,7 +726,7 @@ static int ide_set_features(IDE *ide) { return 0; } - ide->mdma_mode = -1; + ide->mdma_mode = (1 << submode) | 0x400; ide_log("IDE %02X: Setting DPIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); break; @@ -724,8 +770,17 @@ static int ide_set_features(IDE *ide) return 0; } - case 0x66: /* Disable reverting to power on defaults. */ - case 0xCC: /* Enable reverting to power on defaults. */ + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + if (!PCI || !dma || (ide->board >= 2)) + return 0; + else + return 1; + + case FEATURE_DISABLE_REVERT: /* Disable reverting to power on defaults. */ + case FEATURE_ENABLE_REVERT: /* Enable reverting to power on defaults. */ return 1; default: @@ -1573,6 +1628,20 @@ uint32_t ide_read_data(int ide_board, int length) IDE *ide = &ide_drives[cur_ide[ide_board]]; uint32_t temp; + if (!ide->buffer) { + switch (length) + { + case 1: + return 0xff; + case 2: + return 0xffff; + case 4: + return 0xffffffff; + default: + return 0; + } + } + uint8_t *idebufferb = (uint8_t *) ide->buffer; uint16_t *idebufferw = ide->buffer; uint32_t *idebufferl = (uint32_t *) ide->buffer; diff --git a/src/disk/zip.c b/src/disk/zip.c index 33b1388..f072200 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -9,7 +9,7 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.c 1.0.4 2018/03/08 + * Version: @(#)zip.c 1.0.5 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -89,7 +89,7 @@ uint8_t scsi_zip_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0 /* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ -uint8_t zip_command_flags[0x100] = +static const uint8_t zip_command_flags[0x100] = { IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ @@ -1107,12 +1107,6 @@ static void zip_unit_attention(uint8_t id) zip_log("ZIP %i: UNIT ATTENTION\n", id); } -static void zip_bus_master_error(uint8_t id) -{ - zip_sense_key = zip_asc = zip_ascq = 0; - zip_cmd_error(id); -} - static void zip_not_ready(uint8_t id) { zip_sense_key = SENSE_NOT_READY; @@ -2243,16 +2237,10 @@ int zip_read_from_ide_dma(uint8_t channel) return 0; if (ide_bus_master_write) { - if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) { - zip_bus_master_error(id); - zip_phase_callback(id); + if (ide_bus_master_write(channel >> 1, zipbufferb, zip[id].packet_len)) return 0; - } else + else return 1; - } else { - zip_bus_master_error(id); - zip_phase_callback(id); - return 0; } return 0; @@ -2271,6 +2259,12 @@ int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) 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; @@ -2296,11 +2290,19 @@ int zip_read_from_dma(uint8_t id) } ret = zip_phase_data_out(id); - if (!ret) { - zip_phase_callback(id); - return 0; - } else - return 1; + + 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; } @@ -2315,21 +2317,10 @@ int zip_write_to_ide_dma(uint8_t channel) } if (ide_bus_master_read) { - if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) { - zip_log("ZIP %i: ATAPI DMA error\n", id); - zip_bus_master_error(id); - zip_phase_callback(id); + if (ide_bus_master_read(channel >> 1, zipbufferb, zip[id].packet_len)) return 0; - } - else { - zip_log("ZIP %i: ATAPI DMA success\n", id); + else return 1; - } - } else { - zip_log("ZIP %i: No bus master\n", id); - zip_bus_master_error(id); - zip_phase_callback(id); - return 0; } return 0; @@ -2360,16 +2351,20 @@ int zip_write_to_dma(uint8_t id) } else ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); - if (!ret) - return 0; + 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 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])); + return 0; } /* If the result is 1, issue an IRQ, otherwise not. */ @@ -2405,12 +2400,6 @@ void zip_phase_callback(uint8_t id) case ZIP_PHASE_DATA_OUT_DMA: zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); zip_read_from_dma(id); - 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); return; case ZIP_PHASE_DATA_IN: zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); @@ -2421,12 +2410,6 @@ void zip_phase_callback(uint8_t id) case ZIP_PHASE_DATA_IN_DMA: zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); zip_write_to_dma(id); - 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); return; case ZIP_PHASE_ERROR: zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); diff --git a/src/mem.c b/src/mem.c index e096403..b8c001e 100644 --- a/src/mem.c +++ b/src/mem.c @@ -8,7 +8,7 @@ * * Memory handling and MMU. * - * Version: @(#)mem.c 1.0.6 2018/03/16 + * Version: @(#)mem.c 1.0.7 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -1750,6 +1750,8 @@ 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; diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index e90c878..c7c5d42 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -8,7 +8,7 @@ * * Implementation of the AudioPCI sound device. * - * Version: @(#)snd_audiopci.c 1.0.4 2018/03/15 + * Version: @(#)snd_audiopci.c 1.0.5 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -41,6 +41,7 @@ #include #include #include +#include #define HAVE_STDARG_H #include "../emu.h" #include "../device.h" @@ -53,6 +54,12 @@ #include "snd_audiopci.h" +#define N 16 + +#define ES1371_NCoef 91 + +static float low_fir_es1371_coef[ES1371_NCoef]; + typedef struct { uint8_t pci_command, pci_serr; @@ -93,6 +100,9 @@ typedef struct { int16_t buffer_l[64], buffer_r[64]; int buffer_pos, buffer_pos_end; + int filtered_l[32], filtered_r[32]; + int f_pos; + int16_t out_l, out_r; int32_t vol_l, vol_r; @@ -528,6 +538,7 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0x71: es1371->dac[0].vf = (es1371->dac[0].vf & ~0x1f8000) | ((val & 0xfc00) << 5); es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + es1371->dac[0].f_pos = 0; break; case 0x72: es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7fff) | (val & 0x7fff); @@ -539,6 +550,7 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0x75: es1371->dac[1].vf = (es1371->dac[1].vf & ~0x1f8000) | ((val & 0xfc00) << 5); es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + es1371->dac[1].f_pos = 0; break; case 0x76: es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7fff) | (val & 0x7fff); @@ -1034,15 +1046,60 @@ static void es1371_fetch(es1371_t *es1371, int dac_nr) } } -static void es1371_next_sample(es1371_t *es1371, int dac_nr) +static inline float low_fir_es1371(int dac_nr, int i, float NewSample) { + static float x[2][2][128]; //input samples + static int x_pos[2] = {0, 0}; + float out = 0.0; + int read_pos; + int n_coef; + int pos = x_pos[dac_nr]; + + x[dac_nr][i][pos] = NewSample; + + /*Since only 1/16th of input samples are non-zero, only filter those that + are valid.*/ + read_pos = (pos + 15) & (127 & ~15); + n_coef = (16 - pos) & 15; + + while (n_coef < ES1371_NCoef) + { + out += low_fir_es1371_coef[n_coef] * x[dac_nr][i][read_pos]; + read_pos = (read_pos + 16) & (127 & ~15); + n_coef += 16; + } + + if (i == 1) + { + x_pos[dac_nr] = (x_pos[dac_nr] + 1) & 127; + if (x_pos[dac_nr] > 127) + x_pos[dac_nr] = 0; + } + + return out; +} + +static void es1371_next_sample_filtered(es1371_t *es1371, int dac_nr, int out_idx) +{ + int out_l, out_r; + int c; + if ((es1371->dac[dac_nr].buffer_pos - es1371->dac[dac_nr].buffer_pos_end) >= 0) { es1371_fetch(es1371, dac_nr); } - es1371->dac[dac_nr].out_l = es1371->dac[dac_nr].buffer_l[es1371->dac[dac_nr].buffer_pos & 63]; - es1371->dac[dac_nr].out_r = es1371->dac[dac_nr].buffer_r[es1371->dac[dac_nr].buffer_pos & 63]; + out_l = es1371->dac[dac_nr].buffer_l[es1371->dac[dac_nr].buffer_pos & 63]; + out_r = es1371->dac[dac_nr].buffer_r[es1371->dac[dac_nr].buffer_pos & 63]; + + es1371->dac[dac_nr].filtered_l[out_idx] = (int)low_fir_es1371(dac_nr, 0, (float)out_l); + es1371->dac[dac_nr].filtered_r[out_idx] = (int)low_fir_es1371(dac_nr, 1, (float)out_r); + for (c = 1; c < 16; c++) + { + es1371->dac[dac_nr].filtered_l[out_idx+c] = (int)low_fir_es1371(dac_nr, 0, 0); + es1371->dac[dac_nr].filtered_r[out_idx+c] = (int)low_fir_es1371(dac_nr, 1, 0); + } + // audiopci_log("Use %02x %04x %04x\n", es1371->dac[dac_nr].buffer_pos & 63, es1371->dac[dac_nr].out_l, es1371->dac[dac_nr].out_r); es1371->dac[dac_nr].buffer_pos++; @@ -1050,20 +1107,64 @@ static void es1371_next_sample(es1371_t *es1371, int dac_nr) } //static FILE *es1371_f;//,*es1371_f2; + +static void es1371_update(es1371_t *es1371) +{ + int32_t l, r; + + l = (es1371->dac[0].out_l * es1371->dac[0].vol_l) >> 12; + l += ((es1371->dac[1].out_l * es1371->dac[1].vol_l) >> 12); + r = (es1371->dac[0].out_r * es1371->dac[0].vol_r) >> 12; + r += ((es1371->dac[1].out_r * es1371->dac[1].vol_r) >> 12); + + l >>= 1; + r >>= 1; + + l = (l * es1371->master_vol_l) >> 15; + r = (r * es1371->master_vol_r) >> 15; + + if (l < -32768) + l = -32768; + else if (l > 32767) + l = 32767; + if (r < -32768) + r = -32768; + else if (r > 32767) + r = 32767; + + for (; es1371->pos < sound_pos_global; es1371->pos++) + { + es1371->buffer[es1371->pos*2] = l; + es1371->buffer[es1371->pos*2 + 1] = r; + } +} + static void es1371_poll(void *p) { es1371_t *es1371 = (es1371_t *)p; es1371->dac[1].time += es1371->dac[1].latch; + es1371_update(es1371); + if (es1371->int_ctrl & INT_DAC1_EN) { + int frac = es1371->dac[0].ac & 0x7fff; + int idx = es1371->dac[0].ac >> 15; + int samp1_l = es1371->dac[0].filtered_l[idx]; + int samp1_r = es1371->dac[0].filtered_r[idx]; + int samp2_l = es1371->dac[0].filtered_l[(idx + 1) & 31]; + int samp2_r = es1371->dac[0].filtered_r[(idx + 1) & 31]; + + es1371->dac[0].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; + es1371->dac[0].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; // audiopci_log("1Samp %i %i %08x\n", es1371->dac[0].curr_samp_ct, es1371->dac[0].samp_ct, es1371->dac[0].ac); - es1371->dac[0].ac += es1371->dac[0].vf; - if (es1371->dac[0].ac & (~0 << (15+4))) + es1371->dac[0].ac += es1371->dac[0].vf; + es1371->dac[0].ac &= ((32 << 15) - 1); + if ((es1371->dac[0].ac >> (15+4)) != es1371->dac[0].f_pos) { - es1371->dac[0].ac &= ~(~0 << (15+4)); - es1371_next_sample(es1371, 0); + es1371_next_sample_filtered(es1371, 0, es1371->dac[0].f_pos ? 16 : 0); + es1371->dac[0].f_pos = (es1371->dac[0].f_pos + 1) & 1; es1371->dac[0].curr_samp_ct++; if (es1371->dac[0].curr_samp_ct == es1371->dac[0].samp_ct) @@ -1081,51 +1182,35 @@ static void es1371_poll(void *p) if (es1371->int_ctrl & INT_DAC2_EN) { + int frac = es1371->dac[1].ac & 0x7fff; + int idx = es1371->dac[1].ac >> 15; + int samp1_l = es1371->dac[1].filtered_l[idx]; + int samp1_r = es1371->dac[1].filtered_r[idx]; + int samp2_l = es1371->dac[1].filtered_l[(idx + 1) & 31]; + int samp2_r = es1371->dac[1].filtered_r[(idx + 1) & 31]; + + es1371->dac[1].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; + es1371->dac[1].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; // audiopci_log("2Samp %i %i %08x\n", es1371->dac[1].curr_samp_ct, es1371->dac[1].samp_ct, es1371->dac[1].ac); es1371->dac[1].ac += es1371->dac[1].vf; - if (es1371->dac[1].ac & (~0 << (15+4))) + es1371->dac[1].ac &= ((32 << 15) - 1); + if ((es1371->dac[1].ac >> (15+4)) != es1371->dac[1].f_pos) { - es1371->dac[1].ac &= ~(~0 << (15+4)); - es1371_next_sample(es1371, 1); + es1371_next_sample_filtered(es1371, 1, es1371->dac[1].f_pos ? 16 : 0); + es1371->dac[1].f_pos = (es1371->dac[1].f_pos + 1) & 1; es1371->dac[1].curr_samp_ct++; if (es1371->dac[1].curr_samp_ct > es1371->dac[1].samp_ct) { - es1371->dac[1].curr_samp_ct = 0; +// es1371->dac[1].curr_samp_ct = 0; // audiopci_log("DAC2 IRQ\n"); es1371->int_status |= INT_STATUS_DAC2; es1371_update_irqs(es1371); } + if (es1371->dac[1].curr_samp_ct > es1371->dac[1].samp_ct) + es1371->dac[1].curr_samp_ct = 0; } } - - for (; es1371->pos < sound_pos_global; es1371->pos++) - { - int32_t l, r; - - l = (es1371->dac[0].out_l * es1371->dac[0].vol_l) >> 12; - l += ((es1371->dac[1].out_l * es1371->dac[1].vol_l) >> 12); - r = (es1371->dac[0].out_r * es1371->dac[0].vol_r) >> 12; - r += ((es1371->dac[1].out_r * es1371->dac[1].vol_r) >> 12); - - l >>= 1; - r >>= 1; - - l = (l * es1371->master_vol_l) >> 15; - r = (r * es1371->master_vol_r) >> 15; - - if (l < -32768) - l = -32768; - else if (l > 32767) - l = 32767; - if (r < -32768) - r = -32768; - else if (r > 32767) - r = 32767; - - es1371->buffer[es1371->pos*2] = l; - es1371->buffer[es1371->pos*2 + 1] = r; - } } static void es1371_get_buffer(int32_t *buffer, int len, void *p) @@ -1133,12 +1218,48 @@ static void es1371_get_buffer(int32_t *buffer, int len, void *p) es1371_t *es1371 = (es1371_t *)p; int c; + es1371_update(es1371); + for (c = 0; c < len * 2; c++) buffer[c] += (es1371->buffer[c] / 2); es1371->pos = 0; } +static inline double sinc(double x) +{ + return sin(M_PI * x) / (M_PI * x); +} + +static void generate_es1371_filter() +{ + /*Cutoff frequency = 1 / 32*/ + float fC = 1.0 / 32.0; + float gain; + int n; + + for (n = 0; n < ES1371_NCoef; n++) + { + /*Blackman window*/ + double w = 0.42 - (0.5 * cos((2.0*n*M_PI)/(double)(ES1371_NCoef-1))) + (0.08 * cos((4.0*n*M_PI)/(double)(ES1371_NCoef-1))); + /*Sinc filter*/ + double h = sinc(2.0 * fC * ((double)n - ((double)(ES1371_NCoef-1) / 2.0))); + + /*Create windowed-sinc filter*/ + low_fir_es1371_coef[n] = w * h; + } + + low_fir_es1371_coef[(ES1371_NCoef - 1) / 2] = 1.0; + + gain = 0.0; + for (n = 0; n < ES1371_NCoef; n++) + gain += low_fir_es1371_coef[n] / (float)N; + + /*Normalise filter, to produce unity gain*/ + for (n = 0; n < ES1371_NCoef; n++) + low_fir_es1371_coef[n] /= gain; +} + static void *es1371_init(const device_t *info) { es1371_t *es1371 = malloc(sizeof(es1371_t)); @@ -1149,6 +1270,8 @@ static void *es1371_init(const device_t *info) es1371->card = pci_add_card(PCI_ADD_NORMAL, es1371_pci_read, es1371_pci_write, es1371); timer_add(es1371_poll, &es1371->dac[1].time, TIMER_ALWAYS_ENABLED, es1371); + + generate_es1371_filter(); return es1371; } @@ -1166,6 +1289,54 @@ static void es1371_speed_changed(void *p) es1371->dac[1].latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); } + +void es1371_add_status_info_dac(es1371_t *es1371, char *s, int max_len, int dac_nr) +{ + int ena = dac_nr ? INT_DAC2_EN : INT_DAC1_EN; + char *dac_name = dac_nr ? "DAC2 (Wave)" : "DAC1 (MIDI)"; + char temps[128]; + + if (es1371->int_ctrl & ena) + { + int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3); + double freq = 48000.0 * ((double)es1371->dac[dac_nr].vf / (32768.0 * 16.0)); + + switch (format) + { + case FORMAT_MONO_8: + snprintf(temps, 128, "%s format : 8-bit mono\n", dac_name); + break; + case FORMAT_STEREO_8: + snprintf(temps, 128, "%s format : 8-bit stereo\n", dac_name); + break; + case FORMAT_MONO_16: + snprintf(temps, 128, "%s format : 16-bit mono\n", dac_name); + break; + case FORMAT_STEREO_16: + snprintf(temps, 128, "%s format : 16-bit stereo\n", dac_name); + break; + } + + strncat(s, temps, max_len); + max_len -= strlen(temps); + + snprintf(temps, 128, "Playback frequency : %i Hz\n", (int)freq); + strncat(s, temps, max_len); + } + else + { + snprintf(temps, max_len, "%s stopped\n", dac_name); + strncat(s, temps, max_len); + } +} + +void es1371_add_status_info(char *s, int max_len, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + es1371_add_status_info_dac(es1371, s, max_len, 0); + es1371_add_status_info_dac(es1371, s, max_len, 1); +} const device_t es1371_device = { @@ -1178,6 +1349,6 @@ const device_t es1371_device = NULL, es1371_speed_changed, NULL, - NULL, + es1371_add_status_info, NULL }; diff --git a/src/video/vid_ati18800.c b/src/video/vid_ati18800.c index f1f4576..54d41b8 100644 --- a/src/video/vid_ati18800.c +++ b/src/video/vid_ati18800.c @@ -8,7 +8,7 @@ * * ATI 18800 emulation (VGA Edge-16) * - * Version: @(#)vid_ati18800.c 1.0.3 2018/03/15 + * Version: @(#)vid_ati18800.c 1.0.4 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -51,6 +51,7 @@ #include "vid_ati18800.h" #include "vid_ati_eeprom.h" #include "vid_svga.h" +#include "vid_svga_render.h" #define BIOS_ROM_PATH_WONDER L"roms/video/ati/ati18800/vga_wonder_v3-1.02.bin" @@ -169,6 +170,39 @@ static uint8_t ati18800_in(uint16_t addr, void *p) case 0x3D5: temp = svga->crtc[svga->crtcreg]; break; + case 0x3DA: + svga->attrff = 0; + svga->attrff = 0; + svga->cgastat &= ~0x30; + /* copy color diagnostic info from the overscan color register */ + switch (svga->attrregs[0x12] & 0x30) + { + case 0x00: /* P0 and P2 */ + if (svga->attrregs[0x11] & 0x01) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x04) + svga->cgastat |= 0x20; + break; + case 0x10: /* P4 and P5 */ + if (svga->attrregs[0x11] & 0x10) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x20) + svga->cgastat |= 0x20; + break; + case 0x20: /* P1 and P3 */ + if (svga->attrregs[0x11] & 0x02) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x08) + svga->cgastat |= 0x20; + break; + case 0x30: /* P6 and P7 */ + if (svga->attrregs[0x11] & 0x40) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x80) + svga->cgastat |= 0x20; + break; + } + return svga->cgastat; default: temp = svga_in(addr, svga); break; @@ -179,6 +213,28 @@ static uint8_t ati18800_in(uint16_t addr, void *p) return temp; } +static void ati18800_recalctimings(svga_t *svga) +{ + ati18800_t *ati18800 = (ati18800_t *)svga->p; + + if(svga->crtc[0x17] & 4) + { + svga->vtotal <<= 1; + svga->dispend <<= 1; + svga->vsyncstart <<= 1; + svga->split <<= 1; + svga->vblankstart <<= 1; + } + + if (!svga->scrblank && (ati18800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + { + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + svga->rowoffset <<= 1; + svga->ma <<= 1; + } +} + static void *ati18800_init(const device_t *info) { ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); @@ -198,7 +254,7 @@ static void *ati18800_init(const device_t *info) }; svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ - NULL, + ati18800_recalctimings, ati18800_in, ati18800_out, NULL, NULL); diff --git a/src/video/vid_ati28800.c b/src/video/vid_ati28800.c index af7d1eb..2894c88 100644 --- a/src/video/vid_ati28800.c +++ b/src/video/vid_ati28800.c @@ -8,7 +8,7 @@ * * ATI 28800 emulation (VGA Charger and Korean VGA) * - * Version: @(#)vid_ati28800.c 1.0.6 2018/03/15 + * Version: @(#)vid_ati28800.c 1.0.7 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -268,6 +268,39 @@ static uint8_t ati28800_in(uint16_t addr, void *p) case 0x3D5: temp = svga->crtc[svga->crtcreg]; break; + case 0x3DA: + svga->attrff = 0; + svga->attrff = 0; + svga->cgastat &= ~0x30; + /* copy color diagnostic info from the overscan color register */ + switch (svga->attrregs[0x12] & 0x30) + { + case 0x00: /* P0 and P2 */ + if (svga->attrregs[0x11] & 0x01) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x04) + svga->cgastat |= 0x20; + break; + case 0x10: /* P4 and P5 */ + if (svga->attrregs[0x11] & 0x10) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x20) + svga->cgastat |= 0x20; + break; + case 0x20: /* P1 and P3 */ + if (svga->attrregs[0x11] & 0x02) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x08) + svga->cgastat |= 0x20; + break; + case 0x30: /* P6 and P7 */ + if (svga->attrregs[0x11] & 0x40) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x80) + svga->cgastat |= 0x20; + break; + } + return svga->cgastat; default: temp = svga_in(addr, svga); break; @@ -295,7 +328,7 @@ static uint8_t ati28800k_in(uint16_t addr, void *p) switch(get_korean_font_kind >> 8) { case 4: /* ROM font */ - temp = fontdatksc5601[get_korean_font_base][get_korean_font_index++]; + temp = fontdatksc5601[get_korean_font_base].chr[get_korean_font_index++]; break; case 2: /* User defined font - TODO : Should be implemented later */ temp = 0; diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index cc26c97..df956eb 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -8,7 +8,7 @@ * * ATi Mach64 graphics card emulation. * - * Version: @(#)vid_ati_mach64.c 1.0.6 2018/03/15 + * Version: @(#)vid_ati_mach64.c 1.0.7 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -194,6 +194,7 @@ typedef struct mach64_t uint32_t linear_base, old_linear_base; uint32_t io_base; + int draw_pixel; struct { @@ -310,6 +311,7 @@ enum { SRC_PATT_EN = 1, SRC_PATT_ROT_EN = 2, + SRC_BYTE_ALIGN = 3, SRC_LINEAR_EN = 4 }; @@ -449,6 +451,39 @@ uint8_t mach64_in(uint16_t addr, void *p) if (svga->crtcreg > 0x18) return 0xff; return svga->crtc[svga->crtcreg]; + case 0x3DA: + svga->attrff = 0; + svga->attrff = 0; + svga->cgastat &= ~0x30; + /* copy color diagnostic info from the overscan color register */ + switch (svga->attrregs[0x12] & 0x30) + { + case 0x00: /* P0 and P2 */ + if (svga->attrregs[0x11] & 0x01) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x04) + svga->cgastat |= 0x20; + break; + case 0x10: /* P4 and P5 */ + if (svga->attrregs[0x11] & 0x10) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x20) + svga->cgastat |= 0x20; + break; + case 0x20: /* P1 and P3 */ + if (svga->attrregs[0x11] & 0x02) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x08) + svga->cgastat |= 0x20; + break; + case 0x30: /* P6 and P7 */ + if (svga->attrregs[0x11] & 0x40) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x80) + svga->cgastat |= 0x20; + break; + } + return svga->cgastat; } return svga_in(addr, svga); } @@ -476,36 +511,41 @@ void mach64_recalctimings(svga_t *svga) svga->render = mach64->ramdac.render; switch ((mach64->crtc_gen_cntl >> 8) & 7) { - case 1: + case 1: + mach64->draw_pixel = 4; if (mach64->type != MACH64_GX) - svga->render = svga_render_4bpp_highres; + svga->render = svga_render_4bpp_highres; svga->hdisp *= 8; break; - case 2: + case 2: + mach64->draw_pixel = 8; if (mach64->type != MACH64_GX) - svga->render = svga_render_8bpp_highres; + svga->render = svga_render_8bpp_highres; svga->hdisp *= 8; svga->rowoffset /= 2; break; - case 3: + case 3: + mach64->draw_pixel = 16; if (mach64->type != MACH64_GX) - svga->render = svga_render_15bpp_highres; + svga->render = svga_render_15bpp_highres; svga->hdisp *= 8; break; - case 4: + case 4: + mach64->draw_pixel = 16; if (mach64->type != MACH64_GX) - svga->render = svga_render_16bpp_highres; + svga->render = svga_render_16bpp_highres; svga->hdisp *= 8; break; - case 5: + case 5: if (mach64->type != MACH64_GX) - svga->render = svga_render_24bpp_highres; + svga->render = svga_render_24bpp_highres; svga->hdisp *= 8; svga->rowoffset = (svga->rowoffset * 3) / 2; break; - case 6: + case 6: + mach64->draw_pixel = 32; if (mach64->type != MACH64_GX) - svga->render = svga_render_32bpp_highres; + svga->render = svga_render_32bpp_highres; svga->hdisp *= 8; svga->rowoffset *= 2; break; @@ -663,11 +703,7 @@ static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val (addr & 0x3ff) == 0x113) && !(val & 0x80)) { mach64_start_fill(mach64); -#ifdef MACH64_DEBUG - pclog("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), - ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), - (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src); -#endif + if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) @@ -971,7 +1007,7 @@ void mach64_cursor_dump(mach64_t *mach64) void mach64_start_fill(mach64_t *mach64) { int x, y; - + mach64->accel.dst_x = 0; mach64->accel.dst_y = 0; mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff; @@ -980,19 +1016,26 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; +/* + if ((((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC)) + { + pclog("Byte Align set=%02x\n", mach64->dp_pix_width & DP_BYTE_PIX_ORDER); + } +*/ + if (((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC) { - if (mach64->accel.dst_width & 7) + if (mach64->accel.dst_width & 7) mach64->accel.dst_width = (mach64->accel.dst_width & ~7) + 8; } - mach64->accel.x_count = mach64->accel.dst_width; + mach64->accel.x_count = mach64->accel.dst_width; - mach64->accel.src_x = 0; + mach64->accel.src_x = 0; mach64->accel.src_y = 0; mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; mach64->accel.src_y_start = mach64->src_y_x & 0xfff; - if (mach64->src_cntl & SRC_LINEAR_EN) + if (mach64->src_cntl & (SRC_LINEAR_EN|SRC_BYTE_ALIGN)) mach64->accel.src_x_count = 0x7ffffff; /*Essentially infinite*/ else mach64->accel.src_x_count = (mach64->src_height1_width1 >> 16) & 0x7fff; @@ -1002,36 +1045,27 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.src_y_count = mach64->src_height1_width1 & 0x1fff; mach64->accel.src_width1 = (mach64->src_height1_width1 >> 16) & 0x7fff; - mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; + mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff; - mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; + mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; -#ifdef MACH64_DEBUG - pclog("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count, - mach64->accel.src_y_count, - mach64->accel.src_width1, - mach64->accel.src_height1, - mach64->src_height1_width1, - mach64->src_height2_width2); -#endif - mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; - mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; - + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; mach64->accel.mix_bg = mach64->dp_mix & 0x1f; - + mach64->accel.source_bg = mach64->dp_src & 7; mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; - + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; - + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; @@ -1040,18 +1074,17 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.src_offset <<= 3; else mach64->accel.src_offset >>= mach64->accel.src_size; - + if (mach64->accel.dst_size == WIDTH_1BIT) mach64->accel.dst_offset <<= 3; else mach64->accel.dst_offset >>= mach64->accel.dst_size; - + mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; - mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; - + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); - - + for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) @@ -1060,36 +1093,30 @@ void mach64_start_fill(mach64_t *mach64) mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; } } - + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; -/* mach64->accel.sc_left *= mach64_inc[mach64->accel.dst_pix_width]; - mach64->accel.sc_right *= mach64_inc[mach64->accel.dst_pix_width];*/ - mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; - mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); - + mach64->accel.poly_draw = 0; - + mach64->accel.busy = 1; -#ifdef MACH64_DEBUG - pclog("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); -#endif mach64->accel.op = OP_RECT; } void mach64_start_line(mach64_t *mach64) { int x, y; - + mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff; mach64->accel.dst_y = mach64->dst_y_x & 0xfff; @@ -1101,37 +1128,34 @@ void mach64_start_line(mach64_t *mach64) mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; - + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; mach64->accel.mix_bg = mach64->dp_mix & 0x1f; - + mach64->accel.source_bg = mach64->dp_src & 7; mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; - + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; - + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; - + if (mach64->accel.src_size == WIDTH_1BIT) mach64->accel.src_offset <<= 3; else mach64->accel.src_offset >>= mach64->accel.src_size; - + if (mach64->accel.dst_size == WIDTH_1BIT) mach64->accel.dst_offset <<= 3; else mach64->accel.dst_offset >>= mach64->accel.dst_size; -/* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; - mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ - mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); - + for (y = 0; y < 8; y++) { for (x = 0; x < 8; x++) @@ -1140,41 +1164,43 @@ void mach64_start_line(mach64_t *mach64) mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; } } - + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; - + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; - mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; - + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + mach64->accel.x_count = mach64->dst_bres_lnth & 0x7fff; mach64->accel.err = (mach64->dst_bres_err & 0x3ffff) | ((mach64->dst_bres_err & 0x40000) ? 0xfffc0000 : 0); - + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); mach64->accel.busy = 1; -#ifdef MACH64_DEBUG - pclog("mach64_start_line\n"); -#endif mach64->accel.op = OP_LINE; } -#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ - else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ - else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ - else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; \ - else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; +#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ + else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ + else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ + else \ + { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (((addr) & 7))) & 1; \ + else \ + dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; \ + } #define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ { \ case 0x0: dest_dat = ~dest_dat; break; \ case 0x1: dest_dat = 0; break; \ - case 0x2: dest_dat = 0xffffffff; break; \ + case 0x2: dest_dat = ~0; break; \ case 0x3: dest_dat = dest_dat; break; \ case 0x4: dest_dat = ~src_dat; break; \ case 0x5: dest_dat = src_dat ^ dest_dat; break; \ @@ -1207,17 +1233,10 @@ void mach64_start_line(mach64_t *mach64) } \ else \ { \ - if (dest_dat & 1) { \ - if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ - svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \ - else \ - svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (7 - ((addr) & 7)); \ - } else { \ - if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ - svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \ - else \ - svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (7 - ((addr) & 7)));\ - } \ + if (dest_dat & 1) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (((addr) & 7)); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (((addr) & 7))); \ svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \ } @@ -1225,7 +1244,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) { svga_t *svga = &mach64->svga; int cmp_clr = 0; - + if (!mach64->accel.busy) { #ifdef MACH64_DEBUG @@ -1245,7 +1264,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; int src_x; int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff; - + if (mach64->src_cntl & SRC_LINEAR_EN) src_x = mach64->accel.src_x; else @@ -1293,20 +1312,17 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mix = 1; break; case MONO_SRC_BLITSRC: - if (mach64->src_cntl & SRC_LINEAR_EN) - { - READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); - } - else - { - READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); - } + if (mach64->src_cntl & SRC_LINEAR_EN) { + READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); + } else { + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); + } break; } if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right && dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom) - { + { switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) { case SRC_HOST: @@ -1348,20 +1364,20 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; break; } - + if (!cmp_clr) MIX WRITE(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, mach64->accel.dst_size); } } - + if (mach64->dst_cntl & DST_24_ROT_EN) { mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16); mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16); } - + mach64->accel.src_x += mach64->accel.xinc; mach64->accel.dst_x += mach64->accel.xinc; if (!(mach64->src_cntl & SRC_LINEAR_EN)) @@ -1379,9 +1395,9 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mach64->accel.src_x_count = mach64->accel.src_width1; } } - + mach64->accel.x_count--; - + if (mach64->accel.x_count <= 0) { mach64->accel.x_count = mach64->accel.dst_width; @@ -1393,7 +1409,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) if (!(mach64->src_cntl & SRC_LINEAR_EN)) { mach64->accel.src_x = 0; - mach64->accel.src_y += mach64->accel.yinc; + mach64->accel.src_y += mach64->accel.yinc; mach64->accel.src_y_count--; if (mach64->accel.src_y_count <= 0) { @@ -1411,13 +1427,10 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) mach64->accel.poly_draw = 0; mach64->accel.dst_height--; - + if (mach64->accel.dst_height <= 0) { /*Blit finished*/ -#ifdef MACH64_DEBUG - pclog("mach64 blit finished\n"); -#endif mach64->accel.busy = 0; if (mach64->dst_cntl & DST_X_TILE) mach64->dst_y_x = (mach64->dst_y_x & 0xfff) | ((mach64->dst_y_x + (mach64->accel.dst_width << 16)) & 0xfff0000); @@ -1437,7 +1450,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) } } } - } + } break; case OP_LINE: @@ -1447,7 +1460,7 @@ void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) uint32_t host_dat = 0; int mix = 0; int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); - + if (mach64->accel.source_host) { host_dat = cpu_dat; diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index d2e67c1..99e95c0 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.8 2018/03/15 + * Version: @(#)vid_cl54xx.c 1.0.9 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -60,8 +60,8 @@ #define BIOS_GD5424_PATH L"roms/video/cirruslogic/cl5424.bin" -#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.bin" -#define BIOS_GD5428_VLB_PATH L"roms/video/cirruslogic/diamond speedstar pro vlb (cirrus logic 5428)_V3.04.bin" +#define BIOS_GD5426_PATH L"roms/video/cirruslogic/diamond speedstar pro vlb v3.04.bin" +#define BIOS_GD5428_PATH L"roms/video/cirruslogic/vlbusjapan.bin" #define BIOS_GD5429_PATH L"roms/video/cirruslogic/5429.vbi" #define BIOS_GD5430_VLB_PATH L"roms/video/cirruslogic/diamondvlbus.bin" #define BIOS_GD5430_PCI_PATH L"roms/video/cirruslogic/pci.bin" @@ -69,6 +69,7 @@ #define BIOS_GD5436_PATH L"roms/video/cirruslogic/5436.vbi" #define CIRRUS_ID_CLGD5424 0x94 +#define CIRRUS_ID_CLGD5426 0x90 #define CIRRUS_ID_CLGD5428 0x98 #define CIRRUS_ID_CLGD5429 0x9c #define CIRRUS_ID_CLGD5430 0xa0 @@ -97,9 +98,13 @@ #define CIRRUS_BUSTYPE_VLBSLOW 0x30 #define CIRRUS_BUSTYPE_ISA 0x38 #define CIRRUS_MMIO_ENABLE 0x04 -#define CIRRUS_MMIO_USE_PCIADDR 0x40 // 0xb8000 if cleared. +#define CIRRUS_MMIO_USE_PCIADDR 0x40 /* 0xb8000 if cleared. */ #define CIRRUS_MEMSIZEEXT_DOUBLE 0x80 +/* control 0x0b */ +#define CIRRUS_BANKING_DUAL 0x01 +#define CIRRUS_BANKING_GRANULARITY_16K 0x20 /* set:16k, clear:4k */ + /* control 0x30 */ #define CIRRUS_BLTMODE_BACKWARDS 0x01 #define CIRRUS_BLTMODE_MEMSYSDEST 0x02 @@ -113,7 +118,14 @@ #define CIRRUS_BLTMODE_PIXELWIDTH24 0x20 #define CIRRUS_BLTMODE_PIXELWIDTH32 0x30 -// control 0x33 +/* control 0x31 */ +#define CIRRUS_BLT_BUSY 0x01 +#define CIRRUS_BLT_START 0x02 +#define CIRRUS_BLT_RESET 0x04 +#define CIRRUS_BLT_FIFOUSED 0x10 +#define CIRRUS_BLT_AUTOSTART 0x80 + +/* control 0x33 */ #define CIRRUS_BLTMODEEXT_SOLIDFILL 0x04 #define CIRRUS_BLTMODEEXT_COLOREXPINV 0x02 #define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 @@ -139,22 +151,22 @@ typedef struct gd54xx_t uint32_t vram_mask; uint8_t vclk_n[4]; - uint8_t vclk_d[4]; + uint8_t vclk_d[4]; uint32_t bank[2]; struct { uint8_t state; int ctrl; - } ramdac; - + } ramdac; + struct { uint32_t fg_col, bg_col; uint16_t width, height; - uint16_t dst_pitch, src_pitch; + uint16_t dst_pitch, src_pitch; uint32_t dst_addr, src_addr; uint8_t mask, mode, rop; uint8_t modeext; - uint8_t bltstart; + uint8_t status; uint16_t trans_col, trans_mask; uint32_t dst_addr_backup, src_addr_backup; @@ -167,15 +179,15 @@ typedef struct gd54xx_t uint16_t pixel_cnt; uint16_t scan_cnt; } blt; - - int pci, vlb; - + + int pci, vlb; + uint8_t pci_regs[256]; uint8_t int_line; int card; - + uint32_t lfb_base; - + int mmio_vram_overlap; } gd54xx_t; @@ -219,7 +231,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if (svga->seqaddr > 5) { svga->seqregs[svga->seqaddr & 0x1f] = val; switch (svga->seqaddr & 0x1f) { - case 6: /* cirrus unlock extensions */ + case 6: val &= 0x17; if (val == 0x12) svga->seqregs[6] = 0x12; @@ -234,17 +246,25 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) break; case 0x10: case 0x30: case 0x50: case 0x70: case 0x90: case 0xb0: case 0xd0: case 0xf0: - svga->hwcursor.x = (val << 3) | ((svga->seqaddr >> 5) & 7); + svga->hwcursor.x = (val << 3) | (svga->seqaddr >> 5); break; case 0x11: case 0x31: case 0x51: case 0x71: case 0x91: case 0xb1: case 0xd1: case 0xf1: - svga->hwcursor.y = (val << 3) | ((svga->seqaddr >> 5) & 7); + svga->hwcursor.y = (val << 3) | (svga->seqaddr >> 5); break; case 0x12: - svga->hwcursor.ena = val & 1; + svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; + svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; + if (val & CIRRUS_CURSOR_LARGE) + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); + else + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((svga->seqregs[0x13] & 0x3f) * 256)); break; case 0x13: - svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3f) * 256)); + if (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3c) * 256)); + else + svga->hwcursor.addr = (((gd54xx->vram_size<<20)-0x4000) + ((val & 0x3f) * 256)); break; case 0x07: svga->set_reset_disabled = svga->seqregs[7] & 1; @@ -414,8 +434,7 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) val = (svga->crtc[7] & ~0x10) | (val & 0x10); old = svga->crtc[svga->crtcreg]; - if ((svga->crtcreg != 0x27) && (svga->crtcreg != 0x28)) - svga->crtc[svga->crtcreg] = val; + svga->crtc[svga->crtcreg] = val; if (old != val) { if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { @@ -441,18 +460,31 @@ gd54xx_in(uint16_t addr, void *p) addr ^= 0x60; switch (addr) { + case 0x3c4: + if ((svga->seqregs[6] & 0x17) == 0x12) + { + temp = svga->seqaddr; + if ((temp & 0x1e) == 0x10) + { + if (temp & 1) + temp = ((svga->hwcursor.y & 7) << 5) | 0x11; + else + temp = ((svga->hwcursor.x & 7) << 5) | 0x10; + } + return temp; + } + return svga->seqaddr; + case 0x3c5: if (svga->seqaddr > 5) { switch (svga->seqaddr) { case 6: - return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; + return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; case 0x0b: case 0x0c: case 0x0d: case 0x0e: return gd54xx->vclk_n[svga->seqaddr-0x0b]; - case 0x0f: - return svga->seqregs[0x0f]; case 0x17: temp = svga->gdcreg[0x17] & ~(7 << 3); - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5430) { + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { if (gd54xx->vlb) temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); else @@ -468,8 +500,6 @@ gd54xx_in(uint16_t addr, void *p) return temp; case 0x1b: case 0x1c: case 0x1d: case 0x1e: return gd54xx->vclk_d[svga->seqaddr-0x1b]; - case 0x1f: - return svga->seqregs[0x1f]; } return svga->seqregs[svga->seqaddr & 0x3f]; } @@ -493,7 +523,7 @@ gd54xx_in(uint16_t addr, void *p) case 0x24: /*Attribute controller toggle readback (R)*/ return svga->attrff << 7; case 0x26: /*Attribute controller index readback (R)*/ - return svga->attraddr & 0x3f; + return svga->attraddr & 0x3f; case 0x27: /*ID*/ return svga->crtc[0x27]; /*GD542x/GD543x*/ case 0x28: /*Class ID*/ @@ -512,13 +542,13 @@ gd54xx_recalc_banking(gd54xx_t *gd54xx) { svga_t *svga = &gd54xx->svga; - if (svga->gdcreg[0xb] & 0x20) + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) gd54xx->bank[0] = svga->gdcreg[0x09] << 14; else gd54xx->bank[0] = svga->gdcreg[0x09] << 12; - if (svga->gdcreg[0xb] & 0x01) { - if (svga->gdcreg[0xb] & 0x20) + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_DUAL) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) gd54xx->bank[1] = svga->gdcreg[0x0a] << 14; else gd54xx->bank[1] = svga->gdcreg[0x0a] << 12; @@ -543,7 +573,7 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) if (!(svga->seqregs[7] & 0xf0)) { mem_mapping_disable(&gd54xx->linear_mapping); - switch (svga->gdcreg[6] & 0x0C) { + switch (svga->gdcreg[6] & 0x0c) { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); svga->banked_mask = 0xffff; @@ -554,12 +584,10 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) break; case 0x8: /*32k at B0000*/ mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); - mem_mapping_disable(&gd54xx->mmio_mapping); svga->banked_mask = 0x7fff; break; case 0xC: /*32k at B8000*/ mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); - mem_mapping_disable(&gd54xx->mmio_mapping); svga->banked_mask = 0x7fff; gd54xx->mmio_vram_overlap = 1; break; @@ -572,7 +600,7 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) uint32_t base, size; if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { - if (svga->gdcreg[0xb] & 0x20) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { base = (svga->seqregs[7] & 0xf0) << 16; size = 1 * 1024 * 1024; } else { @@ -597,7 +625,7 @@ gd543x_recalc_mapping(gd54xx_t *gd54xx) mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); svga->linear_base = base; if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { - if (svga->seqregs[0x17] & 0x40) { + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) { if (size >= (4 * 1024 * 1024)) mem_mapping_disable(&gd54xx->mmio_mapping); /* MMIO is handled in the linear read/write functions */ else { @@ -622,45 +650,85 @@ gd54xx_recalctimings(svga_t *svga) svga->interlace = (svga->crtc[0x1a] & 0x01); - if (svga->seqregs[7] & 0x01) { - svga->render = svga_render_8bpp_highres; - svga->bpp = 8; - } else if (svga->gdcreg[5] & 0x40) { - svga->render = svga_render_8bpp_lowres; - svga->bpp = 8; - } - svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); - if (gd54xx->ramdac.ctrl & 0x80) { - if (gd54xx->ramdac.ctrl & 0x40) { - switch (gd54xx->ramdac.ctrl & 0xf) { - case 0x0: - svga->render = svga_render_15bpp_highres; - svga->bpp = 15; - break; - case 0x1: - svga->render = svga_render_16bpp_highres; - svga->bpp = 16; - break; - case 0x5: - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) && (svga->seqregs[7] & 8)) { - svga->render = svga_render_32bpp_highres; - svga->bpp = 32; - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) - svga->rowoffset *= 2; - } else { - svga->render = svga_render_24bpp_highres; - svga->bpp = 24; - } - break; - } - } else { - svga->render = svga_render_15bpp_highres; - svga->bpp = 15; + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) + { + svga->bpp = 8; + svga->render = svga_render_8bpp_highres; + } + else if (svga->gdcreg[5] & 0x40) + { + svga->bpp = 8; + svga->render = svga_render_8bpp_lowres; } - } + if (gd54xx->ramdac.ctrl & 0x80) + { + if (gd54xx->ramdac.ctrl & 0x40) + { + switch (gd54xx->ramdac.ctrl & 0xf) + { + case 0: + svga->bpp = 15; + svga->render = svga_render_15bpp_highres; + break; + + case 1: + svga->bpp = 16; + svga->render = svga_render_16bpp_highres; + break; + + case 5: + if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) && (svga->seqregs[7] & CIRRUS_SR7_BPP_32)) + { + svga->bpp = 32; + svga->render = svga_render_32bpp_highres; + if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + svga->rowoffset *= 2; + } + else + { + svga->bpp = 24; + svga->render = svga_render_24bpp_highres; + } + break; + + case 0xf: + switch (svga->seqregs[7] & CIRRUS_SR7_BPP_MASK) + { + case CIRRUS_SR7_BPP_32: + svga->bpp = 32; + svga->render = svga_render_32bpp_highres; + svga->rowoffset *= 2; + break; + + case CIRRUS_SR7_BPP_24: + svga->bpp = 24; + svga->render = svga_render_24bpp_highres; + break; + + case CIRRUS_SR7_BPP_16: + case CIRRUS_SR7_BPP_16_DOUBLEVCLK: + svga->bpp = 16; + svga->render = svga_render_16bpp_highres; + break; + + case CIRRUS_SR7_BPP_8: + svga->bpp = 8; + svga->render = svga_render_8bpp_highres; + break; + } + break; + } + } + else + { + svga->bpp = 15; + svga->render = svga_render_15bpp_highres; + } + } + clocksel = (svga->miscout >> 2) & 3; if (!gd54xx->vclk_n[clocksel] || !gd54xx->vclk_d[clocksel]) @@ -676,7 +744,7 @@ gd54xx_recalctimings(svga_t *svga) freq /= 2.0; break; case 4: - if (svga->crtc[0x27] < CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5434) freq /= 3.0; break; } @@ -687,46 +755,51 @@ gd54xx_recalctimings(svga_t *svga) } -static void -gd54xx_hwcursor_draw(svga_t *svga, int displine) +static +void gd54xx_hwcursor_draw(svga_t *svga, int displine) { - int x; - uint8_t dat[2]; - int xx; - int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int largecur = (svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE); - int cursize = (largecur) ? 64 : 32; - int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; - int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; - - if (svga->interlace && svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 4; - - for (x = 0; x < cursize; x += 8) { - dat[0] = svga->vram[svga->hwcursor_latch.addr]; - dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; - for (xx = 0; xx < 8; xx++) { - if (offset >= svga->hwcursor_latch.x) { - if (dat[1] & 0x80) - ((uint32_t *)buffer32->line[displine + y_add])[offset + cursize + x_add] = 0; - if (dat[0] & 0x80) - ((uint32_t *)buffer32->line[displine + y_add])[offset + cursize + x_add] ^= 0xffffff; - } + int x; + uint8_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + for (x = 0; x < svga->hwcursor.xsize; x += 8) { + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + if (svga->hwcursor.xsize == 64) + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + else + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) { + if (offset >= svga->hwcursor_latch.x) { + if (dat[1] & 0x80) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = 0; + if (dat[0] & 0x80) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + } - offset++; - dat[0] <<= 1; - dat[1] <<= 1; + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr++; } - svga->hwcursor_latch.addr++; - } - - if (svga->interlace && !svga->hwcursor_oddeven) - svga->hwcursor_latch.addr += 4; + + if (svga->hwcursor.xsize == 64) + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; } static void -gd5428_copy_pixel(gd54xx_t *gd54xx, svga_t *svga, uint8_t src, uint8_t dst) +gd54xx_memsrc_rop(gd54xx_t *gd54xx, svga_t *svga, uint8_t src, uint8_t dst) { uint8_t res = src; svga->changedvram[(gd54xx->blt.dst_addr_backup & svga->vram_mask) >> 12] = changeframecount; @@ -771,7 +844,7 @@ gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) for (x=0;x<32;x+=8) { pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) - gd5428_copy_pixel(gd54xx, svga, pixel, svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); + gd54xx_memsrc_rop(gd54xx, svga, pixel, svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask]); gd54xx->blt.dst_addr_backup++; gd54xx->blt.pixel_cnt++; } @@ -1143,7 +1216,7 @@ gd54xx_readb_linear(uint32_t addr, void *p) } if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) return gd543x_mmio_read(addr & 0x000000ff, gd54xx); } @@ -1163,7 +1236,7 @@ gd54xx_readw_linear(uint32_t addr, void *p) addr &= 0x003fffff; /* 4 MB mask */ if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { if (ap == 2) addr ^= 0x00000002; @@ -1219,7 +1292,7 @@ gd54xx_readl_linear(uint32_t addr, void *p) addr &= 0x003fffff; /* 4 MB mask */ if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); switch(ap) { @@ -1306,7 +1379,7 @@ gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) } if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); } @@ -1340,7 +1413,7 @@ gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) uint16_t temp; if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { switch(ap) { case 0: default: @@ -1414,7 +1487,7 @@ gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) uint32_t temp; if ((addr & 0x003fff00) == 0x003fff00) { - if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & 0x40)) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { switch(ap) { case 0: default: @@ -1540,7 +1613,7 @@ gd54xx_readl(uint32_t addr, void *p) static int gd543x_do_mmio(svga_t *svga, uint32_t addr) { - if (svga->seqregs[0x17] & 0x40) + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) return 1; else return ((addr & ~0xff) == 0xb8000); @@ -1640,7 +1713,7 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) else gd54xx->blt.dst_addr &= 0x1fffff; - if ((svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) && (gd54xx->blt.bltstart & 0x80)) { + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5436) && (gd54xx->blt.status & CIRRUS_BLT_AUTOSTART)) { if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { gd54xx->blt.sys_tx = 1; gd54xx->blt.sys_cnt = 0; @@ -1679,7 +1752,7 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) break; case 0x1b: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) gd54xx->blt.modeext = val; break; @@ -1700,8 +1773,8 @@ gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) break; case 0x40: - gd54xx->blt.bltstart = val; - if (gd54xx->blt.bltstart & 0x02) { + gd54xx->blt.status = val; + if (gd54xx->blt.status & CIRRUS_BLT_START) { if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { gd54xx->blt.sys_tx = 1; gd54xx->blt.sys_cnt = 0; @@ -1819,20 +1892,8 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) blt_mask *= 2; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) - { - x_max = 24; - if (gd54xx->blt.mode & CIRRUS_BLTMODE_PATTERNCOPY) - { - blt_mask = (gd54xx->blt.mask & 0x1f); - blt_mask /= 3; - } - else - { - blt_mask = gd54xx->blt.mask & 7; - blt_mask *= 3; - } - } + blt_mask = (gd54xx->blt.mask & 0x1f); + x_max = 24; break; case CIRRUS_BLTMODE_PIXELWIDTH32: blt_mask = gd54xx->blt.mask & 7; @@ -1873,7 +1934,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); + mem_mapping_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); mem_mapping_set_p(&gd54xx->linear_mapping, svga); } gd543x_recalc_mapping(gd54xx); @@ -1912,19 +1973,16 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) } break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if ((gd54xx->blt.x_count % 3) == 2) + src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); + else if ((gd54xx->blt.x_count % 3) == 1) + src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); + else + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; + if ((gd54xx->blt.x_count % 3) == 2) { - if ((gd54xx->blt.x_count % 3) == 2) - src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); - else if ((gd54xx->blt.x_count % 3) == 1) - src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); - else - src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; - if ((gd54xx->blt.x_count % 3) == 2) - { - cpu_dat <<= 1; - count--; - } + cpu_dat <<= 1; + count--; } break; case CIRRUS_BLTMODE_PIXELWIDTH32: @@ -1961,9 +2019,7 @@ 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 & ~3)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - pclog("Pattern copy\n"); - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) - 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 & ~3)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count % 24)]; 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)]; @@ -1986,20 +2042,19 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) - { - mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); - if ((gd54xx->blt.dst_addr % 3) == 2) - src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); - else if ((gd54xx->blt.dst_addr % 3) == 1) - src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); - else - src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; - } + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); + if ((gd54xx->blt.dst_addr % 3) == 2) + src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); + else if ((gd54xx->blt.dst_addr % 3) == 1) + src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); + else + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH32: mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); - if ((gd54xx->blt.dst_addr & 3) == 2) + if ((gd54xx->blt.dst_addr & 3) == 3) + src = mask ? (gd54xx->blt.fg_col >> 24) : (gd54xx->blt.bg_col >> 24); + else if ((gd54xx->blt.dst_addr & 3) == 2) src = mask ? (gd54xx->blt.fg_col >> 16) : (gd54xx->blt.bg_col >> 16); else if ((gd54xx->blt.dst_addr & 3) == 1) src = mask ? (gd54xx->blt.fg_col >> 8) : (gd54xx->blt.bg_col >> 8); @@ -2059,7 +2114,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; break; case CIRRUS_BLTMODE_PIXELWIDTH24: - if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + if (svga->crtc[0x27] == CIRRUS_ID_CLGD5436) { mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); if ((gd54xx->blt.dst_addr % 3) == 2) @@ -2126,7 +2181,9 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); gd54xx->blt.x_count++; - if (gd54xx->blt.x_count == x_max) { + + if (gd54xx->blt.x_count == x_max) + { gd54xx->blt.x_count = 0; if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == CIRRUS_BLTMODE_COLOREXPAND) gd54xx->blt.src_addr++; @@ -2166,7 +2223,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) } else { - mem_mapping_set_handler(&gd54xx->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); + mem_mapping_set_handler(&gd54xx->linear_mapping, svga_readb_linear, svga_readw_linear, svga_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear); mem_mapping_set_p(&gd54xx->linear_mapping, svga); } gd543x_recalc_mapping(gd54xx); @@ -2192,16 +2249,10 @@ cl_pci_read(int func, int addr, void *p) case 0x01: return 0x10; case 0x02: - switch (svga->crtc[0x27]) { - case CIRRUS_ID_CLGD5430: - return 0xa0; - case CIRRUS_ID_CLGD5434: - return 0xa8; - case CIRRUS_ID_CLGD5436: - return 0xac; - } - return 0xff; + return svga->crtc[0x27]; + case 0x03: return 0x00; + case PCI_REG_COMMAND: return gd54xx->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ @@ -2218,10 +2269,10 @@ cl_pci_read(int func, int addr, void *p) case 0x12: return 0x00; case 0x13: return gd54xx->lfb_base >> 24; - case 0x30: return (gd54xx->has_bios) ? (gd54xx->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ + case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ case 0x31: return 0x00; - case 0x32: return (gd54xx->has_bios) ? gd54xx->pci_regs[0x32] : 0x00; - case 0x33: return (gd54xx->has_bios) ? gd54xx->pci_regs[0x33] : 0x00; + case 0x32: return gd54xx->pci_regs[0x32]; + case 0x33: return gd54xx->pci_regs[0x33]; case 0x3c: return gd54xx->int_line; case 0x3d: return PCI_INTA; @@ -2250,8 +2301,6 @@ cl_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x30: case 0x32: case 0x33: - if (!(gd54xx->has_bios)) - return; gd54xx->pci_regs[addr] = val; if (gd54xx->pci_regs[0x30] & 0x01) { uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); @@ -2272,21 +2321,20 @@ gd54xx_init(const device_t *info) { gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); svga_t *svga = &gd54xx->svga; - int id = info->local & 0x7FFF; + int id = info->local; wchar_t *romfn = NULL; memset(gd54xx, 0, sizeof(gd54xx_t)); - gd54xx->has_bios = !(info->local & 0x8000); - gd54xx->pci = !!(info->flags & DEVICE_PCI); gd54xx->vlb = !!(info->flags & DEVICE_VLB); switch (id) { + case CIRRUS_ID_CLGD5426: + romfn = BIOS_GD5426_PATH; + break; + case CIRRUS_ID_CLGD5428: - if (gd54xx->vlb) - romfn = BIOS_GD5428_VLB_PATH; - else - romfn = BIOS_GD5428_ISA_PATH; + romfn = BIOS_GD5428_PATH; break; case CIRRUS_ID_CLGD5429: @@ -2312,7 +2360,6 @@ gd54xx_init(const device_t *info) gd54xx->vram_size = device_get_config_int("memory"); gd54xx->vram_mask = (gd54xx->vram_size << 20) - 1; - if (gd54xx->has_bios) rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, @@ -2327,23 +2374,6 @@ gd54xx_init(const device_t *info) io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); - svga->decode_mask = (4 << 20) - 1; - - switch (gd54xx->vram_size) { - case 1: /*1MB*/ - svga->vram_mask = (1 << 20) - 1; - svga->vram_max = 1 << 20; - break; - case 2: /*2MB*/ - svga->vram_mask = (2 << 20) - 1; - svga->vram_max = 2 << 20; - break; - case 4: /*4MB*/ - svga->vram_mask = (4 << 20) - 1; - svga->vram_max = 4 << 20; - break; - } - svga->hwcursor.yoff = 32; svga->hwcursor.xoff = 0; @@ -2354,10 +2384,10 @@ gd54xx_init(const device_t *info) gd54xx->bank[1] = 0x8000; - if ((info->flags & DEVICE_PCI) && id >= CIRRUS_ID_CLGD5430) + if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); - gd54xx->pci_regs[0x04] = 7; + gd54xx->pci_regs[PCI_REG_COMMAND] = 7; gd54xx->pci_regs[0x30] = 0x00; gd54xx->pci_regs[0x32] = 0x0c; @@ -2369,19 +2399,17 @@ gd54xx_init(const device_t *info) } static int -gd5428_isa_available(void) +gd5426_available(void) { - return rom_present(BIOS_GD5428_ISA_PATH); + return rom_present(BIOS_GD5426_PATH); } - static int -gd5428_vlb_available(void) +gd5428_available(void) { - return rom_present(BIOS_GD5428_VLB_PATH); + return rom_present(BIOS_GD5428_PATH); } - static int gd5429_available(void) { @@ -2505,6 +2533,21 @@ static const device_config_t gd5434_config[] = }; +const device_t gd5426_vlb_device = +{ + "Cirrus Logic GD5426 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5426, + gd54xx_init, + gd54xx_close, + NULL, + gd5426_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd54xx_add_status_info, + gd5428_config +}; + const device_t gd5428_isa_device = { "Cirrus Logic GD5428 (ISA)", @@ -2513,7 +2556,7 @@ const device_t gd5428_isa_device = gd54xx_init, gd54xx_close, NULL, - gd5428_isa_available, + gd5428_available, gd54xx_speed_changed, gd54xx_force_redraw, gd54xx_add_status_info, @@ -2528,7 +2571,7 @@ const device_t gd5428_vlb_device = gd54xx_init, gd54xx_close, NULL, - gd5428_vlb_available, + gd5428_available, gd54xx_speed_changed, gd54xx_force_redraw, gd54xx_add_status_info, diff --git a/src/video/vid_cl54xx.h b/src/video/vid_cl54xx.h index c02432f..8528fad 100644 --- a/src/video/vid_cl54xx.h +++ b/src/video/vid_cl54xx.h @@ -8,7 +8,7 @@ * * Definitions for the CLGD5428 driver. * - * Version: @(#)vid_cl54xx.h 1.0.4 2018/03/15 + * Version: @(#)vid_cl54xx.h 1.0.5 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -40,6 +40,7 @@ # define VIDEO_CL54XX_H +extern const device_t gd5426_vlb_device; extern const device_t gd5428_isa_device; extern const device_t gd5428_vlb_device; extern const device_t gd5429_isa_device; diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index e345521..d762c56 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,7 +11,7 @@ * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * - * Version: @(#)vid_svga.c 1.0.6 2018/03/12 + * Version: @(#)vid_svga.c 1.0.7 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -314,44 +314,11 @@ uint8_t svga_in(uint16_t addr, void *p) case 0x3DA: svga->attrff = 0; -#if 0 - /* old diagnostic code */ if (svga->cgastat & 0x01) svga->cgastat &= ~0x30; else svga->cgastat ^= 0x30; return svga->cgastat; -#endif - svga->cgastat &= ~0x30; - /* copy color diagnostic info from the overscan color register */ - switch (svga->attrregs[0x12] & 0x30) - { - case 0x00: /* P0 and P2 */ - if (svga->attrregs[0x11] & 0x01) - svga->cgastat |= 0x10; - if (svga->attrregs[0x11] & 0x04) - svga->cgastat |= 0x20; - break; - case 0x10: /* P4 and P5 */ - if (svga->attrregs[0x11] & 0x10) - svga->cgastat |= 0x10; - if (svga->attrregs[0x11] & 0x20) - svga->cgastat |= 0x20; - break; - case 0x20: /* P1 and P3 */ - if (svga->attrregs[0x11] & 0x02) - svga->cgastat |= 0x10; - if (svga->attrregs[0x11] & 0x08) - svga->cgastat |= 0x20; - break; - case 0x30: /* P6 and P7 */ - if (svga->attrregs[0x11] & 0x40) - svga->cgastat |= 0x10; - if (svga->attrregs[0x11] & 0x80) - svga->cgastat |= 0x20; - break; - } - return svga->cgastat; } return 0xFF; } diff --git a/src/video/vid_svga_render.c b/src/video/vid_svga_render.c index bb7b0f9..572ce0c 100644 --- a/src/video/vid_svga_render.c +++ b/src/video/vid_svga_render.c @@ -8,7 +8,7 @@ * * SVGA renderers. * - * Version: @(#)vid_svga_render.c 1.0.6 2018/03/14 + * Version: @(#)vid_svga_render.c 1.0.7 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -330,7 +330,7 @@ void svga_render_text_80_ksc5601(svga_t *svga) dat = svga->vram[charaddr + (svga->sc << 2)]; if(x + xinc < svga->hdisp && (chr & nextchr & 0x80)) { - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc]; + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc]; } else { @@ -377,7 +377,7 @@ void svga_render_text_80_ksc5601(svga_t *svga) } } - dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc + 16]; + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc + 16]; if (svga->seqregs[1] & 1) { for (xx = 0; xx < 8; xx++) diff --git a/src/video/vid_table.c b/src/video/vid_table.c index a32e2cd..c83c1cd 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.9 2018/03/15 + * Version: @(#)vid_table.c 1.0.10 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -163,7 +163,7 @@ video_cards[] = { {"[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device, VID_ET4000W32_CARDEX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, {"[VLB] Cirrus Logic GD5429", "cl_gd5429_vlb", &gd5429_vlb_device, VID_CL_GD5429_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, {"[VLB] Cirrus Logic GD5434", "cl_gd5434_vlb", &gd5434_vlb_device, VID_CL_GD5434_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, - {"[VLB] Diamond SpeedStar PRO (CL GD5428)", "cl_gd5428_vlb", &gd5428_vlb_device, VID_CL_GD5428_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[VLB] Diamond SpeedStar PRO (CL-GD5426)", "cl_gd5426_vlb", &gd5426_vlb_device, VID_CL_GD5426_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, {"[VLB] Diamond SpeedStar PRO SE (CL GD5430)", "cl_gd5430_vlb", &gd5430_vlb_device, VID_CL_GD5430_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, #if defined(DEV_BRANCH) && defined(USE_STEALTH32) {"[VLB] Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32_vlb", &et4000w32p_vlb_device, VID_ET4000W32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, @@ -220,6 +220,11 @@ video_reset(int card) if ((card == VID_NONE) || \ (card == VID_INTERNAL) || machines[machine].fixed_vidcard) return; + if (fontdatksc5601 != NULL) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } + /* Initialize the video card. */ device_add(video_cards[video_old_to_new(card)].device); diff --git a/src/video/video.c b/src/video/video.c index 60406a7..d090fc7 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.5 2018/03/15 + * Version: @(#)video.c 1.0.6 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -101,7 +101,7 @@ uint8_t fontdat[2048][8]; /* IBM CGA font */ uint8_t fontdatm[2048][16]; /* IBM MDA font */ uint8_t fontdatw[512][32]; /* Wyse700 font */ uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ -uint8_t fontdatksc5601[16384][32]; /* Korean KSC-5601 font */ +dbcs_font_t *fontdatksc5601; /* Korean KSC-5601 font */ uint32_t pal_lookup[256]; int xsize = 1, ysize = 1; @@ -679,6 +679,11 @@ video_close(void) destroy_bitmap(buffer); destroy_bitmap(buffer32); + + if (fontdatksc5601 != NULL) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } } @@ -775,9 +780,12 @@ loadfont(wchar_t *s, int format) break; case 6: /* Korean KSC-5601 */ + if (fontdatksc5601 == NULL) + fontdatksc5601 = malloc(16384 * sizeof(dbcs_font_t)); + for (c=0;c<16384;c++) { for (d=0;d<32;d++) - fontdatksc5601[c][d]=getc(f); + fontdatksc5601[c].chr[d]=getc(f); } break; } diff --git a/src/video/video.h b/src/video/video.h index ef3f6c7..db42e3d 100644 --- a/src/video/video.h +++ b/src/video/video.h @@ -8,7 +8,7 @@ * * Definitions for the video controller module. * - * Version: @(#)video.h 1.0.6 2018/03/15 + * Version: @(#)video.h 1.0.8 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -94,11 +94,12 @@ enum { VID_MACH64VT2, /* ATI Mach64 VT2 */ VID_CL_GD5424_ISA, /* Cirrus Logic GD5424 ISA */ VID_CL_GD5424_VLB, /* Cirrus Logic GD5424 VLB */ + VID_CL_GD5426_VLB, /* Diamond SpeedStar PRO (Cirrus Logic GD5426) VLB */ VID_CL_GD5428_ISA, /* Cirrus Logic GD5428 ISA */ - VID_CL_GD5428_VLB, /* Diamond SpeedStar PRO (Cirrus Logic GD5428) VLB */ + VID_CL_GD5428_VLB, /* Cirrus Logic GD5428 VLB */ VID_CL_GD5429_ISA, /* Cirrus Logic GD5429 ISA */ VID_CL_GD5429_VLB, /* Cirrus Logic GD5429 VLB */ - VID_CL_GD5430_VLB, /* Diamond SpeedStar PRO SE (Cirrus Logic GD5430) PCI */ + VID_CL_GD5430_VLB, /* Diamond SpeedStar PRO SE (Cirrus Logic GD5430) VLB */ VID_CL_GD5430_PCI, /* Cirrus Logic GD5430 PCI */ VID_CL_GD5434_ISA, /* Cirrus Logic GD5434 ISA */ VID_CL_GD5434_VLB, /* Cirrus Logic GD5434 VLB */ @@ -163,6 +164,10 @@ typedef struct { uint8_t r, g, b; } rgb_t; +typedef struct { + uint8_t chr[32]; +} dbcs_font_t; + typedef rgb_t PALETTE[256]; @@ -183,7 +188,7 @@ extern int video_fullscreen, extern int fullchange; extern uint8_t fontdat[2048][8]; extern uint8_t fontdatm[2048][16]; -extern uint8_t fontdatksc5601[16384][32]; +extern dbcs_font_t *fontdatksc5601; extern uint32_t *video_6to8, *video_15to32, *video_16to32; diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 2d51af5..4491d98 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.13 2018/03/14 +# Version: @(#)Makefile.mingw 1.0.14 2018/03/17 # # Author: Fred N. van Kempen, # @@ -95,6 +95,9 @@ endif ifndef RDP RDP := n endif +ifndef PNG + PNG := n +endif ifndef DEV_BUILD DEV_BUILD := n endif @@ -347,10 +350,11 @@ endif ifneq ($(WX), n) OPTS += -DUSE_WX $(WX_FLAGS) - LIBS += $(WX_LIBS) -lz -lm + LIBS += $(WX_LIBS) -lm UIOBJ := wx_main.o wx_ui.o wx_stbar.o wx_render.o else - UIOBJ := win_ui.o win_ddraw.o win_d3d.o win_png.o \ + UIOBJ := win_ui.o \ + win_ddraw.o win_d3d.o \ win_dialog.o win_about.o win_status.o win_stbar.o \ win_settings.o win_devconf.o win_snd_gain.o \ win_new_floppy.o win_jsconf.o @@ -383,7 +387,7 @@ RFLAGS += -DUSE_VNC endif VNCLIB += -lvncserver VNCOBJ := vnc.o vnc_keymap.o -LIBS += $(VNCLIB) -lws2_32 -lz +LIBS += $(VNCLIB) -lws2_32 endif ifeq ($(RDP), y) @@ -398,6 +402,12 @@ RDPOBJ := rdp.o LIBS += $(RDPLIB) endif +ifeq ($(PNG), y) +OPTS += -DUSE_PNG +RFLAGS += -DUSE_PNG +LIBS += -lpng -lz +endif + # Options for the DEV branch. ifeq ($(DEV_BRANCH), y) OPTS += -DDEV_BRANCH diff --git a/src/win/win.c b/src/win/win.c index 11fb66d..d2e6838 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.7 2018/03/10 + * Version: @(#)win.c 1.0.8 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -833,32 +833,27 @@ take_screenshot(void) wcscat(path, L"\\"); + wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); + wcscat(path, fn); + switch(vid_api) { #ifdef USE_WX case 0: case 1: - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); - wcscat(path, fn); wx_screenshot(path); break; #else case 0: /* ddraw */ - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.bmp", info); - wcscat(path, fn); ddraw_take_screenshot(path); break; case 1: /* d3d9 */ - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); - wcscat(path, fn); d3d_take_screenshot(path); break; #endif #ifdef USE_VNC case 2: /* vnc */ - wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); - wcscat(path, fn); vnc_take_screenshot(path); break; #endif diff --git a/src/win/win_cdrom_ioctl.c b/src/win/win_cdrom_ioctl.c index ef5c37e..cdd04cd 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.4 2018/03/08 + * Version: @(#)cdrom_ioctl.c 1.0.5 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -118,9 +118,9 @@ void ioctl_audio_callback(uint8_t id, int16_t *output, int len) in.DiskOffset.HighPart = 0; in.SectorCount = 1; in.TrackMode = CDDA; - if (!DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 2352, &count, NULL)) + if (!DeviceIoControl(cdrom_ioctl_windows[id].hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &(cdrom[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 2352, &count, NULL)) { - memset(&(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); + memset(&(cdrom[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); cdrom_ioctl_windows[id].is_playing = 0; ioctl_close(id); cdrom_ioctl[id].cd_state = CD_STOPPED; @@ -134,15 +134,15 @@ void ioctl_audio_callback(uint8_t id, int16_t *output, int len) } else { - memset(&(cdrom_ioctl[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); + memset(&(cdrom[id].cd_buffer[cdrom_ioctl[id].cd_buflen]), 0, (BUF_SIZE - cdrom_ioctl[id].cd_buflen) * 2); cdrom_ioctl_windows[id].is_playing = 0; ioctl_close(id); cdrom_ioctl[id].cd_state = CD_STOPPED; cdrom_ioctl[id].cd_buflen = len; } } - memcpy(output, cdrom_ioctl[id].cd_buffer, len * 2); - memcpy(&cdrom_ioctl[id].cd_buffer[0], &(cdrom_ioctl[id].cd_buffer[len]), (BUF_SIZE - len) * 2); + memcpy(output, cdrom[id].cd_buffer, len * 2); + memcpy(&cdrom[id].cd_buffer[0], &(cdrom[id].cd_buffer[len]), (BUF_SIZE - len) * 2); cdrom_ioctl[id].cd_buflen -= len; } diff --git a/src/win/win_ddraw.cpp b/src/win/win_ddraw.cpp index c2f7866..e73d252 100644 --- a/src/win/win_ddraw.cpp +++ b/src/win/win_ddraw.cpp @@ -11,7 +11,7 @@ * NOTES: This code should be re-merged into a single init() with a * 'fullscreen' argument, indicating FS mode is requested. * - * Version: @(#)win_ddraw.cpp 1.0.2 2018/03/07 + * Version: @(#)win_ddraw.cpp 1.0.3 2018/03/17 * * Authors: Fred N. van Kempen, * Miran Grca, @@ -44,6 +44,10 @@ #include #include #include +#ifdef USE_LIBPNG +# define PNG_DEBUG 0 +# include +#endif #include "../emu.h" #include "../device.h" #include "../video/video.h" @@ -51,7 +55,6 @@ #include "../ui.h" #include "win.h" #include "win_ddraw.h" -#include "win_png.h" static LPDIRECTDRAW lpdd = NULL; @@ -65,6 +68,10 @@ static HWND ddraw_hwnd; static HBITMAP hbitmap; static int ddraw_w, ddraw_h, xs, ys, ys2; +#ifdef USE_LIBPNG +static png_structp png_ptr; +static png_infop png_info_ptr; +#endif static void @@ -88,6 +95,159 @@ CopySurface(IDirectDrawSurface4 *pDDSurface) } +#ifdef USE_LIBPNG +static void +bgra_to_rgb(png_bytep *b_rgb, uint8_t *bgra, int width, int height) +{ + int i, j; + uint8_t *r, *b; + + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + r = &b_rgb[(height - 1) - i][j * 3]; + b = &bgra[((i * width) + j) * 4]; + r[0] = b[2]; + r[1] = b[1]; + r[2] = b[0]; + } + } +} + + +static void +SavePNG(wchar_t *szFilename, HBITMAP hBitmap) +{ + static WCHAR szMessage[512]; + BITMAPFILEHEADER bmpFileHeader; + BITMAPINFO bmpInfo; + HDC hdc; + LPVOID pBuf = NULL; + LPVOID pBuf2 = NULL; + png_bytep *b_rgb = NULL; + FILE *fp; + int i; + + /* Create file. */ + fp = plat_fopen(szFilename, (wchar_t *) L"wb"); + if (fp == NULL) { + pclog("[SavePNG] File %ls could not be opened for writing", szFilename); + _swprintf(szMessage, plat_get_string(IDS_2088), szFilename); + ui_msgbox(MBX_ERROR, szMessage); + return; + } + + /* Initialize PNG stuff. */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + NULL, NULL, NULL); + if (png_ptr == NULL) { + fclose(fp); + pclog("[SavePNG] png_create_write_struct failed"); + _swprintf(szMessage, plat_get_string(IDS_2088), szFilename); + ui_msgbox(MBX_ERROR, szMessage); + return; + } + + png_info_ptr = png_create_info_struct(png_ptr); + if (png_info_ptr == NULL) { + fclose(fp); + pclog("[SavePNG] png_create_info_struct failed"); + _swprintf(szMessage, plat_get_string(IDS_2088), szFilename); + ui_msgbox(MBX_ERROR, szMessage); + return; + } + + png_init_io(png_ptr, fp); + + hdc = GetDC(NULL); + + ZeroMemory(&bmpInfo, sizeof(BITMAPINFO)); + bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + + GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS); + if (bmpInfo.bmiHeader.biSizeImage <= 0) + bmpInfo.bmiHeader.biSizeImage = + bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; + + if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { + fclose(fp); + pclog("[SavePNG] Unable to Allocate Bitmap Memory"); + _swprintf(szMessage, plat_get_string(IDS_2088), szFilename); + ui_msgbox(MBX_ERROR, szMessage); + return; + } + + if (ys2 <= 250) { + bmpInfo.bmiHeader.biSizeImage <<= 1; + + if ((pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { + fclose(fp); + free(pBuf); + pclog("[SavePNG] Unable to Allocate Secondary Bitmap Memory"); + _swprintf(szMessage, plat_get_string(IDS_2088), szFilename); + ui_msgbox(MBX_ERROR, szMessage); + return; + } + + bmpInfo.bmiHeader.biHeight <<= 1; + } + +#if 0 + pclog("save png w=%i h=%i\n", + bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); +#endif + + bmpInfo.bmiHeader.biCompression = BI_RGB; + + GetDIBits(hdc, hBitmap, 0, + bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS); + + png_set_IHDR(png_ptr, png_info_ptr, + bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + b_rgb = (png_bytep *)malloc(sizeof(png_bytep)*bmpInfo.bmiHeader.biHeight)); + if (b_rgb == NULL) { + fclose(fp); + free(pBuf); + free(pBuf2); + pclog("[SavePNG] Unable to Allocate RGB Bitmap Memory"); + _swprintf(szMessage, plat_get_string(IDS_2088), szFilename); + ui_msgbox(MBX_ERROR, szMessage); + return; + } + + for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) + b_rgb[i] = (png_byte *)malloc(png_get_rowbytes(png_ptr, info_ptr)); + + if (pBuf2) { + DoubleLines((uint8_t *)pBuf2, (uint8_t *)pBuf); + bgra_to_rgb(b_rgb, (uint8_t *)pBuf2, + bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); + } else + bgra_to_rgb(b_rgb, (uint8_t *)pBuf, + bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); + + png_write_info(png_ptr, png_info_ptr); + + png_write_image(png_ptr, b_rgb); + + png_write_end(png_ptr, NULL); + + /* Clean up. */ + if (hdc) ReleaseDC(NULL,hdc); + + for (i = 0; i < bmpInfo.bmiHeader.biHeight; i++) + if (b_rgb[i]) free(b_rgb[i]); + + if (b_rgb) free(b_rgb); + + if (pBuf) free(pBuf); + if (pBuf2) free(pBuf2); + + if (fp != NULL) fclose(fp); +} +#else static void DoubleLines(uint8_t *dst, uint8_t *src) { @@ -101,7 +261,7 @@ DoubleLines(uint8_t *dst, uint8_t *src) static void -SaveBitmap(wchar_t *szFilename, HBITMAP hBitmap) +SaveBMP(wchar_t *szFilename, HBITMAP hBitmap) { static WCHAR szMessage[512]; BITMAPFILEHEADER bmpFileHeader; @@ -170,6 +330,7 @@ SaveBitmap(wchar_t *szFilename, HBITMAP hBitmap) if (fp) fclose(fp); } +#endif static void @@ -442,7 +603,11 @@ ddraw_take_screenshot(wchar_t *fn) CopySurface(lpdds_back2); - SaveBitmap(fn, hbitmap); +#ifdef USE_LIBPNG + SavePNG(fn, hbitmap); +#else + SaveBMP(fn, hbitmap); +#endif } diff --git a/src/win/win_png.c b/src/win/win_png.c deleted file mode 100644 index 274419f..0000000 --- a/src/win/win_png.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * 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. - * - * Simple PNG image file format handler. - * - * Adapted for use with VARCem. Writing of (very basic) PNG - * image files, mostly intended to be used for creating - * screenshots. We only support sRGB format (3-byte pixel - * data) with a color depth of 8 bits per sample- so, 24bpp. - * - * NOTES: This is a stripped-down version of my full library for PNG - * image file format support. All the 'reading' code has been - * removed, and some other stuff we don't need here. - * - * TODO: Compression is currently not supported, until I figure out - * how ZLIB works so I can interface with it here. - * - * Version: @(#)win_png.c 1.0.2 2018/03/08 - * - * Author: Fred N. van Kempen, - * - * Copyright 2017,2018 Fred N. van Kempen. - * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include -#include -#include -#include -#include "../emu.h" -#include "../plat.h" -#include "win_png.h" - - -#ifdef CRC_DYNAMIC -static uint32_t crc_table[256]; -static int crc_tblok = 0; - - -/* Pre-calculate the CRC table. */ -static void -crc_create(void) -{ - uint32_t crc; - int i, k; - - for (i=0; i<256; i++) { - crc = (uint32_t)i; - for (k=0; k<8; k++) { - if (crc & 1) - crc = 0xedb88320UL ^ (crc >> 1); - else - crc >>= 1; - } - crc_table[i] = crc; - } - - crc_tblok = 1; -} - - -#else -static uint32_t crc_table[256] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d -}; -#endif - - -/* Standard Network CRC32. */ -static uint32_t -crc_upd(uint32_t crc, uint8_t *bufp, int buflen) -{ - int i; - -#ifdef CRC_DYNAMIC - if (! crc_tblok) - crc_create(); -#endif - - for (i=0; i> 8); - - return(crc); -} - - -static uint32_t -crc_init(void) -{ - return(0xffffffffUL); -} - - -static uint32_t -crc_finish(uint32_t crc) -{ - return(crc ^ 0xffffffffUL); -} - - -/* Perform CRC over the compressed data. */ -static uint32_t -png_dcrc(uint32_t state, const uint8_t *bufp, uint32_t buflen) -{ - uint16_t s1, s2; - uint32_t i; - - s1 = (uint16_t)(state & 0xffff); - s2 = (uint16_t)(state >> 16); - - for (i=0; ifp) != sizeof(buff)) { - pclog("PNG(%ls): could not write trailer chunk!\n", png->name); - return(-1); - } - - /* All is good! */ - return(0); -} - - -/* Write an IDAT chunk header to the file. */ -static uint32_t -png_wridat(png_t *png, uint32_t pixels) -{ - uint8_t buff[10]; - uint32_t cnt; - int i, fluff; - - /* - * We must know the size of the chunk we are about to write, - * and that is not straightforward. If compression is enabled, - * we won't know until we're done with the chunk, so we would - * have to just write a dummy, and then go back afterwards and - * fix up the chunk size. - * - * Without compression, we could do the same, or we can do some - * calculations on how much data we expect to generate, and use - * that. For now, we'll go with the latter option. - */ - cnt = png->lwidth; /* bytes per scanline */ - cnt += 1; /* filter type per line */ - cnt *= (pixels/png->width); /* number of full lines */ - cnt += (pixels%png->width); /* number of pixels */ - - /* - * We now have the total number of pixel bytes to write. - * - * All that is left is adding the expected overhead (since we - * are dealing with fixed-size blocks and their headers) and - * that should give us the grand total.. - */ - i = (cnt / DEFL_MAX_BLKSZ); /* number of full blocks */ - if ((cnt % DEFL_MAX_BLKSZ) != 0) i++; /* incomplete block */ - cnt += (i * 5); /* block header is 5 bytes */ - - /* - * We are not using compression, so we must account for - * the extra data we insert to fake that. Below you will - * see the two DEFLATE bytes (this makes it look like a - * real deflate stream.) Upon closing, we also add the - * four compressed-data CRC bytes, so, a total of 6. - */ - fluff = 6; - - i = 0; - png_putlong(&buff[i], cnt+fluff, &i); /* IDAT chunk */ - memcpy(&buff[i], "IDAT", 4); i += 4; - buff[i++] = 0x08; /* deflate data: zlib */ - buff[i++] = 0x1d; /* zlib method number */ - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): unable to write IDAT header!\n", png->name); - png_close(png); - return(-1); - } - - /* Initialize IDAT CRC. */ - png->crc = crc_upd(png->crc, &buff[4], i-4); - - /* Initialize for writing data. */ - png->bufcnt = 0; /* no data in buffer */ - - return(cnt); -} - - -/* - * API: Write (more) data to the PNG file. - * - * To keep things semi-simple, we generate a single IDAT - * chunk for each write. So, if the application calls us - * with the entire image, we have one IDAT. If it calls - * us multiple times (for example, once per scanline), we - * get one IDAT per scanline. - */ -int -png_write(png_t *png, uint8_t *bitmap, uint32_t pixels) -{ - uint8_t buff[10]; - uint32_t cnt, n; - uint16_t s; - int i; - - /* Do they want to close up? */ - if (bitmap == NULL && pixels == 0) { - i = png_wriend(png); - return(i); - } - - if (png->line >= png->height) { - pclog("PNG(%ls): cannot write %u pixels!\n", png->name, pixels); - png_close(png); - return(-1); - } - - /* Start a new IDAT chunk. */ - cnt = png_wridat(png, pixels); - - /* Loop, writing all pixels to the file. */ - while (cnt > 0) { - if (png->bufcnt == 0) { - /* - * Initialize a new block header. - * - * Bit0: LastBlock - * Bits[2:1]: compression type (00=stored) - * Len: block size (MSB) - * Nlen: block size, negated (MSB) - */ - s = (cnt < DEFL_MAX_BLKSZ) ? cnt : DEFL_MAX_BLKSZ; - i = 0; - buff[i++] = (cnt <= DEFL_MAX_BLKSZ) ? 1:0; - buff[i++] = ((s >> 8) & 0xff); - buff[i++] = (s & 0xff); - buff[i++] = ((s >> 8) ^ 0xff); - buff[i++] = (s ^ 0xff); - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): block header write failed!\n", - png->name); - png_close(png); - return(-1); - } - png->crc = crc_upd(png->crc, buff, i); - cnt -= i; - } - - if (png->col == 0) { - /* Beginning of line, write filter method. */ - buff[0] = 0x00; - if (fwrite(buff, 1, 1, png->fp) != 1) { - pclog("PNG(%ls): cannot write filter?!\n", png->name); - png_close(png); - return(-1); - } - png->crc = crc_upd(png->crc, buff, 1); - png->dcrc = png_dcrc(png->dcrc, buff, 1); - png->bufcnt++; - cnt--; - } - - /* See how many pixels we can write for this scanline. */ - n = cnt; - if ((uint32_t)(png->lwidth - png->col) < n) - n = (png->lwidth - png->col); - if ((DEFL_MAX_BLKSZ - png->bufcnt) < n) - n = (DEFL_MAX_BLKSZ - png->bufcnt); - - /* Write the pixel data for this block. */ - if (fwrite(bitmap, 1, n, png->fp) != n) { - pclog("PNG(%ls): cannot write pixeldata?!\n", png->name); - png_close(png); - return(-1); - } - - /* Update the CRCs for these pixels. */ - png->crc = crc_upd(png->crc, bitmap, n); - png->dcrc = png_dcrc(png->dcrc, bitmap, n); - - /* Update stats. */ - bitmap += n; - png->bufcnt += n; - if (png->bufcnt == DEFL_MAX_BLKSZ) - png->bufcnt = 0; - cnt -= n; - - png->col += n; - if (png->col == png->lwidth) { - png->col = 0; - if (++png->line == png->height) { - if (cnt > 0) { - pclog("PNG(%ls): done, more data?!\n", - png->name); - png_close(png); - return(-1); - } - } - } - } - - /* Write the CRCs. */ - i = 0; - png_putlong(buff, png->dcrc, &i); - png->crc = crc_finish(crc_upd(png->crc, buff, i)); - png_putlong(&buff[i], png->crc, &i); - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): cannot write IDAT trailer?!\n", png->name); - png_close(png); - return(-1); - } - - return(0); -} - - -/* Write an unsigned long 32bit value in MSB. */ -void -png_putlong(uint8_t *ptr, uint32_t val, int *off) -{ - *ptr++ = (val >> 24) & 0xff; - *ptr++ = (val >> 16) & 0xff; - *ptr++ = (val >> 8) & 0xff; - *ptr = val & 0xff; - - if (off != NULL) - *off += sizeof(uint32_t); -} - - -/* API: Close the current PNG file. */ -void -png_close(png_t *png) -{ - if (png->fp != NULL) { - fflush(png->fp); - (void)fclose(png->fp); - - free(png); - } -} - - -/* API: Create a new PNG file. */ -png_t * -png_create(wchar_t *fn, int width, int height, int bpp) -{ - uint8_t buff[33]; - uint32_t crc; - png_t *png; - int i; - - /* Make sure we can do this. */ - if ((bpp != 24) || - (width<=0 || width >= 65536) || - (height<=0 || height >= 65536)) { - pclog("PNG(%ls): invalid image parameters!\n", fn); - return(NULL); - } - - /* Allocate the control block. */ - png = (png_t *)malloc(sizeof(png_t)); - if (png == NULL) { - pclog("PNG(%ls): out of memory!\n", fn); - return(NULL); - } - memset(png, 0x00, sizeof(png_t)); - png->name = fn; - png->width = width; /* width, in pixels */ - png->height = height; /* height, in pixels */ - png->bpp = bpp; /* total bits per pixel */ - png->ctype = PNG_COLOR_TYPE; /* 02 - sRBG */ - png->cdepth = (bpp/3); /* bits per color sample */ - png->pwidth = (bpp/8); /* bytes per pixel */ - png->lwidth = (png->pwidth*width); /* line width in bytes */ - png->crc = crc_init(); /* initialize data CRC */ - png->dcrc = 1; /* compressed-data CRC */ - - /* Create the data file. */ - if ((png->fp = plat_fopen(fn, L"wb")) == NULL) { - pclog("PNG(%ls): unable to create file!\n", fn); - png_close(png); - return(NULL); - } - - /* Write out the basic header chunks. */ - i = 0; - buff[i++] = 0x89; /* standard PNG header */ - memcpy(&buff[i], "PNG", 3); i += 3; - buff[i++] = 0x0d; buff[i++] = 0x0a; - buff[i++] = 0x1a; buff[i++] = 0x0a; - - png_putlong(&buff[i], 13, &i); /* IHDR chunk */ - memcpy(&buff[i], "IHDR", 4); i += 4; - png_putlong(&buff[i], png->width, &i); /* width */ - png_putlong(&buff[i], png->height, &i); /* height */ - buff[i++] = png->cdepth; /* color depth (per color) */ - buff[i++] = png->ctype; /* color type (2=RGB) */ - buff[i++] = PNG_COMPRESSION_TYPE; /* compression (0=deflate) */ - buff[i++] = PNG_FILTER_TYPE; /* filter (0=adaptive) */ - buff[i++] = PNG_INTERLACE_MODE; /* interlace (0=none) */ - crc = crc_finish(crc_upd(crc_init(), &buff[12], 17)); - png_putlong(&buff[i], crc, &i); - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): unable to write PNG header!\n", fn); - png_close(png); - return(NULL); - } - - i = 4; - memcpy(&buff[i], "tEXt", 4); i += 4; - memcpy(&buff[i], "Software", 8); i+= 8; - buff[i++] = 0x00; - memcpy(&buff[i], "VARCem PNGlib", 12); i+= 12; - png_putlong(buff, i-8, NULL); - crc = crc_finish(crc_upd(crc_init(), &buff[4], i-4)); - png_putlong(&buff[i], crc, &i); - if (fwrite(buff, 1, i, png->fp) != i) { - pclog("PNG(%ls): unable to write chunk header!\n", fn); - png_close(png); - return(NULL); - } - - return(png); -} diff --git a/src/win/win_png.h b/src/win/win_png.h deleted file mode 100644 index e25c237..0000000 --- a/src/win/win_png.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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. - * - * Definitions for the Simple PNG image file format handler. - * - * Version: @(#)win_png.h 1.0.1 2018/02/14 - * - * Author: Fred N. van Kempen, - * - * Copyright 2017,2018 Fred N. van Kempen. - * - * Redistribution and use in source and binary forms, with - * or without modification, are permitted provided that the - * following conditions are met: - * - * 1. Redistributions of source code must retain the entire - * above notice, this list of conditions and the following - * disclaimer. - * - * 2. Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the - * following disclaimer in the documentation and/or other - * materials provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names - * of its contributors may be used to endorse or promote - * products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef WIN_PNG_H -# define WIN_PNG_H - - -/* PNG defintions, as per the specification. */ -#define PNG_COLOR_TYPE 0x02 /* 3-sample sRGB */ -#define PNG_COMPRESSION_TYPE 0x00 /* deflate compression */ -#define PNG_FILTER_TYPE 0x00 /* no filtering */ -#define PNG_INTERLACE_MODE 0x00 /* no interlacing */ - -/* DEFLATE definition, as per RFC1950/1 specification. */ -#define DEFL_MAX_BLKSZ 65535 /* DEFLATE max block size */ - - -typedef struct { - wchar_t *name; /* name of datafile */ - FILE *fp; - - uint16_t width, /* configured with in pixels */ - height; /* configured with in pixels */ - uint8_t bpp, /* configured bits per pixel */ - ctype; /* configured color type */ - - uint16_t col, /* current column */ - line, /* current scanline */ - lwidth; /* line width in bytes */ - uint8_t cdepth, /* color depth in bits */ - pwidth; /* bytes per pixel */ - uint32_t crc; /* idat chunk crc */ - uint32_t dcrc; /* deflate data crc */ - - uint32_t bufcnt; /* #bytes in block */ -} png_t; - - -#ifdef __cplusplus -extern "C" { -#endif - -extern void png_putlong(uint8_t *ptr, uint32_t val, int *off); -extern void png_close(png_t *png); -extern png_t *png_create(wchar_t *fn, int width, int height, int bpp); -extern int png_write(png_t *png, uint8_t *bitmap, uint32_t pixels); - -#ifdef __cplusplus -} -#endif - - -#endif /*WIN_PNG_H*/