mirror of
https://github.com/86Box/86Box.git
synced 2026-02-24 02:18:20 -07:00
Merge branch 'master' of github.com:OBattler/86Box
This commit is contained in:
@@ -45,7 +45,7 @@ guide:
|
||||
7. In order to test your fresh build, replace the `86Box.exe` in your current
|
||||
86Box enviroment with your freshly built one. If you do not have a
|
||||
pre-existing 86Box environment, download the latest successful build from
|
||||
http://ci.86box.net, and the ROM set from http://tinyurl.com/rs20180302.
|
||||
http://ci.86box.net, and the ROM set from http://tinyurl.com/rs20180312.
|
||||
8. Enjoy using and testing the emulator! :)
|
||||
|
||||
If you encounter issues at any step or have additional questions, please join
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Main include file for the application.
|
||||
*
|
||||
* Version: @(#)86box.h 1.0.17 2018/01/18
|
||||
* Version: @(#)86box.h 1.0.18 2018/03/13
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
@@ -105,6 +105,7 @@ extern int cpu_manufacturer, /* (C) cpu manufacturer */
|
||||
cpu, /* (C) cpu type */
|
||||
cpu_use_dynarec, /* (C) cpu uses/needs Dyna */
|
||||
enable_external_fpu; /* (C) enable external FPU */
|
||||
extern int enable_sync; /* (C) enable time sync */
|
||||
|
||||
|
||||
#ifdef ENABLE_LOG_TOGGLES
|
||||
|
||||
@@ -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.34 2018/03/06
|
||||
* Version: @(#)cdrom.c 1.0.35 2018/03/15
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
@@ -886,12 +886,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;
|
||||
@@ -2722,17 +2716,12 @@ 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;
|
||||
}
|
||||
@@ -2750,6 +2739,12 @@ int cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
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]));
|
||||
}
|
||||
|
||||
int cdrom_read_from_dma(uint8_t id)
|
||||
{
|
||||
int32_t *BufLen = &SCSIDevices[cdrom_drives[id].scsi_device_id][cdrom_drives[id].scsi_device_lun].BufferLength;
|
||||
@@ -2770,43 +2765,33 @@ 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_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 1;
|
||||
} 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);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
@@ -2834,16 +2819,16 @@ 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_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 1;
|
||||
} 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. */
|
||||
@@ -2879,12 +2864,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);
|
||||
@@ -2895,12 +2874,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);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Implementation of the CD-ROM drive with SCSI(-like)
|
||||
* commands, for both ATAPI and SCSI usage.
|
||||
*
|
||||
* Version: @(#)cdrom.h 1.0.5 2018/03/06
|
||||
* Version: @(#)cdrom.h 1.0.6 2018/03/15
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
@@ -148,6 +148,8 @@ typedef struct {
|
||||
int block_descriptor_len;
|
||||
|
||||
int init_length;
|
||||
|
||||
int16_t cd_buffer[BUF_SIZE];
|
||||
} cdrom_t;
|
||||
|
||||
typedef struct {
|
||||
@@ -187,7 +189,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;
|
||||
|
||||
@@ -199,7 +200,6 @@ typedef struct {
|
||||
int tocvalid;
|
||||
int cd_state;
|
||||
uint32_t cd_end;
|
||||
int16_t cd_buffer[BUF_SIZE];
|
||||
int cd_buflen;
|
||||
int actual_requested_blocks;
|
||||
int last_track_pos;
|
||||
|
||||
@@ -80,9 +80,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;
|
||||
}
|
||||
@@ -94,13 +94,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* CPU type handler.
|
||||
*
|
||||
* Version: @(#)cpu.c 1.0.13 2018/03/02
|
||||
* Version: @(#)cpu.c 1.0.14 2018/03/11
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* leilei,
|
||||
@@ -113,7 +113,7 @@ int cpuspeed;
|
||||
uint64_t cpu_CR4_mask;
|
||||
|
||||
int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l;
|
||||
int cpu_prefetch_cycles, cpu_prefetch_width;
|
||||
int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles;
|
||||
int cpu_waitstates;
|
||||
int cpu_cache_int_enabled, cpu_cache_ext_enabled;
|
||||
int cpu_pci_speed;
|
||||
@@ -246,6 +246,11 @@ void cpu_set()
|
||||
|
||||
isa_cycles = cpu_s->atclk_div;
|
||||
|
||||
if (cpu_s->rspeed <= 8000000)
|
||||
cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles;
|
||||
else
|
||||
cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000;
|
||||
|
||||
if (cpu_s->pci_speed)
|
||||
{
|
||||
pci_nonburst_time = 4*cpu_s->rspeed / cpu_s->pci_speed;
|
||||
@@ -2217,7 +2222,10 @@ void cpu_update_waitstates()
|
||||
{
|
||||
cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective];
|
||||
|
||||
cpu_prefetch_width = cpu_16bitbus ? 2 : 4;
|
||||
if (is486)
|
||||
cpu_prefetch_width = 16;
|
||||
else
|
||||
cpu_prefetch_width = cpu_16bitbus ? 2 : 4;
|
||||
|
||||
if (cpu_cache_int_enabled)
|
||||
{
|
||||
@@ -2251,4 +2259,9 @@ void cpu_update_waitstates()
|
||||
cpu_cycles_write = cpu_s->mem_write_cycles;
|
||||
cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_write_cycles;
|
||||
}
|
||||
if (is486)
|
||||
cpu_prefetch_cycles *= 4;
|
||||
cpu_mem_prefetch_cycles = cpu_prefetch_cycles;
|
||||
if (cpu_s->rspeed <= 8000000)
|
||||
cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* CPU type handler.
|
||||
*
|
||||
* Version: @(#)cpu.h 1.0.9 2018/03/02
|
||||
* Version: @(#)cpu.h 1.0.10 2018/03/11
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* leilei,
|
||||
@@ -387,7 +387,7 @@ extern x86seg _oldds;
|
||||
#define ISA_CYCLES(x) ((x * isa_cycles) >> ISA_CYCLES_SHIFT)
|
||||
|
||||
extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l;
|
||||
extern int cpu_prefetch_cycles, cpu_prefetch_width;
|
||||
extern int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles;
|
||||
extern int cpu_waitstates;
|
||||
extern int cpu_cache_int_enabled, cpu_cache_ext_enabled;
|
||||
extern int cpu_pci_speed;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Implementation of the IDE emulation for hard disks and ATAPI
|
||||
* CD-ROM devices.
|
||||
*
|
||||
* Version: @(#)hdc_ide.c 1.0.32 2018/03/06
|
||||
* Version: @(#)hdc_ide.c 1.0.35 2018/03/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -20,10 +20,11 @@
|
||||
#define __USE_LARGEFILE64
|
||||
#define _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <inttypes.h>
|
||||
#include <wchar.h>
|
||||
#define HAVE_STDARG_H
|
||||
@@ -90,6 +91,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,
|
||||
@@ -397,11 +406,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)
|
||||
{
|
||||
@@ -411,7 +422,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]);
|
||||
}
|
||||
@@ -452,10 +466,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)
|
||||
{
|
||||
@@ -465,12 +481,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*/
|
||||
@@ -506,26 +526,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*/
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,14 +667,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);
|
||||
@@ -647,7 +694,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);
|
||||
@@ -669,7 +716,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 PIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode);
|
||||
break;
|
||||
|
||||
@@ -704,8 +751,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:
|
||||
@@ -738,6 +794,24 @@ void ide_ter_disable_cond();
|
||||
void ide_qua_disable_cond();
|
||||
|
||||
|
||||
void ide_destroy_buffers(void)
|
||||
{
|
||||
int d;
|
||||
|
||||
for (d = 0; d < (IDE_NUM+XTIDE_NUM); d++)
|
||||
{
|
||||
if (ide_drives[d].buffer) {
|
||||
free(ide_drives[d].buffer);
|
||||
ide_drives[d].buffer = NULL;
|
||||
}
|
||||
|
||||
if (ide_drives[d].sector_buffer) {
|
||||
free(ide_drives[d].sector_buffer);
|
||||
ide_drives[d].sector_buffer = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ide_reset(void)
|
||||
{
|
||||
int c, d;
|
||||
@@ -763,8 +837,18 @@ void ide_reset(void)
|
||||
ide_drives[d].atastat = READY_STAT | DSC_STAT;
|
||||
ide_drives[d].service = 0;
|
||||
ide_drives[d].board = d >> 1;
|
||||
|
||||
if (ide_drives[d].buffer) {
|
||||
free(ide_drives[d].buffer);
|
||||
ide_drives[d].buffer = NULL;
|
||||
}
|
||||
|
||||
if (ide_drives[d].sector_buffer) {
|
||||
free(ide_drives[d].sector_buffer);
|
||||
ide_drives[d].sector_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
idecallback[0]=idecallback[1]=0LL;
|
||||
idecallback[2]=idecallback[3]=0LL;
|
||||
idecallback[4]=0LL;
|
||||
@@ -777,12 +861,16 @@ void ide_reset(void)
|
||||
{
|
||||
ide_log("Found IDE hard disk on channel %i\n", hdd[d].ide_channel);
|
||||
loadhd(&ide_drives[hdd[d].ide_channel], d, hdd[d].fn);
|
||||
ide_drives[hdd[d].ide_channel].sector_buffer = NULL; /* Important, makes sure malloc does not reuse an existing pointer from elsewhere. */
|
||||
ide_drives[hdd[d].ide_channel].sector_buffer = (uint8_t *) malloc(256*512);
|
||||
if (++c >= (IDE_NUM+XTIDE_NUM)) break;
|
||||
}
|
||||
if ((hdd[d].bus==HDD_BUS_XTIDE) && (hdd[d].xtide_channel < XTIDE_NUM))
|
||||
{
|
||||
ide_log("Found XT IDE hard disk on channel %i\n", hdd[d].xtide_channel);
|
||||
loadhd(&ide_drives[hdd[d].xtide_channel | 8], d, hdd[d].fn);
|
||||
ide_drives[hdd[d].xtide_channel | 8].sector_buffer = NULL; /* Important, makes sure malloc does not reuse an existing pointer from elsewhere. */
|
||||
ide_drives[hdd[d].xtide_channel | 8].sector_buffer = (uint8_t *) malloc(256*512);
|
||||
if (++c >= (IDE_NUM+XTIDE_NUM)) break;
|
||||
}
|
||||
}
|
||||
@@ -790,13 +878,14 @@ void ide_reset(void)
|
||||
|
||||
for (d = 0; d < IDE_NUM; d++)
|
||||
{
|
||||
if (ide_drive_is_zip(&ide_drives[d]) && (ide_drives[d].type != IDE_HDD))
|
||||
{
|
||||
if (ide_drive_is_zip(&ide_drives[d]) && (ide_drives[d].type == IDE_NONE))
|
||||
ide_drives[d].type = IDE_ZIP;
|
||||
}
|
||||
else if (ide_drive_is_cdrom(&ide_drives[d]) && (ide_drives[d].type != IDE_HDD))
|
||||
{
|
||||
else if (ide_drive_is_cdrom(&ide_drives[d]) && (ide_drives[d].type == IDE_NONE))
|
||||
ide_drives[d].type = IDE_CDROM;
|
||||
|
||||
if (ide_drives[d].type != IDE_NONE) {
|
||||
ide_drives[d].buffer = NULL; /* Important, makes sure malloc does not reuse an existing pointer from elsewhere. */
|
||||
ide_drives[d].buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
ide_set_signature(&ide_drives[d]);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Implementation of the IDE emulation for hard disks and ATAPI
|
||||
* CD-ROM devices.
|
||||
*
|
||||
* Version: @(#)hdd_ide.h 1.0.6 2018/02/14
|
||||
* Version: @(#)hdd_ide.h 1.0.7 2018/03/15
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -36,7 +36,7 @@ typedef struct {
|
||||
int packetstatus;
|
||||
uint8_t asc;
|
||||
int reset;
|
||||
uint16_t buffer[65536];
|
||||
uint16_t *buffer;
|
||||
int irqstat;
|
||||
int service;
|
||||
int lba;
|
||||
@@ -49,7 +49,7 @@ typedef struct {
|
||||
int hdd_num;
|
||||
uint8_t specify_success;
|
||||
int mdma_mode;
|
||||
uint8_t sector_buffer[256*512];
|
||||
uint8_t *sector_buffer;
|
||||
int do_initial_read;
|
||||
int sector_pos;
|
||||
} IDE;
|
||||
@@ -104,6 +104,7 @@ extern void ide_set_callback(uint8_t channel, int64_t callback);
|
||||
extern void secondary_ide_check(void);
|
||||
|
||||
extern void ide_padstr8(uint8_t *buf, int buf_size, const char *src);
|
||||
extern void ide_destroy_buffers(void);
|
||||
|
||||
extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length);
|
||||
extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length);
|
||||
|
||||
@@ -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.8 2018/03/07
|
||||
* Version: @(#)zip.c 1.0.9 2018/03/15
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
*
|
||||
@@ -1084,12 +1084,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;
|
||||
@@ -2220,19 +2214,12 @@ 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);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
@@ -2248,6 +2235,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;
|
||||
@@ -2273,13 +2266,17 @@ 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;
|
||||
|
||||
return 0;
|
||||
if (ret) {
|
||||
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 1;
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zip_write_to_ide_dma(uint8_t channel)
|
||||
@@ -2292,24 +2289,12 @@ 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);
|
||||
} else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun)
|
||||
@@ -2337,16 +2322,16 @@ int zip_write_to_dma(uint8_t id)
|
||||
} else
|
||||
ret = zip_write_to_ide_dma(zip_drives[id].ide_channel);
|
||||
|
||||
if (!ret)
|
||||
if (ret) {
|
||||
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 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]));
|
||||
}
|
||||
|
||||
/* If the result is 1, issue an IRQ, otherwise not. */
|
||||
@@ -2382,12 +2367,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);
|
||||
@@ -2398,12 +2377,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);
|
||||
|
||||
45
src/dma.h
45
src/dma.h
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Implementation of the Intel DMA controllers.
|
||||
*
|
||||
* Version: @(#)dma.h 1.0.4 2017/12/15
|
||||
* Version: @(#)dma.h 1.0.5 2018/03/11
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -25,32 +25,25 @@
|
||||
#define DMA_VERIFY 0x20000
|
||||
|
||||
|
||||
typedef struct DMA {
|
||||
uint32_t ab[4],
|
||||
ac[4];
|
||||
uint16_t cb[4];
|
||||
int cc[4];
|
||||
int wp;
|
||||
uint8_t m,
|
||||
mode[4];
|
||||
uint8_t page[4];
|
||||
uint8_t stat,
|
||||
stat_rq;
|
||||
uint8_t command;
|
||||
uint8_t request;
|
||||
|
||||
int xfr_command,
|
||||
xfr_channel;
|
||||
int byte_ptr;
|
||||
|
||||
int is_ps2;
|
||||
uint8_t arb_level[4];
|
||||
uint8_t ps2_mode[4];
|
||||
} DMA;
|
||||
|
||||
|
||||
extern DMA dma, dma16;
|
||||
/*DMA*/
|
||||
typedef struct dma_t
|
||||
{
|
||||
uint32_t ab, ac;
|
||||
uint16_t cb;
|
||||
int cc;
|
||||
int wp;
|
||||
uint8_t m, mode;
|
||||
uint8_t page;
|
||||
uint8_t stat, stat_rq;
|
||||
uint8_t command;
|
||||
int size;
|
||||
|
||||
uint8_t ps2_mode;
|
||||
uint8_t arb_level;
|
||||
uint16_t io_addr;
|
||||
} dma_t;
|
||||
|
||||
extern dma_t dma[8];
|
||||
|
||||
extern void dma_init(void);
|
||||
extern void dma16_init(void);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Implementation of the floppy drive emulation.
|
||||
*
|
||||
* Version: @(#)fdd.c 1.0.8 2018/03/06
|
||||
* Version: @(#)fdd.c 1.0.9 2018/03/14
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -447,6 +447,7 @@ void fdd_load(int drive, wchar_t *fn)
|
||||
{
|
||||
driveloaders[drive] = c;
|
||||
memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2);
|
||||
d86f_initialize_linked_lists(drive);
|
||||
loaders[c].load(drive, floppyfns[drive]);
|
||||
drive_empty[drive] = 0;
|
||||
fdd_forced_seek(drive, 0);
|
||||
@@ -468,6 +469,8 @@ void fdd_close(int drive)
|
||||
drive_empty[drive] = 1;
|
||||
fdd_set_head(drive, 0);
|
||||
floppyfns[drive][0] = 0;
|
||||
d86f_destroy_linked_lists(drive, 0);
|
||||
d86f_destroy_linked_lists(drive, 1);
|
||||
drives[drive].hole = NULL;
|
||||
drives[drive].poll = NULL;
|
||||
drives[drive].seek = NULL;
|
||||
|
||||
@@ -263,7 +263,7 @@ typedef union
|
||||
void d86f_set_version(int drive, uint16_t version);
|
||||
|
||||
void d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n);
|
||||
void d86f_zero_bit_field(int drive, int side);
|
||||
void d86f_destroy_linked_lists(int drive, int side);
|
||||
|
||||
void d86f_set_fdc(void *fdc);
|
||||
void fdi_set_fdc(void *fdc);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* data in the form of FM/MFM-encoded transitions) which also
|
||||
* forms the core of the emulator's floppy disk emulation.
|
||||
*
|
||||
* Version: @(#)fdd_86f.c 1.0.15 2018/03/05
|
||||
* Version: @(#)fdd_86f.c 1.0.17 2018/03/14
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
@@ -195,6 +195,14 @@ typedef union {
|
||||
static fdc_t *d86f_fdc;
|
||||
|
||||
|
||||
#pragma pack(push,1)
|
||||
typedef struct
|
||||
{
|
||||
uint8_t c, h, r, n;
|
||||
void *prev;
|
||||
} sector_t;
|
||||
#pragma pack(pop)
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct
|
||||
{
|
||||
@@ -239,7 +247,7 @@ struct
|
||||
uint8_t *outbuf;
|
||||
uint32_t dma_over;
|
||||
int turbo_pos;
|
||||
uint16_t sector_id_bit_field[2][256][256][256];
|
||||
sector_t *last_side_sector[2];
|
||||
} d86f[FDD_NUM + 1];
|
||||
#pragma pack(pop)
|
||||
|
||||
@@ -265,25 +273,29 @@ d86f_log(const char *format, ...)
|
||||
}
|
||||
|
||||
|
||||
void d86f_zero_bit_field(int drive, int side)
|
||||
void d86f_initialize_linked_lists(int drive)
|
||||
{
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
int l = 0;
|
||||
d86f[drive].last_side_sector[0] = NULL;
|
||||
d86f[drive].last_side_sector[1] = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < side; i++)
|
||||
void d86f_destroy_linked_lists(int drive, int side)
|
||||
{
|
||||
sector_t *s;
|
||||
sector_t *t;
|
||||
|
||||
if (d86f[drive].last_side_sector[side])
|
||||
{
|
||||
for (j = 0; j < 256; j++)
|
||||
{
|
||||
for (k = 0; k < 256; k++)
|
||||
{
|
||||
for (l = 0; l < 256; l++)
|
||||
{
|
||||
d86f[drive].sector_id_bit_field[i][j][k][l] = 0;
|
||||
}
|
||||
}
|
||||
s = d86f[drive].last_side_sector[side];
|
||||
while (s) {
|
||||
t = s->prev;
|
||||
free(s);
|
||||
s = NULL;
|
||||
if (!t)
|
||||
break;
|
||||
s = t;
|
||||
}
|
||||
d86f[drive].last_side_sector[side] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2190,6 +2202,24 @@ void d86f_turbo_format(int drive, int side, int nop)
|
||||
}
|
||||
}
|
||||
|
||||
int d86f_sector_is_present(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n)
|
||||
{
|
||||
sector_t *s, *t;
|
||||
|
||||
if (d86f[drive].last_side_sector[side]) {
|
||||
s = d86f[drive].last_side_sector[side];
|
||||
while (s) {
|
||||
if ((s->c == c) && (s->h == h) && (s->r == r) && (s->n == n))
|
||||
return 1;
|
||||
if (!s->prev)
|
||||
break;
|
||||
t = s->prev;
|
||||
s = t;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void d86f_turbo_poll(int drive, int side)
|
||||
{
|
||||
if ((d86f[drive].state != STATE_IDLE) && (d86f[drive].state != STATE_SECTOR_NOT_FOUND) && ((d86f[drive].state & 0xF8) != 0xE8))
|
||||
@@ -2213,7 +2243,11 @@ void d86f_turbo_poll(int drive, int side)
|
||||
d86f[drive].state++;
|
||||
return;
|
||||
case STATE_02_FIND_ID:
|
||||
if (!(d86f[drive].sector_id_bit_field[side][fdc_get_read_track_sector(d86f_fdc).id.c][fdc_get_read_track_sector(d86f_fdc).id.h][fdc_get_read_track_sector(d86f_fdc).id.r] & (1 << fdc_get_read_track_sector(d86f_fdc).id.n)))
|
||||
if (!d86f_sector_is_present(drive, side,
|
||||
fdc_get_read_track_sector(d86f_fdc).id.c,
|
||||
fdc_get_read_track_sector(d86f_fdc).id.h,
|
||||
fdc_get_read_track_sector(d86f_fdc).id.r,
|
||||
fdc_get_read_track_sector(d86f_fdc).id.n))
|
||||
{
|
||||
d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = d86f[drive].error_condition = 0;
|
||||
fdc_nosector(d86f_fdc);
|
||||
@@ -2234,7 +2268,11 @@ void d86f_turbo_poll(int drive, int side)
|
||||
case STATE_0C_FIND_ID:
|
||||
case STATE_11_FIND_ID:
|
||||
case STATE_16_FIND_ID:
|
||||
if (!(d86f[drive].sector_id_bit_field[side][d86f[drive].req_sector.id.c][d86f[drive].req_sector.id.h][d86f[drive].req_sector.id.r] & (1 << d86f[drive].req_sector.id.n)))
|
||||
if (!d86f_sector_is_present(drive, side,
|
||||
d86f[drive].req_sector.id.c,
|
||||
d86f[drive].req_sector.id.h,
|
||||
d86f[drive].req_sector.id.r,
|
||||
d86f[drive].req_sector.id.n))
|
||||
{
|
||||
d86f[drive].id_find.sync_marks = d86f[drive].id_find.bits_obtained = d86f[drive].id_find.bytes_obtained = d86f[drive].error_condition = 0;
|
||||
fdc_nosector(d86f_fdc);
|
||||
@@ -2577,6 +2615,8 @@ uint16_t d86f_prepare_pretrack(int drive, int side, int iso)
|
||||
|
||||
d86f[drive].index_hole_pos[side] = 0;
|
||||
|
||||
d86f_destroy_linked_lists(drive, side);
|
||||
|
||||
for (i = 0; i < raw_size; i++)
|
||||
{
|
||||
d86f_write_direct_common(drive, side, gap_fill, 0, i);
|
||||
@@ -2621,6 +2661,7 @@ uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf,
|
||||
uint16_t pos;
|
||||
|
||||
int i;
|
||||
sector_t *s;
|
||||
|
||||
int real_gap2_len = gap2;
|
||||
int real_gap3_len = gap3;
|
||||
@@ -2635,7 +2676,17 @@ uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf,
|
||||
uint16_t dataam_mfm = 0x4555;
|
||||
uint16_t datadam_mfm = 0x4A55;
|
||||
|
||||
d86f[drive].sector_id_bit_field[side][id_buf[0]][id_buf[1]][id_buf[2]] |= (1 << id_buf[3]);
|
||||
if (fdd_get_turbo(drive) && (d86f[drive].version == 0x0063)) {
|
||||
s = (sector_t *) malloc(sizeof(sector_t));
|
||||
memset(s, 0, sizeof(sector_t));
|
||||
s->c = id_buf[0];
|
||||
s->h = id_buf[1];
|
||||
s->r = id_buf[2];
|
||||
s->n = id_buf[3];
|
||||
if (d86f[drive].last_side_sector[side])
|
||||
s->prev = d86f[drive].last_side_sector[side];
|
||||
d86f[drive].last_side_sector[side] = s;
|
||||
}
|
||||
|
||||
mfm = d86f_is_mfm(drive);
|
||||
|
||||
@@ -3748,10 +3799,16 @@ void d86f_load(int drive, wchar_t *fn)
|
||||
|
||||
void d86f_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
memset(d86f, 0, sizeof(d86f));
|
||||
d86f_setupcrc(0x1021);
|
||||
|
||||
d86f[0].state = d86f[1].state = STATE_IDLE;
|
||||
for (i = 0; i < (FDD_NUM + 1); i++)
|
||||
{
|
||||
d86f[i].state = STATE_IDLE;
|
||||
d86f_initialize_linked_lists(i);
|
||||
}
|
||||
}
|
||||
|
||||
void d86f_set_fdc(void *fdc)
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* data in the form of FM/MFM-encoded transitions) which also
|
||||
* forms the core of the emulator's floppy disk emulation.
|
||||
*
|
||||
* Version: @(#)floppy_86f.h 1.0.4 2018/01/18
|
||||
* Version: @(#)floppy_86f.h 1.0.5 2018/03/14
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
@@ -69,7 +69,9 @@ extern int gap4_size[2];
|
||||
#define D86FVER 0x020B
|
||||
|
||||
extern void d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n);
|
||||
extern void d86f_zero_bit_field(int drive, int side);
|
||||
|
||||
extern void d86f_initialize_linked_lists(int drive);
|
||||
extern void d86f_destroy_linked_lists(int drive, int side);
|
||||
|
||||
|
||||
#endif /*EMU_FLOPPY_86F_H*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Implementation of the IMD floppy image format.
|
||||
*
|
||||
* Version: @(#)fdd_imd.c 1.0.7 2018/03/06
|
||||
* Version: @(#)fdd_imd.c 1.0.8 2018/03/14
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
@@ -542,8 +542,8 @@ void imd_seek(int drive, int track)
|
||||
d86f_reset_index_hole_pos(drive, 0);
|
||||
d86f_reset_index_hole_pos(drive, 1);
|
||||
|
||||
d86f_zero_bit_field(drive, 0);
|
||||
d86f_zero_bit_field(drive, 1);
|
||||
d86f_destroy_linked_lists(drive, 0);
|
||||
d86f_destroy_linked_lists(drive, 1);
|
||||
|
||||
if (track > imd[drive].track_count)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* Implementation of the raw sector-based floppy image format,
|
||||
* as well as the Japanese FDI, CopyQM, and FDF formats.
|
||||
*
|
||||
* Version: @(#)fdd_img.c 1.0.8 2018/01/16
|
||||
* Version: @(#)fdd_img.c 1.0.9 2018/03/14
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -960,8 +960,8 @@ void img_seek(int drive, int track)
|
||||
d86f_reset_index_hole_pos(drive, 0);
|
||||
d86f_reset_index_hole_pos(drive, 1);
|
||||
|
||||
d86f_zero_bit_field(drive, 0);
|
||||
d86f_zero_bit_field(drive, 1);
|
||||
d86f_destroy_linked_lists(drive, 0);
|
||||
d86f_destroy_linked_lists(drive, 1);
|
||||
|
||||
if (track > img[drive].tracks)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Implementation of the PCjs JSON floppy image format.
|
||||
*
|
||||
* Version: @(#)fdd_json.c 1.0.10 2018/01/16
|
||||
* Version: @(#)fdd_json.c 1.0.11 2018/03/14
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
@@ -357,8 +357,8 @@ json_seek(int drive, int track)
|
||||
/* Reset the 86F state machine. */
|
||||
d86f_reset_index_hole_pos(drive, 0);
|
||||
d86f_reset_index_hole_pos(drive, 1);
|
||||
d86f_zero_bit_field(drive, 0);
|
||||
d86f_zero_bit_field(drive, 1);
|
||||
d86f_destroy_linked_lists(drive, 0);
|
||||
d86f_destroy_linked_lists(drive, 1);
|
||||
|
||||
interleave_type = 0;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Implementation of the Teledisk floppy image format.
|
||||
*
|
||||
* Version: @(#)fdd_td0.c 1.0.7 2018/01/16
|
||||
* Version: @(#)fdd_td0.c 1.0.8 2018/03/14
|
||||
*
|
||||
* Authors: Milodrag Milanovic,
|
||||
* Haruhiko OKUMURA,
|
||||
@@ -1111,8 +1111,8 @@ void td0_seek(int drive, int track)
|
||||
d86f_reset_index_hole_pos(drive, 0);
|
||||
d86f_reset_index_hole_pos(drive, 1);
|
||||
|
||||
d86f_zero_bit_field(drive, 0);
|
||||
d86f_zero_bit_field(drive, 1);
|
||||
d86f_destroy_linked_lists(drive, 0);
|
||||
d86f_destroy_linked_lists(drive, 1);
|
||||
|
||||
if (track > td0[drive].tracks)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Intel 8042 (AT keyboard controller) emulation.
|
||||
*
|
||||
* Version: @(#)keyboard_at.c 1.0.27 2018/03/02
|
||||
* Version: @(#)keyboard_at.c 1.0.30 2018/03/13
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -91,7 +91,7 @@ typedef struct {
|
||||
uint8_t status;
|
||||
uint8_t mem[0x100];
|
||||
uint8_t out;
|
||||
int out_new;
|
||||
int out_new, out_delayed;
|
||||
uint8_t secr_phase;
|
||||
uint8_t mem_addr;
|
||||
|
||||
@@ -645,7 +645,7 @@ kbd_poll(void *priv)
|
||||
kbdlog("ATkbd: want keyboard data\n");
|
||||
if (kbd->mem[0] & 0x01)
|
||||
picint(2);
|
||||
kbd->out = kbd->out_new;
|
||||
kbd->out = kbd->out_new & 0xff;
|
||||
kbd->out_new = -1;
|
||||
kbd->status |= STAT_OFULL;
|
||||
kbd->status &= ~STAT_IFULL;
|
||||
@@ -656,8 +656,16 @@ kbd_poll(void *priv)
|
||||
|
||||
if (kbd->out_new == -1 && !(kbd->status & STAT_OFULL) &&
|
||||
key_ctrl_queue_start != key_ctrl_queue_end) {
|
||||
kbd->out_new = key_ctrl_queue[key_ctrl_queue_start];
|
||||
kbd->out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200;
|
||||
key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf;
|
||||
} else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1 &&
|
||||
kbd->out_delayed != -1) {
|
||||
kbd->out_new = kbd->out_delayed;
|
||||
kbd->out_delayed = -1;
|
||||
} else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1 &&
|
||||
!(kbd->mem[0] & 0x10) && kbd->out_delayed != -1) {
|
||||
kbd->out_new = kbd->out_delayed;
|
||||
kbd->out_delayed = -1;
|
||||
} else if (!(kbd->status & STAT_OFULL) && kbd->out_new == -1/* && !(kbd->mem[0] & 0x20)*/ &&
|
||||
(mouse_queue_start != mouse_queue_end)) {
|
||||
kbd->out_new = mouse_queue[mouse_queue_start] | 0x100;
|
||||
@@ -675,6 +683,11 @@ kbd_adddata(uint8_t val)
|
||||
{
|
||||
key_ctrl_queue[key_ctrl_queue_end] = val;
|
||||
key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf;
|
||||
|
||||
if (!(CurrentKbd->out_new & 0x300)) {
|
||||
CurrentKbd->out_delayed = CurrentKbd->out_new;
|
||||
CurrentKbd->out_new = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -960,7 +973,7 @@ kbd_cmd_write(atkbd_t *kbd, uint8_t val)
|
||||
|
||||
/* ISA AT keyboard controllers use bit 5 for keyboard mode (1 = PC/XT, 2 = AT);
|
||||
PS/2 (and EISA/PCI) keyboard controllers use it as the PS/2 mouse enable switch. */
|
||||
if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) {
|
||||
if (((kbd->flags & KBC_VEN_MASK) == KBC_VEN_AMI) || ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) {
|
||||
keyboard_mode &= ~CCB_PCMODE;
|
||||
|
||||
mouse_scan = !(val & 0x20);
|
||||
|
||||
@@ -1,9 +1,155 @@
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implementation of the Toshiba T3100e.
|
||||
*
|
||||
* The Toshiba 3100e is a 286-based portable.
|
||||
*
|
||||
* To bring up the BIOS setup screen hold down the 'Fn' key
|
||||
* on booting.
|
||||
*
|
||||
* Memory management
|
||||
* ~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Motherboard memory is divided into:
|
||||
* - Conventional memory: Either 512k or 640k
|
||||
* - Upper memory: Either 512k or 384k, depending on
|
||||
* amount of conventional memory.
|
||||
* Upper memory can be used as EMS or XMS.
|
||||
* - High memory: 0-4Mb, depending on RAM installed.
|
||||
* The BIOS setup screen allows some or
|
||||
* all of this to be used as EMS; the
|
||||
* remainder is XMS.
|
||||
*
|
||||
* Additional memory (either EMS or XMS) can also be provided
|
||||
* by ISA expansion cards.
|
||||
*
|
||||
* Under test in PCem, the BIOS will boot with up to 65368Kb
|
||||
* of memory in total (16Mb less 16k). However it will give
|
||||
* an error with RAM sizes above 8Mb, if any of the high
|
||||
* memory is allocated as EMS, because the builtin EMS page
|
||||
* registers can only access up to 8Mb.
|
||||
*
|
||||
* Memory is controlled by writes to I/O port 8084h:
|
||||
* Bit 7: Always 0 }
|
||||
* Bit 6: Always 1 } These bits select which motherboard
|
||||
* Bit 5: Always 0 } function to access.
|
||||
* Bit 4: Set to treat upper RAM as XMS
|
||||
* Bit 3: Enable external RAM boards?
|
||||
* Bit 2: Set for 640k conventional memory, clear for 512k
|
||||
* Bit 1: Enable RAM beyond 1Mb.
|
||||
* Bit 0: Enable EMS.
|
||||
*
|
||||
* The last value written to this port is saved at 0040:0093h,
|
||||
* and in CMOS memory at offset 0x37. If the top bit of the
|
||||
* CMOS byte is set, then high memory is being provided by
|
||||
* an add-on card rather than the mainboard; accordingly,
|
||||
* the BIOS will not allow high memory to be used as EMS.
|
||||
*
|
||||
* EMS is controlled by 16 page registers:
|
||||
*
|
||||
* Page mapped at 0xD000 0xD400 0xD800 0xDC00
|
||||
* ------------------------------------------------------
|
||||
* Pages 0x00-0x7F 0x208 0x4208 0x8208 0xc208
|
||||
* Pages 0x80-0xFF 0x218 0x4218 0x8218 0xc218
|
||||
* Pages 0x100-0x17F 0x258 0x4258 0x8258 0xc258
|
||||
* Pages 0x180-0x1FF 0x268 0x4268 0x8268 0xc268
|
||||
*
|
||||
* The value written has bit 7 set to enable EMS, reset to
|
||||
* disable it.
|
||||
*
|
||||
* So:
|
||||
* OUT 0x208, 0x80 will page in the first 16k page at 0xD0000.
|
||||
* OUT 0x208, 0x00 will page out EMS, leaving nothing at 0xD0000.
|
||||
* OUT 0x4208, 0x80 will page in the first 16k page at 0xD4000.
|
||||
* OUT 0x218, 0x80 will page in the 129th 16k page at 0xD0000.
|
||||
* etc.
|
||||
*
|
||||
* To use EMS from DOS, you will need the Toshiba EMS driver
|
||||
* (TOSHEMM.ZIP). This supports the above system, plus further
|
||||
* ranges of ports at 0x_2A8, 0x_2B8, 0x_2C8.
|
||||
*
|
||||
* Features not implemented:
|
||||
* > Four video fonts.
|
||||
* > BIOS-controlled mapping of serial ports to IRQs.
|
||||
* > Custom keyboard controller. This has a number of extra
|
||||
* commands in the 0xB0-0xBC range, for such things as turbo
|
||||
* on/off, and switching the keyboard between AT and PS/2
|
||||
* modes. Currently I have only implemented command 0xBB,
|
||||
* so that self-test completes successfully. Commands include:
|
||||
*
|
||||
* 0xB0: Turbo on
|
||||
* 0xB1: Turbo off
|
||||
* 0xB2: Internal display on?
|
||||
* 0xB3: Internal display off?
|
||||
* 0xB5: Get settings byte (bottom bit is color/mono setting)
|
||||
* 0xB6: Set settings byte
|
||||
* 0xB7: Behave as 101-key PS/2 keyboard
|
||||
* 0xB8: Behave as 84-key AT keyboard
|
||||
* 0xBB: Return a byte, bit 2 is Fn key state, other bits unknown.
|
||||
*
|
||||
* The other main I/O port needed to POST is:
|
||||
* 0x8084: System control.
|
||||
* Top 3 bits give command, bottom 5 bits give parameters.
|
||||
* 000 => set serial port IRQ / addresses
|
||||
* bit 4: IRQ5 serial port base: 1 => 0x338, 0 => 0x3E8
|
||||
* bits 3, 2, 0 specify serial IRQs for COM1, COM2, COM3:
|
||||
* 00 0 => 4, 3, 5
|
||||
* 00 1 => 4, 5, 3
|
||||
* 01 0 => 3, 4, 5
|
||||
* 01 1 => 3, 5, 4
|
||||
* 10 0 => 4, -, 3
|
||||
* 10 1 => 3, -, 4
|
||||
* 010 => set memory mappings
|
||||
* bit 4 set if upper RAM is XMS
|
||||
* bit 3 enable add-on memory boards beyond 5Mb?
|
||||
* bit 2 set for 640k sysram, clear for 512k sysram
|
||||
* bit 1 enable mainboard XMS
|
||||
* bit 0 enable mainboard EMS
|
||||
* 100 => set parallel mode / LCD settings
|
||||
* bit 4 set for bidirectional parallel port
|
||||
* bit 3 set to disable internal CGA
|
||||
* bit 2 set for single-pixel LCD font
|
||||
* bits 0,1 for display font
|
||||
*
|
||||
* Version: @(#)m_at_t3100e.c 1.0.3 2018/03/05
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the:
|
||||
*
|
||||
* Free Software Foundation, Inc.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
|
||||
#include "../86box.h"
|
||||
#include "../io.h"
|
||||
#include "../mouse.h"
|
||||
@@ -13,124 +159,18 @@
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "../video/vid_t3100e.h"
|
||||
|
||||
#include "machine.h"
|
||||
#include "m_at_t3100e.h"
|
||||
|
||||
/* The Toshiba 3100e is a 286-based portable.
|
||||
*
|
||||
* To bring up the BIOS setup screen hold down the 'Fn' key on booting
|
||||
*
|
||||
* Memory management
|
||||
* ~~~~~~~~~~~~~~~~~
|
||||
*
|
||||
* Motherboard memory is divided into:
|
||||
* - Conventional memory: Either 512k or 640k
|
||||
* - Upper memory: Either 512k or 384k, depending on amount of
|
||||
* conventional memory. Upper memory can be
|
||||
* used either as EMS or XMS.
|
||||
* - High memory: 0-4Mb, depending on RAM installed. The BIOS
|
||||
* setup screen allows some or all of this to be
|
||||
* used as EMS; the remainder is XMS.
|
||||
*
|
||||
* Additional memory (either EMS or XMS) can also be provided by ISA
|
||||
* expansion cards.
|
||||
*
|
||||
* Under test in PCEM, the BIOS will boot with up to 65368Kb of memory in
|
||||
* total (16Mb less 16k). However it will give an error with RAM sizes
|
||||
* above 8Mb, if any of the high memory is allocated as EMS, because the
|
||||
* builtin EMS page registers can only access up to 8Mb.
|
||||
*
|
||||
* Memory is controlled by writes to I/O port 8084h:
|
||||
* Bit 7: Always 0 }
|
||||
* Bit 6: Always 1 } These bits select which motherboard function to
|
||||
* Bit 5: Always 0 } access.
|
||||
* Bit 4: Set to treat upper RAM as XMS
|
||||
* Bit 3: Enable external RAM boards?
|
||||
* Bit 2: Set for 640k conventional memory, clear for 512k
|
||||
* Bit 1: Enable RAM beyond 1Mb.
|
||||
* Bit 0: Enable EMS.
|
||||
*
|
||||
* The last value written to this port is saved at 0040:0093h, and in
|
||||
* CMOS memory at offset 0x37. If the top bit of the CMOS byte is set,
|
||||
* then high memory is being provided by an add-on card rather than the
|
||||
* mainboard; accordingly, the BIOS will not allow high memory to be
|
||||
* used as EMS.
|
||||
*
|
||||
* EMS is controlled by 16 page registers:
|
||||
*
|
||||
* Page mapped at 0xD000 0xD400 0xD800 0xDC00
|
||||
* ------------------------------------------------------
|
||||
* Pages 0x00-0x7F 0x208 0x4208 0x8208 0xc208
|
||||
* Pages 0x80-0xFF 0x218 0x4218 0x8218 0xc218
|
||||
* Pages 0x100-0x17F 0x258 0x4258 0x8258 0xc258
|
||||
* Pages 0x180-0x1FF 0x268 0x4268 0x8268 0xc268
|
||||
*
|
||||
* The value written has bit 7 set to enable EMS, reset to disable it.
|
||||
*
|
||||
* So: OUT 0x208, 0x80 will page in the first 16k page at 0xD0000.
|
||||
* OUT 0x208, 0x00 will page out EMS, leaving nothing at 0xD0000.
|
||||
* OUT 0x4208, 0x80 will page in the first 16k page at 0xD4000.
|
||||
* OUT 0x218, 0x80 will page in the 129th 16k page at 0xD0000.
|
||||
*
|
||||
* etc.
|
||||
*
|
||||
* To use EMS from DOS, you will need the Toshiba EMS driver (TOSHEMM.ZIP).
|
||||
* This supports the above system, plus further ranges of ports at
|
||||
* 0x_2A8, 0x_2B8, 0x_2C8.
|
||||
*
|
||||
*/
|
||||
|
||||
static const int t3100e_log = 0;
|
||||
|
||||
extern uint8_t *ram; /* Physical RAM */
|
||||
|
||||
/* Features not implemented:
|
||||
* > Four video fonts.
|
||||
* > BIOS-controlled mapping of serial ports to IRQs.
|
||||
* > Custom keyboard controller. This has a number of extra commands in the
|
||||
* 0xB0-0xBC range, for such things as turbo on/off, and switching the
|
||||
* keyboard between AT and PS/2 modes. Currently I have only implemented
|
||||
* command 0xBB, so that self-test completes successfully. Commands include:
|
||||
*
|
||||
* 0xB0: Turbo on
|
||||
* 0xB1: Turbo off
|
||||
* 0xB2: Internal display on?
|
||||
* 0xB3: Internal display off?
|
||||
* 0xB5: Get settings byte (bottom bit is colour / mono setting)
|
||||
* 0xB6: Set settings byte
|
||||
* 0xB7: Behave as 101-key PS/2 keyboard
|
||||
* 0xB8: Behave as 84-key AT keyboard
|
||||
* 0xBB: Return a byte, bit 2 is Fn key state, other bits unknown.
|
||||
*
|
||||
* The other main I/O port needed to POST is:
|
||||
* 0x8084: System control.
|
||||
* Top 3 bits give command, bottom 5 bits give parameters.
|
||||
* 000 => set serial port IRQ / addresses
|
||||
* bit 4: IRQ5 serial port base: 1 => 0x338, 0 => 0x3E8
|
||||
* bits 3, 2, 0 specify serial IRQs for COM1, COM2, COM3:
|
||||
* 00 0 => 4, 3, 5
|
||||
* 00 1 => 4, 5, 3
|
||||
* 01 0 => 3, 4, 5
|
||||
* 01 1 => 3, 5, 4
|
||||
* 10 0 => 4, -, 3
|
||||
* 10 1 => 3, -, 4
|
||||
* 010 => set memory mappings
|
||||
* bit 4 set if upper RAM is XMS
|
||||
* bit 3 enable add-on memory boards beyond 5Mb?
|
||||
* bit 2 set for 640k sysram, clear for 512k sysram
|
||||
* bit 1 enable mainboard XMS
|
||||
* bit 0 enable mainboard EMS
|
||||
* 100 => set parallel mode / LCD settings
|
||||
* bit 4 set for bidirectional parallel port
|
||||
* bit 3 set to disable internal CGA
|
||||
* bit 2 set for single-pixel LCD font
|
||||
* bits 0,1 for display font
|
||||
*/
|
||||
|
||||
void at_init();
|
||||
|
||||
|
||||
static const int t3100e_log = 0;
|
||||
|
||||
|
||||
/* The T3100e motherboard can (and does) dynamically reassign RAM between
|
||||
* conventional, XMS and EMS. This translates to monkeying with the mappings.
|
||||
*/
|
||||
|
||||
@@ -1,7 +1,58 @@
|
||||
void t3100e_notify_set(uint8_t value);
|
||||
void t3100e_display_set(uint8_t value);
|
||||
uint8_t t3100e_display_get();
|
||||
uint8_t t3100e_config_get();
|
||||
void t3100e_turbo_set(uint8_t value);
|
||||
uint8_t t3100e_mono_get();
|
||||
void t3100e_mono_set(uint8_t value);
|
||||
/*
|
||||
* 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 Toshiba T3100e system.
|
||||
*
|
||||
* Version: @(#)m_at_t3100e.h 1.0.2 2018/03/05
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the:
|
||||
*
|
||||
* Free Software Foundation, Inc.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef MACHINE_T3100E_H
|
||||
# define MACHINE_T3100E_H
|
||||
|
||||
|
||||
extern device_t t3100e_device;
|
||||
|
||||
|
||||
extern void t3100e_notify_set(uint8_t value);
|
||||
extern void t3100e_display_set(uint8_t value);
|
||||
extern uint8_t t3100e_display_get(void);
|
||||
extern uint8_t t3100e_config_get(void);
|
||||
extern void t3100e_turbo_set(uint8_t value);
|
||||
extern uint8_t t3100e_mono_get(void);
|
||||
extern void t3100e_mono_set(uint8_t value);
|
||||
|
||||
extern void t3100e_video_options_set(uint8_t options);
|
||||
extern void t3100e_display_set(uint8_t internal);
|
||||
|
||||
|
||||
#endif /*MACHINE_T3100E_H*/
|
||||
|
||||
763
src/machine/m_at_t3100e_vid.c
Normal file
763
src/machine/m_at_t3100e_vid.c
Normal file
@@ -0,0 +1,763 @@
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implementation of the Toshiba 3100e plasma display.
|
||||
* This display has a fixed 640x400 resolution.
|
||||
*
|
||||
* T3100e CRTC regs (from the ROM):
|
||||
*
|
||||
* Selecting a character height of 3 seems to be sufficient to
|
||||
* convert the 640x200 graphics mode to 640x400 (and, by
|
||||
* analogy, 320x200 to 320x400).
|
||||
*
|
||||
* Horiz-----> Vert------> I ch
|
||||
* 38 28 2D 0A 1F 06 19 1C 02 07 06 07 CO40
|
||||
* 71 50 5A 0A 1F 06 19 1C 02 07 06 07 CO80
|
||||
* 38 28 2D 0A 7F 06 64 70 02 01 06 07 Graphics
|
||||
* 61 50 52 0F 19 06 19 19 02 0D 0B 0C MONO
|
||||
* 2D 28 22 0A 67 00 64 67 02 03 06 07 640x400
|
||||
*
|
||||
* Version: @(#)m_at_t3100e_vid.c 1.0.3 2018/03/07
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the:
|
||||
*
|
||||
* Free Software Foundation, Inc.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../device.h"
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../timer.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../video/video.h"
|
||||
#include "../video/vid_cga.h"
|
||||
#include "m_at_t3100e.h"
|
||||
|
||||
|
||||
#define T3100E_XSIZE 640
|
||||
#define T3100E_YSIZE 400
|
||||
|
||||
|
||||
/* Mapping of attributes to colours */
|
||||
static uint32_t amber, black;
|
||||
static uint8_t boldcols[256]; /* Which attributes use the bold font */
|
||||
static uint32_t blinkcols[256][2];
|
||||
static uint32_t normcols[256][2];
|
||||
|
||||
/* Video options set by the motherboard; they will be picked up by the card
|
||||
* on the next poll.
|
||||
*
|
||||
* Bit 3: Disable built-in video (for add-on card)
|
||||
* Bit 2: Thin font
|
||||
* Bits 0,1: Font set (not currently implemented)
|
||||
*/
|
||||
static uint8_t st_video_options;
|
||||
static int8_t st_display_internal = -1;
|
||||
|
||||
void t3100e_video_options_set(uint8_t options)
|
||||
{
|
||||
st_video_options = options;
|
||||
}
|
||||
|
||||
void t3100e_display_set(uint8_t internal)
|
||||
{
|
||||
st_display_internal = internal;
|
||||
}
|
||||
|
||||
uint8_t t3100e_display_get()
|
||||
{
|
||||
return st_display_internal;
|
||||
}
|
||||
|
||||
|
||||
typedef struct t3100e_t
|
||||
{
|
||||
mem_mapping_t mapping;
|
||||
|
||||
cga_t cga; /* The CGA is used for the external
|
||||
* display; most of its registers are
|
||||
* ignored by the plasma display. */
|
||||
|
||||
int font; /* Current font, 0-3 */
|
||||
int enabled; /* Hardware enabled, 0 or 1 */
|
||||
int internal; /* Using internal display? */
|
||||
uint8_t attrmap; /* Attribute mapping register */
|
||||
|
||||
int dispontime, dispofftime;
|
||||
|
||||
int linepos, displine;
|
||||
int vc;
|
||||
int dispon;
|
||||
int vsynctime;
|
||||
uint8_t video_options;
|
||||
|
||||
uint8_t *vram;
|
||||
} t3100e_t;
|
||||
|
||||
|
||||
void t3100e_recalctimings(t3100e_t *t3100e);
|
||||
void t3100e_write(uint32_t addr, uint8_t val, void *p);
|
||||
uint8_t t3100e_read(uint32_t addr, void *p);
|
||||
void t3100e_recalcattrs(t3100e_t *t3100e);
|
||||
|
||||
|
||||
void t3100e_out(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
t3100e_t *t3100e = (t3100e_t *)p;
|
||||
switch (addr)
|
||||
{
|
||||
/* Emulated CRTC, register select */
|
||||
case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6:
|
||||
cga_out(addr, val, &t3100e->cga);
|
||||
break;
|
||||
|
||||
/* Emulated CRTC, value */
|
||||
case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7:
|
||||
/* Register 0x12 controls the attribute mappings for the
|
||||
* plasma screen. */
|
||||
if (t3100e->cga.crtcreg == 0x12)
|
||||
{
|
||||
t3100e->attrmap = val;
|
||||
t3100e_recalcattrs(t3100e);
|
||||
return;
|
||||
}
|
||||
cga_out(addr, val, &t3100e->cga);
|
||||
|
||||
t3100e_recalctimings(t3100e);
|
||||
return;
|
||||
|
||||
/* CGA control register */
|
||||
case 0x3D8:
|
||||
cga_out(addr, val, &t3100e->cga);
|
||||
return;
|
||||
/* CGA colour register */
|
||||
case 0x3D9:
|
||||
cga_out(addr, val, &t3100e->cga);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t t3100e_in(uint16_t addr, void *p)
|
||||
{
|
||||
t3100e_t *t3100e = (t3100e_t *)p;
|
||||
uint8_t val;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7:
|
||||
if (t3100e->cga.crtcreg == 0x12)
|
||||
{
|
||||
val = t3100e->attrmap & 0x0F;
|
||||
if (t3100e->internal) val |= 0x30; /* Plasma / CRT */
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
return cga_in(addr, &t3100e->cga);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void t3100e_write(uint32_t addr, uint8_t val, void *p)
|
||||
{
|
||||
t3100e_t *t3100e = (t3100e_t *)p;
|
||||
egawrites++;
|
||||
|
||||
// pclog("CGA_WRITE %04X %02X\n", addr, val);
|
||||
t3100e->vram[addr & 0x7fff] = val;
|
||||
cycles -= 4;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t t3100e_read(uint32_t addr, void *p)
|
||||
{
|
||||
t3100e_t *t3100e = (t3100e_t *)p;
|
||||
egareads++;
|
||||
cycles -= 4;
|
||||
|
||||
// pclog("CGA_READ %04X\n", addr);
|
||||
return t3100e->vram[addr & 0x7fff];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void t3100e_recalctimings(t3100e_t *t3100e)
|
||||
{
|
||||
double disptime;
|
||||
double _dispontime, _dispofftime;
|
||||
|
||||
if (!t3100e->internal)
|
||||
{
|
||||
cga_recalctimings(&t3100e->cga);
|
||||
return;
|
||||
}
|
||||
disptime = 651;
|
||||
_dispontime = 640;
|
||||
_dispofftime = disptime - _dispontime;
|
||||
t3100e->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT));
|
||||
t3100e->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
|
||||
}
|
||||
|
||||
|
||||
/* Draw a row of text in 80-column mode */
|
||||
void t3100e_text_row80(t3100e_t *t3100e)
|
||||
{
|
||||
uint32_t cols[2];
|
||||
int x, c;
|
||||
uint8_t chr, attr;
|
||||
int drawcursor;
|
||||
int cursorline;
|
||||
int bold;
|
||||
int blink;
|
||||
uint16_t addr;
|
||||
uint8_t sc;
|
||||
uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff;
|
||||
uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff;
|
||||
|
||||
sc = (t3100e->displine) & 15;
|
||||
addr = ((ma & ~1) + (t3100e->displine >> 4) * 80) * 2;
|
||||
ma += (t3100e->displine >> 4) * 80;
|
||||
|
||||
if ((t3100e->cga.crtc[10] & 0x60) == 0x20)
|
||||
{
|
||||
cursorline = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cursorline = ((t3100e->cga.crtc[10] & 0x0F)*2 <= sc) &&
|
||||
((t3100e->cga.crtc[11] & 0x0F)*2 >= sc);
|
||||
}
|
||||
for (x = 0; x < 80; x++)
|
||||
{
|
||||
chr = t3100e->vram[(addr + 2 * x) & 0x7FFF];
|
||||
attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF];
|
||||
drawcursor = ((ma == ca) && cursorline &&
|
||||
(t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16));
|
||||
|
||||
blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) &&
|
||||
(attr & 0x80) && !drawcursor);
|
||||
|
||||
if (t3100e->video_options & 4)
|
||||
bold = boldcols[attr] ? chr + 256 : chr;
|
||||
else
|
||||
bold = boldcols[attr] ? chr : chr + 256;
|
||||
bold += 512 * (t3100e->video_options & 3);
|
||||
|
||||
if (t3100e->cga.cgamode & 0x20) /* Blink */
|
||||
{
|
||||
cols[1] = blinkcols[attr][1];
|
||||
cols[0] = blinkcols[attr][0];
|
||||
if (blink) cols[1] = cols[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
cols[1] = normcols[attr][1];
|
||||
cols[0] = normcols[attr][0];
|
||||
}
|
||||
if (drawcursor)
|
||||
{
|
||||
for (c = 0; c < 8; c++)
|
||||
{
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (c = 0; c < 8; c++)
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0];
|
||||
}
|
||||
++ma;
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw a row of text in 40-column mode */
|
||||
void t3100e_text_row40(t3100e_t *t3100e)
|
||||
{
|
||||
uint32_t cols[2];
|
||||
int x, c;
|
||||
uint8_t chr, attr;
|
||||
int drawcursor;
|
||||
int cursorline;
|
||||
int bold;
|
||||
int blink;
|
||||
uint16_t addr;
|
||||
uint8_t sc;
|
||||
uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff;
|
||||
uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff;
|
||||
|
||||
sc = (t3100e->displine) & 15;
|
||||
addr = ((ma & ~1) + (t3100e->displine >> 4) * 40) * 2;
|
||||
ma += (t3100e->displine >> 4) * 40;
|
||||
|
||||
if ((t3100e->cga.crtc[10] & 0x60) == 0x20)
|
||||
{
|
||||
cursorline = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cursorline = ((t3100e->cga.crtc[10] & 0x0F)*2 <= sc) &&
|
||||
((t3100e->cga.crtc[11] & 0x0F)*2 >= sc);
|
||||
}
|
||||
for (x = 0; x < 40; x++)
|
||||
{
|
||||
chr = t3100e->vram[(addr + 2 * x) & 0x7FFF];
|
||||
attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF];
|
||||
drawcursor = ((ma == ca) && cursorline &&
|
||||
(t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16));
|
||||
|
||||
blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) &&
|
||||
(attr & 0x80) && !drawcursor);
|
||||
|
||||
if (t3100e->video_options & 4)
|
||||
bold = boldcols[attr] ? chr + 256 : chr;
|
||||
else bold = boldcols[attr] ? chr : chr + 256;
|
||||
bold += 512 * (t3100e->video_options & 3);
|
||||
|
||||
if (t3100e->cga.cgamode & 0x20) /* Blink */
|
||||
{
|
||||
cols[1] = blinkcols[attr][1];
|
||||
cols[0] = blinkcols[attr][0];
|
||||
if (blink) cols[1] = cols[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
cols[1] = normcols[attr][1];
|
||||
cols[0] = normcols[attr][0];
|
||||
}
|
||||
if (drawcursor)
|
||||
{
|
||||
for (c = 0; c < 8; c++)
|
||||
{
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] =
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2 + 1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (c = 0; c < 8; c++)
|
||||
{
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] =
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2+1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0];
|
||||
}
|
||||
}
|
||||
++ma;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Draw a line in CGA 640x200 or T3100e 640x400 mode */
|
||||
void t3100e_cgaline6(t3100e_t *t3100e)
|
||||
{
|
||||
int x, c;
|
||||
uint8_t dat;
|
||||
uint32_t ink = 0;
|
||||
uint16_t addr;
|
||||
uint32_t fg = (t3100e->cga.cgacol & 0x0F) ? amber : black;
|
||||
uint32_t bg = black;
|
||||
|
||||
uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff;
|
||||
|
||||
if (t3100e->cga.crtc[9] == 3) /* 640*400 */
|
||||
{
|
||||
addr = ((t3100e->displine) & 1) * 0x2000 +
|
||||
((t3100e->displine >> 1) & 1) * 0x4000 +
|
||||
(t3100e->displine >> 2) * 80 +
|
||||
((ma & ~1) << 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = ((t3100e->displine >> 1) & 1) * 0x2000 +
|
||||
(t3100e->displine >> 2) * 80 +
|
||||
((ma & ~1) << 1);
|
||||
}
|
||||
for (x = 0; x < 80; x++)
|
||||
{
|
||||
dat = t3100e->vram[addr & 0x7FFF];
|
||||
addr++;
|
||||
|
||||
for (c = 0; c < 8; c++)
|
||||
{
|
||||
ink = (dat & 0x80) ? fg : bg;
|
||||
if (!(t3100e->cga.cgamode & 8)) ink = black;
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[x*8+c] = ink;
|
||||
dat = dat << 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Draw a line in CGA 320x200 mode. Here the CGA colours are converted to
|
||||
* dither patterns: colour 1 to 25% grey, colour 2 to 50% grey */
|
||||
void t3100e_cgaline4(t3100e_t *t3100e)
|
||||
{
|
||||
int x, c;
|
||||
uint8_t dat, pattern;
|
||||
uint32_t ink0 = 0, ink1 = 0;
|
||||
uint16_t addr;
|
||||
|
||||
uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff;
|
||||
if (t3100e->cga.crtc[9] == 3) /* 320*400 undocumented */
|
||||
{
|
||||
addr = ((t3100e->displine) & 1) * 0x2000 +
|
||||
((t3100e->displine >> 1) & 1) * 0x4000 +
|
||||
(t3100e->displine >> 2) * 80 +
|
||||
((ma & ~1) << 1);
|
||||
}
|
||||
else /* 320*200 */
|
||||
{
|
||||
addr = ((t3100e->displine >> 1) & 1) * 0x2000 +
|
||||
(t3100e->displine >> 2) * 80 +
|
||||
((ma & ~1) << 1);
|
||||
}
|
||||
for (x = 0; x < 80; x++)
|
||||
{
|
||||
dat = t3100e->vram[addr & 0x7FFF];
|
||||
addr++;
|
||||
|
||||
for (c = 0; c < 4; c++)
|
||||
{
|
||||
pattern = (dat & 0xC0) >> 6;
|
||||
if (!(t3100e->cga.cgamode & 8)) pattern = 0;
|
||||
|
||||
switch (pattern & 3)
|
||||
{
|
||||
case 0: ink0 = ink1 = black; break;
|
||||
case 1: if (t3100e->displine & 1)
|
||||
{
|
||||
ink0 = black; ink1 = black;
|
||||
}
|
||||
else
|
||||
{
|
||||
ink0 = amber; ink1 = black;
|
||||
}
|
||||
break;
|
||||
case 2: if (t3100e->displine & 1)
|
||||
{
|
||||
ink0 = black; ink1 = amber;
|
||||
}
|
||||
else
|
||||
{
|
||||
ink0 = amber; ink1 = black;
|
||||
}
|
||||
break;
|
||||
case 3: ink0 = ink1 = amber; break;
|
||||
|
||||
}
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[x*8+2*c] = ink0;
|
||||
((uint32_t *)buffer32->line[t3100e->displine])[x*8+2*c+1] = ink1;
|
||||
dat = dat << 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void t3100e_poll(void *p)
|
||||
{
|
||||
t3100e_t *t3100e = (t3100e_t *)p;
|
||||
|
||||
if (t3100e->video_options != st_video_options)
|
||||
{
|
||||
t3100e->video_options = st_video_options;
|
||||
|
||||
if (t3100e->video_options & 8) /* Disable internal CGA */
|
||||
mem_mapping_disable(&t3100e->mapping);
|
||||
else mem_mapping_enable(&t3100e->mapping);
|
||||
|
||||
/* Set the font used for the external display */
|
||||
t3100e->cga.fontbase = (512 * (t3100e->video_options & 3))
|
||||
+ ((t3100e->video_options & 4) ? 256 : 0);
|
||||
|
||||
}
|
||||
/* Switch between internal plasma and external CRT display. */
|
||||
if (st_display_internal != -1 && st_display_internal != t3100e->internal)
|
||||
{
|
||||
t3100e->internal = st_display_internal;
|
||||
t3100e_recalctimings(t3100e);
|
||||
}
|
||||
if (!t3100e->internal)
|
||||
{
|
||||
cga_poll(&t3100e->cga);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!t3100e->linepos)
|
||||
{
|
||||
t3100e->cga.vidtime += t3100e->dispofftime;
|
||||
t3100e->cga.cgastat |= 1;
|
||||
t3100e->linepos = 1;
|
||||
if (t3100e->dispon)
|
||||
{
|
||||
if (t3100e->displine == 0)
|
||||
{
|
||||
video_wait_for_buffer();
|
||||
}
|
||||
|
||||
/* Graphics */
|
||||
if (t3100e->cga.cgamode & 0x02)
|
||||
{
|
||||
if (t3100e->cga.cgamode & 0x10)
|
||||
t3100e_cgaline6(t3100e);
|
||||
else t3100e_cgaline4(t3100e);
|
||||
}
|
||||
else
|
||||
if (t3100e->cga.cgamode & 0x01) /* High-res text */
|
||||
{
|
||||
t3100e_text_row80(t3100e);
|
||||
}
|
||||
else
|
||||
{
|
||||
t3100e_text_row40(t3100e);
|
||||
}
|
||||
}
|
||||
t3100e->displine++;
|
||||
/* Hardcode a fixed refresh rate and VSYNC timing */
|
||||
if (t3100e->displine == 400) /* Start of VSYNC */
|
||||
{
|
||||
t3100e->cga.cgastat |= 8;
|
||||
t3100e->dispon = 0;
|
||||
}
|
||||
if (t3100e->displine == 416) /* End of VSYNC */
|
||||
{
|
||||
t3100e->displine = 0;
|
||||
t3100e->cga.cgastat &= ~8;
|
||||
t3100e->dispon = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t3100e->dispon)
|
||||
{
|
||||
t3100e->cga.cgastat &= ~1;
|
||||
}
|
||||
t3100e->cga.vidtime += t3100e->dispontime;
|
||||
t3100e->linepos = 0;
|
||||
|
||||
if (t3100e->displine == 400)
|
||||
{
|
||||
/* Hardcode 640x400 window size */
|
||||
if (T3100E_XSIZE != xsize || T3100E_YSIZE != ysize)
|
||||
{
|
||||
xsize = T3100E_XSIZE;
|
||||
ysize = T3100E_YSIZE;
|
||||
if (xsize < 64) xsize = 656;
|
||||
if (ysize < 32) ysize = 200;
|
||||
set_screen_size(xsize, ysize);
|
||||
}
|
||||
video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize);
|
||||
|
||||
frames++;
|
||||
/* Fixed 640x400 resolution */
|
||||
video_res_x = T3100E_XSIZE;
|
||||
video_res_y = T3100E_YSIZE;
|
||||
|
||||
if (t3100e->cga.cgamode & 0x02)
|
||||
{
|
||||
if (t3100e->cga.cgamode & 0x10)
|
||||
video_bpp = 1;
|
||||
else video_bpp = 2;
|
||||
|
||||
}
|
||||
else video_bpp = 0;
|
||||
t3100e->cga.cgablink++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void t3100e_recalcattrs(t3100e_t *t3100e)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* val behaves as follows:
|
||||
* Bit 0: Attributes 01-06, 08-0E are inverse video
|
||||
* Bit 1: Attributes 01-06, 08-0E are bold
|
||||
* Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF
|
||||
* are inverse video
|
||||
* Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF
|
||||
* are bold */
|
||||
|
||||
/* Set up colours */
|
||||
amber = makecol(0xf7, 0x7C, 0x34);
|
||||
black = makecol(0x17, 0x0C, 0x00);
|
||||
|
||||
/* Initialise the attribute mapping. Start by defaulting everything
|
||||
* to black on amber, and with bold set by bit 3 */
|
||||
for (n = 0; n < 256; n++)
|
||||
{
|
||||
boldcols[n] = (n & 8) != 0;
|
||||
blinkcols[n][0] = normcols[n][0] = amber;
|
||||
blinkcols[n][1] = normcols[n][1] = black;
|
||||
}
|
||||
|
||||
/* Colours 0x11-0xFF are controlled by bits 2 and 3 of the
|
||||
* passed value. Exclude x0 and x8, which are always black on
|
||||
* amber. */
|
||||
for (n = 0x11; n <= 0xFF; n++)
|
||||
{
|
||||
if ((n & 7) == 0) continue;
|
||||
if (t3100e->attrmap & 4) /* Inverse */
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = amber;
|
||||
blinkcols[n][1] = normcols[n][1] = black;
|
||||
}
|
||||
else /* Normal */
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = black;
|
||||
blinkcols[n][1] = normcols[n][1] = amber;
|
||||
}
|
||||
if (t3100e->attrmap & 8) boldcols[n] = 1; /* Bold */
|
||||
}
|
||||
/* Set up the 01-0E range, controlled by bits 0 and 1 of the
|
||||
* passed value. When blinking is enabled this also affects 81-8E. */
|
||||
for (n = 0x01; n <= 0x0E; n++)
|
||||
{
|
||||
if (n == 7) continue;
|
||||
if (t3100e->attrmap & 1)
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = amber;
|
||||
blinkcols[n][1] = normcols[n][1] = black;
|
||||
blinkcols[n+128][0] = amber;
|
||||
blinkcols[n+128][1] = black;
|
||||
}
|
||||
else
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = black;
|
||||
blinkcols[n][1] = normcols[n][1] = amber;
|
||||
blinkcols[n+128][0] = black;
|
||||
blinkcols[n+128][1] = amber;
|
||||
}
|
||||
if (t3100e->attrmap & 2) boldcols[n] = 1;
|
||||
}
|
||||
/* Colours 07 and 0F are always amber on black. If blinking is
|
||||
* enabled so are 87 and 8F. */
|
||||
for (n = 0x07; n <= 0x0F; n += 8)
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = black;
|
||||
blinkcols[n][1] = normcols[n][1] = amber;
|
||||
blinkcols[n+128][0] = black;
|
||||
blinkcols[n+128][1] = amber;
|
||||
}
|
||||
/* When not blinking, colours 81-8F are always amber on black. */
|
||||
for (n = 0x81; n <= 0x8F; n ++)
|
||||
{
|
||||
normcols[n][0] = black;
|
||||
normcols[n][1] = amber;
|
||||
boldcols[n] = (n & 0x08) != 0;
|
||||
}
|
||||
|
||||
|
||||
/* Finally do the ones which are solid black. These differ between
|
||||
* the normal and blinking mappings */
|
||||
for (n = 0; n <= 0xFF; n += 0x11)
|
||||
{
|
||||
normcols[n][0] = normcols[n][1] = black;
|
||||
}
|
||||
/* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are black */
|
||||
for (n = 0; n <= 0x77; n += 0x11)
|
||||
{
|
||||
blinkcols[n][0] = blinkcols[n][1] = black;
|
||||
blinkcols[n+128][0] = blinkcols[n+128][1] = black;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *t3100e_init(device_t *info)
|
||||
{
|
||||
t3100e_t *t3100e = malloc(sizeof(t3100e_t));
|
||||
memset(t3100e, 0, sizeof(t3100e_t));
|
||||
cga_init(&t3100e->cga);
|
||||
|
||||
t3100e->internal = 1;
|
||||
|
||||
/* 32k video RAM */
|
||||
t3100e->vram = malloc(0x8000);
|
||||
|
||||
timer_add(t3100e_poll, &t3100e->cga.vidtime, TIMER_ALWAYS_ENABLED, t3100e);
|
||||
|
||||
/* Occupy memory between 0xB8000 and 0xBFFFF */
|
||||
mem_mapping_add(&t3100e->mapping, 0xb8000, 0x8000, t3100e_read, NULL, NULL, t3100e_write, NULL, NULL, NULL, 0, t3100e);
|
||||
/* Respond to CGA I/O ports */
|
||||
io_sethandler(0x03d0, 0x000c, t3100e_in, NULL, NULL, t3100e_out, NULL, NULL, t3100e);
|
||||
|
||||
/* Default attribute mapping is 4 */
|
||||
t3100e->attrmap = 4;
|
||||
t3100e_recalcattrs(t3100e);
|
||||
|
||||
/* Start off in 80x25 text mode */
|
||||
t3100e->cga.cgastat = 0xF4;
|
||||
t3100e->cga.vram = t3100e->vram;
|
||||
t3100e->enabled = 1;
|
||||
t3100e->video_options = 0xFF;
|
||||
return t3100e;
|
||||
}
|
||||
|
||||
void t3100e_close(void *p)
|
||||
{
|
||||
t3100e_t *t3100e = (t3100e_t *)p;
|
||||
|
||||
free(t3100e->vram);
|
||||
free(t3100e);
|
||||
}
|
||||
|
||||
void t3100e_speed_changed(void *p)
|
||||
{
|
||||
t3100e_t *t3100e = (t3100e_t *)p;
|
||||
|
||||
t3100e_recalctimings(t3100e);
|
||||
}
|
||||
|
||||
device_t t3100e_device =
|
||||
{
|
||||
"Toshiba T3100e",
|
||||
0,
|
||||
0,
|
||||
t3100e_init,
|
||||
t3100e_close,
|
||||
NULL,
|
||||
NULL,
|
||||
t3100e_speed_changed,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
* 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 86Box distribution.
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implementation of the Schneider EuroPC system.
|
||||
*
|
||||
@@ -27,8 +27,7 @@
|
||||
* f000:ecc5 801a video setup error
|
||||
* f000:d6c9 copyright output
|
||||
* f000:e1b7
|
||||
* f000:e1be DI bits set mean output text!!!,
|
||||
* (801a)
|
||||
* f000:e1be DI bits set mean output text!!! (801a)
|
||||
* f000: 0x8000 output
|
||||
* 1 rtc error
|
||||
* 2 rtc time or date error
|
||||
@@ -53,21 +52,23 @@
|
||||
* output cl at jim 0xa
|
||||
* write ah hinibble as lownibble into jim 0xa
|
||||
* write ah lownibble into jim 0xa
|
||||
* f000:ef66 RTC read reg cl
|
||||
* f000:ef66 RTC read reg cl
|
||||
* polls until jim 0xa is zero,
|
||||
* output cl at jim 0xa
|
||||
* read low 4 nibble at jim 0xa
|
||||
* read low 4 nibble at jim 0xa
|
||||
* return first nibble<<4|second nibble in ah
|
||||
* f000:f046 seldom compares ret
|
||||
* f000:fe87 0 -> ds
|
||||
* 0000:0469 bit 0: b0000 memory available
|
||||
* f000:f046 seldom compares ret
|
||||
* f000:fe87 0 -> ds
|
||||
*
|
||||
* Memory:
|
||||
* 0000:0469 bit 0: b0000 memory available
|
||||
* bit 1: b8000 memory available
|
||||
* 0000:046a: 00 jim 250 01 jim 350
|
||||
* 0000:046a: 00 jim 250 01 jim 350
|
||||
*
|
||||
* WARNING THIS IS A WORK-IN-PROGRESS MODULE. USE AT OWN RISK.
|
||||
*
|
||||
* Version: @(#)europc.c 1.0.6 2018/01/16
|
||||
* Version: @(#)europc.c 1.0.2 2018/03/11
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
@@ -77,12 +78,43 @@
|
||||
* input from people with real EuroPC hardware.
|
||||
*
|
||||
* 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <time.h>
|
||||
#include "../86box.h"
|
||||
#include "../io.h"
|
||||
#include "../nmi.h"
|
||||
@@ -90,17 +122,17 @@
|
||||
#include "../rom.h"
|
||||
#include "../nvr.h"
|
||||
#include "../device.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "../disk/hdc.h"
|
||||
#include "../keyboard.h"
|
||||
#include "../mouse.h"
|
||||
#include "../game/gameport.h"
|
||||
#include "../floppy/fdd.h"
|
||||
#include "../floppy/fdc.h"
|
||||
#include "../disk/hdc.h"
|
||||
#include "../video/video.h"
|
||||
#include "machine.h"
|
||||
|
||||
|
||||
#define EUROPC_DEBUG 1 /* current debugging level */
|
||||
#define EUROPC_DEBUG 0 /* current debugging level */
|
||||
|
||||
|
||||
/* M3002 RTC chip registers. */
|
||||
@@ -109,7 +141,7 @@
|
||||
#define MRTC_HOURS 0x02 /* BCD, 00-23 */
|
||||
#define MRTC_DAYS 0x03 /* BCD, 01-31 */
|
||||
#define MRTC_MONTHS 0x04 /* BCD, 01-12 */
|
||||
#define MRTC_YEARS 0x05 /* BCD, 00-99 (2017 is 0x17) */
|
||||
#define MRTC_YEARS 0x05 /* BCD, 00-99 (year only) */
|
||||
#define MRTC_WEEKDAY 0x06 /* BCD, 01-07 */
|
||||
#define MRTC_WEEKNO 0x07 /* BCD, 01-52 */
|
||||
#define MRTC_CONF_A 0x08 /* EuroPC config, binary */
|
||||
@@ -121,127 +153,232 @@
|
||||
#define MRTC_CHECK_HI 0x0e /* Checksum, high byte */
|
||||
#define MRTC_CTRLSTAT 0x0f /* RTC control/status, binary */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint16_t jim; /* JIM base address */
|
||||
|
||||
uint8_t regs[16]; /* JIM internal regs (8) */
|
||||
|
||||
struct {
|
||||
uint8_t dat[16];
|
||||
uint8_t stat;
|
||||
uint8_t addr;
|
||||
} rtc;
|
||||
|
||||
nvr_t nvr; /* 86Box NVR */
|
||||
} vm_t;
|
||||
nvr_t nvr; /* NVR */
|
||||
uint8_t nvr_stat;
|
||||
uint8_t nvr_addr;
|
||||
} europc_t;
|
||||
|
||||
|
||||
static vm_t *vm = NULL;
|
||||
static europc_t europc;
|
||||
|
||||
|
||||
/* Load the relevant portion of the NVR to disk. */
|
||||
static int8_t
|
||||
load_nvr(wchar_t *fn)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (vm == NULL) return(0);
|
||||
|
||||
f = nvr_fopen(fn, L"rb");
|
||||
if (f != NULL) {
|
||||
(void)fread(vm->rtc.dat, 1, 16, f);
|
||||
(void)fclose(f);
|
||||
pclog("EuroPC: CMOS data loaded from file %ls !\n", fn);
|
||||
return(1);
|
||||
}
|
||||
|
||||
pclog("EuroPC: unable to load NVR !\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* Save the relevant portion of the NVR to disk. */
|
||||
static int8_t
|
||||
save_nvr(wchar_t *fn)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (vm == NULL) return(0);
|
||||
|
||||
f = nvr_fopen(fn, L"wb");
|
||||
if (f != NULL) {
|
||||
(void)fwrite(vm->rtc.dat, 1, 16, f);
|
||||
(void)fclose(f);
|
||||
return(1);
|
||||
}
|
||||
|
||||
pclog("EuroPC: unable to save NVR !\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* This is called every second through the NVR/RTC hook. */
|
||||
/*
|
||||
* This is called every second through the NVR/RTC hook.
|
||||
*
|
||||
* We fake a 'running' RTC by updating its registers on
|
||||
* each passing second. Not exactly accurate, but good
|
||||
* enough.
|
||||
*
|
||||
* Note that this code looks nasty because of all the
|
||||
* BCD to decimal vv going on.
|
||||
*
|
||||
* FIXME: should we mark NVR as dirty?
|
||||
*/
|
||||
static void
|
||||
rtc_hook(nvr_t *nvr)
|
||||
rtc_tick(nvr_t *nvr)
|
||||
{
|
||||
#if 0
|
||||
int month, year;
|
||||
uint8_t *regs;
|
||||
int mon, yr;
|
||||
|
||||
sys->rtc.dat[0] = bcd_adjust(sys->rtc.dat[0]+1);
|
||||
if (sys->rtc.dat[0] >= 0x60) {
|
||||
sys->rtc.dat[0] = 0;
|
||||
sys->rtc.dat[1] = bcd_adjust(sys->rtc.dat[1]+1);
|
||||
if (sys->rtc.dat[1] >= 0x60) {
|
||||
sys->rtc.dat[1] = 0;
|
||||
sys->rtc.dat[2] = bcd_adjust(sys->rtc.dat[2]+1);
|
||||
if (sys->rtc.dat[2] >= 0x24) {
|
||||
sys->rtc.dat[2] = 0;
|
||||
sys->uropc_rtc.data[3]=bcd_adjust(sys->uropc_rtc.data[3]+1);
|
||||
month = bcd_2_dec(sys->rtc.dat[4]);
|
||||
/* Only if RTC is running.. */
|
||||
regs = nvr->regs;
|
||||
if (! (regs[MRTC_CTRLSTAT] & 0x01)) return;
|
||||
|
||||
/* Save for julian_days_in_month_calculation. */
|
||||
year = bcd_2_dec(sys->rtc.dat[5])+2000;
|
||||
if (sys->rtc.dat[3] > gregorian_days_in_month(month, year)) {
|
||||
sys->rtc.dat[3] = 1;
|
||||
sys->rtc.dat[4] = bcd_adjust(sys->rtc.dat[4]+1);
|
||||
if (sys->rtc.dat[4]>0x12) {
|
||||
sys->rtc.dat[4] = 1;
|
||||
sys->rtc.dat[5] = bcd_adjust(sys->rtc.dat[5]+1)&0xff;
|
||||
}
|
||||
regs[MRTC_SECONDS] = RTC_BCDINC(nvr->regs[MRTC_SECONDS], 1);
|
||||
if (regs[MRTC_SECONDS] >= RTC_BCD(60)) {
|
||||
regs[MRTC_SECONDS] = RTC_BCD(0);
|
||||
regs[MRTC_MINUTES] = RTC_BCDINC(regs[MRTC_MINUTES], 1);
|
||||
if (regs[MRTC_MINUTES] >= RTC_BCD(60)) {
|
||||
regs[MRTC_MINUTES] = RTC_BCD(0);
|
||||
regs[MRTC_HOURS] = RTC_BCDINC(regs[MRTC_HOURS], 1);
|
||||
if (regs[MRTC_HOURS] >= RTC_BCD(24)) {
|
||||
regs[MRTC_HOURS] = RTC_BCD(0);
|
||||
regs[MRTC_DAYS] = RTC_BCDINC(regs[MRTC_DAYS], 1);
|
||||
mon = RTC_DCB(regs[MRTC_MONTHS]);
|
||||
yr = RTC_DCB(regs[MRTC_YEARS]) + 1900;
|
||||
if (RTC_DCB(regs[MRTC_DAYS]) > nvr_get_days(mon, yr)) {
|
||||
regs[MRTC_DAYS] = RTC_BCD(1);
|
||||
regs[MRTC_MONTHS] = RTC_BCDINC(regs[MRTC_MONTHS], 1);
|
||||
if (regs[MRTC_MONTHS] > RTC_BCD(12)) {
|
||||
regs[MRTC_MONTHS] = RTC_BCD(1);
|
||||
regs[MRTC_YEARS] = RTC_BCDINC(regs[MRTC_YEARS], 1) & 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get the current NVR time. */
|
||||
static void
|
||||
rtc_time_get(uint8_t *regs, struct tm *tm)
|
||||
{
|
||||
/* NVR is in BCD data mode. */
|
||||
tm->tm_sec = RTC_DCB(regs[MRTC_SECONDS]);
|
||||
tm->tm_min = RTC_DCB(regs[MRTC_MINUTES]);
|
||||
tm->tm_hour = RTC_DCB(regs[MRTC_HOURS]);
|
||||
tm->tm_wday = (RTC_DCB(regs[MRTC_WEEKDAY]) - 1);
|
||||
tm->tm_mday = RTC_DCB(regs[MRTC_DAYS]);
|
||||
tm->tm_mon = (RTC_DCB(regs[MRTC_MONTHS]) - 1);
|
||||
tm->tm_year = RTC_DCB(regs[MRTC_YEARS]);
|
||||
#if USE_Y2K
|
||||
tm->tm_year += (RTC_DCB(regs[MRTC_CENTURY]) * 100) - 1900;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Set the current NVR time. */
|
||||
static void
|
||||
rtc_time_set(uint8_t *regs, struct tm *tm)
|
||||
{
|
||||
/* NVR is in BCD data mode. */
|
||||
regs[MRTC_SECONDS] = RTC_BCD(tm->tm_sec);
|
||||
regs[MRTC_MINUTES] = RTC_BCD(tm->tm_min);
|
||||
regs[MRTC_HOURS] = RTC_BCD(tm->tm_hour);
|
||||
regs[MRTC_WEEKDAY] = RTC_BCD(tm->tm_wday + 1);
|
||||
regs[MRTC_DAYS] = RTC_BCD(tm->tm_mday);
|
||||
regs[MRTC_MONTHS] = RTC_BCD(tm->tm_mon + 1);
|
||||
regs[MRTC_YEARS] = RTC_BCD(tm->tm_year % 100);
|
||||
#if USE_Y2K
|
||||
regs[MRTC_CENTURY] = RTC_BCD((tm->tm_year+1900) / 100);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rtc_start(nvr_t *nvr)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
/* Initialize the internal and chip times. */
|
||||
if (enable_sync) {
|
||||
/* Use the internal clock's time. */
|
||||
nvr_time_get(&tm);
|
||||
rtc_time_set(nvr->regs, &tm);
|
||||
} else {
|
||||
/* Set the internal clock from the chip time. */
|
||||
rtc_time_get(nvr->regs, &tm);
|
||||
nvr_time_set(&tm);
|
||||
}
|
||||
|
||||
#if 0
|
||||
void europc_rtc_init(void)
|
||||
{
|
||||
europc_rtc.data[0xf]=1;
|
||||
|
||||
europc_rtc.timer = timer_alloc(europc_rtc_timer);
|
||||
timer_adjust(europc_rtc.timer, 0, 0, 1.0);
|
||||
}
|
||||
/* Start the RTC - BIOS will do this. */
|
||||
nvr->regs[MRTC_CTRLSTAT] = 0x01;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* Create a valid checksum for the current NVR data. */
|
||||
static uint8_t
|
||||
rtc_checksum(uint8_t *ptr)
|
||||
{
|
||||
uint8_t sum;
|
||||
int i;
|
||||
|
||||
/* Calculate all bytes with XOR. */
|
||||
sum = 0x00;
|
||||
for (i=MRTC_CONF_A; i<=MRTC_CONF_E; i++)
|
||||
sum += ptr[i];
|
||||
|
||||
return(sum);
|
||||
}
|
||||
|
||||
|
||||
/* Reset the machine's NVR to a sane state. */
|
||||
static void
|
||||
rtc_reset(nvr_t *nvr)
|
||||
{
|
||||
/* Initialize the RTC to a known state. */
|
||||
nvr->regs[MRTC_SECONDS] = RTC_BCD(0); /* seconds */
|
||||
nvr->regs[MRTC_MINUTES] = RTC_BCD(0); /* minutes */
|
||||
nvr->regs[MRTC_HOURS] = RTC_BCD(0); /* hours */
|
||||
nvr->regs[MRTC_DAYS] = RTC_BCD(1); /* days */
|
||||
nvr->regs[MRTC_MONTHS] = RTC_BCD(1); /* months */
|
||||
nvr->regs[MRTC_YEARS] = RTC_BCD(80); /* years */
|
||||
nvr->regs[MRTC_WEEKDAY] = RTC_BCD(1); /* weekday */
|
||||
nvr->regs[MRTC_WEEKNO] = RTC_BCD(1); /* weekno */
|
||||
|
||||
/*
|
||||
* EuroPC System Configuration:
|
||||
*
|
||||
* [A] unknown
|
||||
*
|
||||
* [B] 7 1 bootdrive extern
|
||||
* 0 bootdribe intern
|
||||
* 6:5 11 invalid hard disk type
|
||||
* 10 hard disk installed, type 2
|
||||
* 01 hard disk installed, type 1
|
||||
* 00 hard disk not installed
|
||||
* 4:3 11 invalid external drive type
|
||||
* 10 external drive 720K
|
||||
* 01 external drive 360K
|
||||
* 00 external drive disabled
|
||||
* 2 unknown
|
||||
* 1:0 11 invalid internal drive type
|
||||
* 10 internal drive 360K
|
||||
* 01 internal drive 720K
|
||||
* 00 internal drive disabled
|
||||
*
|
||||
* [C] 7:6 unknown
|
||||
* 5 monitor detection OFF
|
||||
* 4 unknown
|
||||
* 3:2 11 illegal memory size
|
||||
* 10 512K
|
||||
* 01 256K
|
||||
* 00 640K
|
||||
* 1:0 11 illegal game port
|
||||
* 10 gameport as mouse port
|
||||
* 01 gameport as joysticks
|
||||
* 00 gameport disabled
|
||||
*
|
||||
* [D] 7:6 10 9MHz CPU speed
|
||||
* 01 7MHz CPU speed
|
||||
* 00 4.77 MHz CPU
|
||||
* 5 unknown
|
||||
* 4 external: color, internal: mono
|
||||
* 3 unknown
|
||||
* 2 internal video ON
|
||||
* 1:0 11 mono
|
||||
* 10 color80
|
||||
* 01 color40
|
||||
* 00 special (EGA,VGA etc)
|
||||
*
|
||||
* [E] 7:4 unknown
|
||||
* 3:0 country (00=Deutschland, 0A=ASCII)
|
||||
*/
|
||||
nvr->regs[MRTC_CONF_A] = 0x00; /* CONFIG A */
|
||||
nvr->regs[MRTC_CONF_B] = 0x0A; /* CONFIG B */
|
||||
nvr->regs[MRTC_CONF_C] = 0x28; /* CONFIG C */
|
||||
nvr->regs[MRTC_CONF_D] = 0x12; /* CONFIG D */
|
||||
nvr->regs[MRTC_CONF_E] = 0x0A; /* CONFIG E */
|
||||
|
||||
nvr->regs[MRTC_CHECK_LO] = 0x00; /* checksum (LO) */
|
||||
nvr->regs[MRTC_CHECK_HI] = 0x00; /* checksum (HI) */
|
||||
|
||||
nvr->regs[MRTC_CTRLSTAT] = 0x01; /* status/control */
|
||||
|
||||
/* Generate a valid checksum. */
|
||||
nvr->regs[MRTC_CHECK_LO] = rtc_checksum(nvr->regs);
|
||||
}
|
||||
|
||||
|
||||
/* Execute a JIM control command. */
|
||||
static void
|
||||
jim_action(vm_t *sys, uint8_t reg, uint8_t val)
|
||||
jim_set(europc_t *sys, uint8_t reg, uint8_t val)
|
||||
{
|
||||
switch(reg) {
|
||||
case 0: /* MISC control (WO) */
|
||||
//pclog("EuroPC: write MISC = %02x\n", val);
|
||||
// bit0: enable MOUSE
|
||||
// bit1: enable joystick
|
||||
break;
|
||||
|
||||
case 2: /* AGA control */
|
||||
//pclog("EuroPC: write AGA = %02x\n", val);
|
||||
if (! (val & 0x80)) {
|
||||
/* Reset AGA. */
|
||||
break;
|
||||
@@ -276,7 +413,6 @@ jim_action(vm_t *sys, uint8_t reg, uint8_t val)
|
||||
break;
|
||||
|
||||
case 4: /* CPU Speed control */
|
||||
//pclog("EuroPC: write CPUCLK = %02x\n", val);
|
||||
switch(val & 0xc0) {
|
||||
case 0x00: /* 4.77 MHz */
|
||||
// cpu_set_clockscale(0, 1.0/2);
|
||||
@@ -304,7 +440,7 @@ jim_action(vm_t *sys, uint8_t reg, uint8_t val)
|
||||
static void
|
||||
jim_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
vm_t *sys = (vm_t *)priv;
|
||||
europc_t *sys = (europc_t *)priv;
|
||||
uint8_t b;
|
||||
|
||||
#if EUROPC_DEBUG > 1
|
||||
@@ -320,28 +456,30 @@ jim_write(uint16_t addr, uint8_t val, void *priv)
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
jim_action(sys, (addr & 0x07), val);
|
||||
jim_set(sys, (addr & 0x07), val);
|
||||
break;
|
||||
|
||||
case 0x0A: /* M3002 RTC INDEX/DATA register */
|
||||
switch(sys->rtc.stat) {
|
||||
case 0x0a: /* M3002 RTC INDEX/DATA register */
|
||||
switch(sys->nvr_stat) {
|
||||
case 0: /* save index */
|
||||
sys->rtc.addr = val & 0x0f;
|
||||
sys->rtc.stat++;
|
||||
sys->nvr_addr = val & 0x0f;
|
||||
sys->nvr_stat++;
|
||||
break;
|
||||
|
||||
case 1: /* save data HI nibble */
|
||||
b = sys->rtc.dat[sys->rtc.addr] & 0x0f;
|
||||
b = sys->nvr.regs[sys->nvr_addr] & 0x0f;
|
||||
b |= (val << 4);
|
||||
sys->rtc.dat[sys->rtc.addr] = b;
|
||||
sys->rtc.stat++;
|
||||
sys->nvr.regs[sys->nvr_addr] = b;
|
||||
sys->nvr_stat++;
|
||||
nvr_dosave++;
|
||||
break;
|
||||
|
||||
case 2: /* save data LO nibble */
|
||||
b = sys->rtc.dat[sys->rtc.addr] & 0xf0;
|
||||
b = sys->nvr.regs[sys->nvr_addr] & 0xf0;
|
||||
b |= (val & 0x0f);
|
||||
sys->rtc.dat[sys->rtc.addr] = b;
|
||||
sys->rtc.stat = 0;
|
||||
sys->nvr.regs[sys->nvr_addr] = b;
|
||||
sys->nvr_stat = 0;
|
||||
nvr_dosave++;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -357,7 +495,7 @@ jim_write(uint16_t addr, uint8_t val, void *priv)
|
||||
static uint8_t
|
||||
jim_read(uint16_t addr, void *priv)
|
||||
{
|
||||
vm_t *sys = (vm_t *)priv;
|
||||
europc_t *sys = (europc_t *)priv;
|
||||
uint8_t r = 0xff;
|
||||
|
||||
switch (addr & 0x000f) {
|
||||
@@ -375,20 +513,20 @@ jim_read(uint16_t addr, void *priv)
|
||||
r = sys->regs[addr & 0x07];
|
||||
break;
|
||||
|
||||
case 0x0A: /* M3002 RTC INDEX/DATA register */
|
||||
switch(sys->rtc.stat) {
|
||||
case 0x0a: /* M3002 RTC INDEX/DATA register */
|
||||
switch(sys->nvr_stat) {
|
||||
case 0:
|
||||
r = 0x00;
|
||||
break;
|
||||
|
||||
case 1: /* read data HI nibble */
|
||||
r = (sys->rtc.dat[sys->rtc.addr] >> 4);
|
||||
sys->rtc.stat++;
|
||||
r = (sys->nvr.regs[sys->nvr_addr] >> 4);
|
||||
sys->nvr_stat++;
|
||||
break;
|
||||
|
||||
case 2: /* read data LO nibble */
|
||||
r = (sys->rtc.dat[sys->rtc.addr] & 0x0f);
|
||||
sys->rtc.stat = 0;
|
||||
r = (sys->nvr.regs[sys->nvr_addr] & 0x0f);
|
||||
sys->nvr_stat = 0;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -406,120 +544,29 @@ jim_read(uint16_t addr, void *priv)
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
rtc_checksum(uint8_t *ptr)
|
||||
{
|
||||
uint8_t sum;
|
||||
int i;
|
||||
|
||||
/* Calculate all bytes with XOR. */
|
||||
sum = 0x00;
|
||||
for (i=MRTC_CONF_A; i<=MRTC_CONF_E; i++)
|
||||
sum += ptr[i];
|
||||
|
||||
return(sum);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the mainboard 'device' of the machine.
|
||||
*/
|
||||
/* Initialize the mainboard 'device' of the machine. */
|
||||
static void *
|
||||
europc_boot(device_t *info)
|
||||
{
|
||||
vm_t *sys = vm;
|
||||
europc_t *sys = &europc;
|
||||
uint8_t b;
|
||||
|
||||
#if EUROPC_DEBUG
|
||||
pclog("EuroPC: booting mainboard..\n");
|
||||
#endif
|
||||
|
||||
/* Try to load the NVR from file. */
|
||||
if (! nvr_load()) {
|
||||
/* Load failed, reset to defaults. */
|
||||
sys->rtc.dat[0x00] = 0x00; /* RTC seconds */
|
||||
sys->rtc.dat[0x01] = 0x00; /* RTC minutes */
|
||||
sys->rtc.dat[0x02] = 0x00; /* RTC hours */
|
||||
sys->rtc.dat[0x03] = 0x01; /* RTC days */
|
||||
sys->rtc.dat[0x04] = 0x01; /* RTC months */
|
||||
sys->rtc.dat[0x05] = 0x17; /* RTC years */
|
||||
sys->rtc.dat[0x06] = 0x01; /* RTC weekday */
|
||||
sys->rtc.dat[0x07] = 0x01; /* RTC weekno */
|
||||
|
||||
/*
|
||||
* EuroPC System Configuration:
|
||||
*
|
||||
* [A] unknown
|
||||
*
|
||||
* [B] 7 1 bootdrive extern
|
||||
* 0 bootdribe intern
|
||||
* 6:5 11 invalid hard disk type
|
||||
* 10 hard disk installed, type 2
|
||||
* 01 hard disk installed, type 1
|
||||
* 00 hard disk not installed
|
||||
* 4:3 11 invalid external drive type
|
||||
* 10 external drive 720K
|
||||
* 01 external drive 360K
|
||||
* 00 external drive disabled
|
||||
* 2 unknown
|
||||
* 1:0 11 invalid internal drive type
|
||||
* 10 internal drive 360K
|
||||
* 01 internal drive 720K
|
||||
* 00 internal drive disabled
|
||||
*
|
||||
* [C] 7:6 unknown
|
||||
* 5 monitor detection OFF
|
||||
* 4 unknown
|
||||
* 3:2 11 illegal memory size
|
||||
* 10 512K
|
||||
* 01 256K
|
||||
* 00 640K
|
||||
* 1:0 11 illegal game port
|
||||
* 10 gameport as mouse port
|
||||
* 01 gameport as joysticks
|
||||
* 00 gameport disabled
|
||||
*
|
||||
* [D] 7:6 10 9MHz CPU speed
|
||||
* 01 7MHz CPU speed
|
||||
* 00 4.77 MHz CPU
|
||||
* 5 unknown
|
||||
* 4 external: color, internal: mono
|
||||
* 3 unknown
|
||||
* 2 internal video ON
|
||||
* 1:0 11 mono
|
||||
* 10 color80
|
||||
* 01 color40
|
||||
* 00 special (EGA,VGA etc)
|
||||
*
|
||||
* [E] 7:4 unknown
|
||||
* 3:0 country (00=Deutschland, 0A=ASCII)
|
||||
*/
|
||||
sys->rtc.dat[MRTC_CONF_A] = 0x00; /* CONFIG A */
|
||||
sys->rtc.dat[MRTC_CONF_B] = 0x0A; /* CONFIG B */
|
||||
sys->rtc.dat[MRTC_CONF_C] = 0x28; /* CONFIG C */
|
||||
sys->rtc.dat[MRTC_CONF_D] = 0x12; /* CONFIG D */
|
||||
sys->rtc.dat[MRTC_CONF_E] = 0x0A; /* CONFIG E */
|
||||
|
||||
sys->rtc.dat[MRTC_CHECK_LO] = 0x44; /* checksum (LO) */
|
||||
sys->rtc.dat[MRTC_CHECK_HI] = 0x00; /* checksum (HI) */
|
||||
|
||||
sys->rtc.dat[MRTC_CTRLSTAT] = 0x01; /* status/control */
|
||||
|
||||
/* Provide correct checksum. */
|
||||
sys->rtc.dat[MRTC_CHECK_LO] = rtc_checksum(sys->rtc.dat);
|
||||
}
|
||||
pclog("EuroPC: NVR=[ %02x %02x %02x %02x %02x ] %sVALID\n",
|
||||
sys->rtc.dat[MRTC_CONF_A], sys->rtc.dat[MRTC_CONF_B],
|
||||
sys->rtc.dat[MRTC_CONF_C], sys->rtc.dat[MRTC_CONF_D],
|
||||
sys->rtc.dat[MRTC_CONF_E],
|
||||
(sys->rtc.dat[MRTC_CHECK_LO]!=rtc_checksum(sys->rtc.dat))?"IN":"");
|
||||
sys->nvr.regs[MRTC_CONF_A], sys->nvr.regs[MRTC_CONF_B],
|
||||
sys->nvr.regs[MRTC_CONF_C], sys->nvr.regs[MRTC_CONF_D],
|
||||
sys->nvr.regs[MRTC_CONF_E],
|
||||
(sys->nvr.regs[MRTC_CHECK_LO]!=rtc_checksum(sys->nvr.regs))?"IN":"");
|
||||
|
||||
/*
|
||||
* Now that we have initialized the NVR (either from file,
|
||||
* or by setting it to defaults) we can start overriding it
|
||||
* with values set by the 86Box user.
|
||||
* with values set by the user.
|
||||
*/
|
||||
b = (sys->rtc.dat[MRTC_CONF_D] & ~0x17);
|
||||
b = (sys->nvr.regs[MRTC_CONF_D] & ~0x17);
|
||||
switch(gfxcard) {
|
||||
case GFX_CGA: /* Color, CGA */
|
||||
case GFX_COLORPLUS: /* Color, Hercules ColorPlus */
|
||||
@@ -536,10 +583,10 @@ europc_boot(device_t *info)
|
||||
b |= 0x10; /* external video, special */
|
||||
|
||||
}
|
||||
sys->rtc.dat[MRTC_CONF_D] = b;
|
||||
sys->nvr.regs[MRTC_CONF_D] = b;
|
||||
|
||||
/* Update the memory size. */
|
||||
b = (sys->rtc.dat[MRTC_CONF_C] & 0xf3);
|
||||
b = (sys->nvr.regs[MRTC_CONF_C] & 0xf3);
|
||||
switch(mem_size) {
|
||||
case 256:
|
||||
b |= 0x04;
|
||||
@@ -553,10 +600,10 @@ europc_boot(device_t *info)
|
||||
b |= 0x00;
|
||||
break;
|
||||
}
|
||||
sys->rtc.dat[MRTC_CONF_C] = b;
|
||||
sys->nvr.regs[MRTC_CONF_C] = b;
|
||||
|
||||
/* Update CPU speed. */
|
||||
b = (sys->rtc.dat[MRTC_CONF_D] & 0x3f);
|
||||
b = (sys->nvr.regs[MRTC_CONF_D] & 0x3f);
|
||||
switch(cpu) {
|
||||
case 0: /* 8088, 4.77 MHz */
|
||||
b |= 0x00;
|
||||
@@ -570,26 +617,26 @@ europc_boot(device_t *info)
|
||||
b |= 0x80;
|
||||
break;
|
||||
}
|
||||
sys->rtc.dat[MRTC_CONF_D] = b;
|
||||
sys->nvr.regs[MRTC_CONF_D] = b;
|
||||
|
||||
/* Set up game port. */
|
||||
b = (sys->rtc.dat[MRTC_CONF_C] & 0xfc);
|
||||
b = (sys->nvr.regs[MRTC_CONF_C] & 0xfc);
|
||||
if (mouse_type == MOUSE_TYPE_LOGIBUS) {
|
||||
b |= 0x01; /* enable port as MOUSE */
|
||||
} else if (joystick_type != 7) {
|
||||
b |= 0x02; /* enable port as joysticks */
|
||||
device_add(&gameport_device);
|
||||
}
|
||||
sys->rtc.dat[MRTC_CONF_C] = b;
|
||||
sys->nvr.regs[MRTC_CONF_C] = b;
|
||||
|
||||
#if 0
|
||||
/* Set up floppy types. */
|
||||
sys->rtc.dat[MRTC_CONF_B] = 0x2A;
|
||||
sys->nvr.regs[MRTC_CONF_B] = 0x2a;
|
||||
#endif
|
||||
|
||||
/* Validate the NVR checksum. */
|
||||
sys->rtc.dat[MRTC_CHECK_LO] = rtc_checksum(sys->rtc.dat);
|
||||
nvr_save();
|
||||
/* Validate the NVR checksum and save. */
|
||||
sys->nvr.regs[MRTC_CHECK_LO] = rtc_checksum(sys->nvr.regs);
|
||||
nvr_dosave++;
|
||||
|
||||
/*
|
||||
* Allocate the system's I/O handlers.
|
||||
@@ -600,11 +647,10 @@ europc_boot(device_t *info)
|
||||
* the way of other cards that need this range.
|
||||
*/
|
||||
io_sethandler(sys->jim, 16,
|
||||
jim_read, NULL, NULL,
|
||||
jim_write, NULL, NULL, sys);
|
||||
jim_read,NULL,NULL, jim_write,NULL,NULL, sys);
|
||||
|
||||
/* Only after JIM has been initialized. */
|
||||
device_add(&keyboard_xt_device);
|
||||
(void)device_add(&keyboard_xt_device);
|
||||
|
||||
/*
|
||||
* Set up and enable the HD20 disk controller.
|
||||
@@ -612,7 +658,7 @@ europc_boot(device_t *info)
|
||||
* We only do this if we have not configured another one.
|
||||
*/
|
||||
if (hdc_current == 1)
|
||||
device_add(&europc_hdc_device);
|
||||
(void)device_add(&europc_hdc_device);
|
||||
|
||||
return(sys);
|
||||
}
|
||||
@@ -621,13 +667,10 @@ europc_boot(device_t *info)
|
||||
static void
|
||||
europc_close(void *priv)
|
||||
{
|
||||
nvr_t *nvr = &vm->nvr;
|
||||
nvr_t *nvr = &europc.nvr;
|
||||
|
||||
if (nvr->fname != NULL)
|
||||
free(nvr->fname);
|
||||
|
||||
free(vm);
|
||||
vm = NULL;
|
||||
if (nvr->fn != NULL)
|
||||
free(nvr->fn);
|
||||
}
|
||||
|
||||
|
||||
@@ -655,9 +698,7 @@ static device_config_t europc_config[] = {
|
||||
device_t europc_device = {
|
||||
"EuroPC System Board",
|
||||
0, 0,
|
||||
europc_boot, /* init */
|
||||
europc_close, /* close */
|
||||
NULL,
|
||||
europc_boot, europc_close, NULL,
|
||||
NULL, NULL, NULL, NULL,
|
||||
europc_config
|
||||
};
|
||||
@@ -674,36 +715,28 @@ device_t europc_device = {
|
||||
void
|
||||
machine_europc_init(machine_t *model)
|
||||
{
|
||||
vm_t *sys;
|
||||
|
||||
/* Allocate machine data. */
|
||||
sys = (vm_t *)malloc(sizeof(vm_t));
|
||||
if (sys == NULL) {
|
||||
pclog("EuroPC: unable to allocate machine data!\n");
|
||||
return;
|
||||
}
|
||||
memset(sys, 0x00, sizeof(vm_t));
|
||||
sys->jim = 0x0250;
|
||||
vm = sys;
|
||||
/* Clear the machine state. */
|
||||
memset(&europc, 0x00, sizeof(europc_t));
|
||||
europc.jim = 0x0250;
|
||||
|
||||
machine_common_init(model);
|
||||
nmi_init();
|
||||
mem_add_bios();
|
||||
|
||||
/* This is machine specific. */
|
||||
vm->nvr.mask = model->nvrmask;
|
||||
vm->nvr.irq = -1;
|
||||
europc.nvr.size = model->nvrmask + 1;
|
||||
europc.nvr.irq = -1;
|
||||
|
||||
/* Set up any local handlers here. */
|
||||
vm->nvr.load = load_nvr;
|
||||
vm->nvr.save = save_nvr;
|
||||
vm->nvr.hook = rtc_hook;
|
||||
europc.nvr.reset = rtc_reset;
|
||||
europc.nvr.start = rtc_start;
|
||||
europc.nvr.tick = rtc_tick;
|
||||
|
||||
/* Initialize the actual NVR. */
|
||||
nvr_init(&vm->nvr);
|
||||
nvr_init(&europc.nvr);
|
||||
|
||||
/* Enable and set up the FDC. */
|
||||
device_add(&fdc_xt_device);
|
||||
(void)device_add(&fdc_xt_device);
|
||||
|
||||
/* Enable and set up the mainboard device. */
|
||||
device_add(&europc_device);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
* 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 86Box distribution.
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implementation of the EuroPC HD20 internal controller.
|
||||
*
|
||||
@@ -20,13 +20,45 @@
|
||||
* This driver is based on the information found in the IBM-PC
|
||||
* Technical Reference manual, pp 187 and on.
|
||||
*
|
||||
* Version: @(#)europc_hdc.c 1.0.2 2017/11/18
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Based on the original "xebec.c" from Sarah Walker.
|
||||
*
|
||||
* Version: @(#)m_europc_hdc.c 1.0.2 2018/03/11
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2008-2017 Sarah Walker.
|
||||
* Copyright 2017 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.
|
||||
*/
|
||||
#define __USE_LARGEFILE64
|
||||
#define _LARGEFILE_SOURCE
|
||||
@@ -44,11 +76,12 @@
|
||||
#include "../timer.h"
|
||||
#include "../disk/hdc.h"
|
||||
#include "../disk/hdd.h"
|
||||
#include "../plat.h"
|
||||
#include "../ui.h"
|
||||
#include "machine.h"
|
||||
|
||||
|
||||
#define HDC_DEBUG 1
|
||||
#define HDC_DEBUG 0
|
||||
#define HDC_NEWPARAMS 1 /* use NEW parameter block */
|
||||
|
||||
#define HDD_IOADDR 0x0320
|
||||
|
||||
@@ -40,7 +40,9 @@ static struct
|
||||
uint8_t io_id;
|
||||
|
||||
mem_mapping_t shadow_mapping;
|
||||
mem_mapping_t split_mapping;
|
||||
mem_mapping_t expansion_mapping;
|
||||
mem_mapping_t cache_mapping;
|
||||
|
||||
uint8_t (*planar_read)(uint16_t port);
|
||||
void (*planar_write)(uint16_t port, uint8_t val);
|
||||
@@ -48,11 +50,99 @@ static struct
|
||||
uint8_t mem_regs[3];
|
||||
|
||||
uint32_t split_addr, split_size;
|
||||
uint32_t split_phys;
|
||||
|
||||
uint8_t mem_pos_regs[8];
|
||||
uint8_t mem_2mb_pos_regs[8];
|
||||
|
||||
int pending_cache_miss;
|
||||
} ps2;
|
||||
|
||||
/*The model 70 type 3/4 BIOS performs cache testing. Since 86Box doesn't have any
|
||||
proper cache emulation, it's faked a bit here.
|
||||
|
||||
Port E2 is used for cache diagnostics. Bit 7 seems to be set on a cache miss,
|
||||
toggling bit 2 seems to clear this. The BIOS performs at least the following
|
||||
tests :
|
||||
|
||||
- Disable RAM, access low 64kb (386) / 8kb (486), execute code from cache to
|
||||
access low memory and verify that there are no cache misses.
|
||||
- Write to low memory using DMA, read low memory and verify that all accesses
|
||||
cause cache misses.
|
||||
- Read low memory, verify that first access is cache miss. Read again and
|
||||
verify that second access is cache hit.
|
||||
|
||||
These tests are also performed on the 486 model 70, despite there being no
|
||||
external cache on this system. Port E2 seems to control the internal cache on
|
||||
these systems. Presumably this port is connected to KEN#/FLUSH# on the 486.
|
||||
This behaviour is required to pass the timer interrupt test on the 486 version
|
||||
- the BIOS uses a fixed length loop that will terminate too early on a 486/25
|
||||
if it executes from internal cache.
|
||||
|
||||
To handle this, 86Box uses some basic heuristics :
|
||||
- If cache is enabled but RAM is disabled, accesses to low memory go directly
|
||||
to cache memory.
|
||||
- Reads to cache addresses not 'valid' will set the cache miss flag, and mark
|
||||
that line as valid.
|
||||
- Cache flushes will clear the valid array.
|
||||
- DMA via the undocumented PS/2 command 0xb will clear the valid array.
|
||||
- Disabling the cache will clear the valid array.
|
||||
- Disabling the cache will also mark shadowed ROM areas as using ROM timings.
|
||||
This works around the timing loop mentioned above.
|
||||
*/
|
||||
|
||||
static uint8_t ps2_cache[65536];
|
||||
static int ps2_cache_valid[65536/8];
|
||||
|
||||
static uint8_t ps2_read_cache_ram(uint32_t addr, void *priv)
|
||||
{
|
||||
// pclog("ps2_read_cache_ram: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc);
|
||||
if (!ps2_cache_valid[addr >> 3])
|
||||
{
|
||||
ps2_cache_valid[addr >> 3] = 1;
|
||||
ps2.mem_regs[2] |= 0x80;
|
||||
}
|
||||
else
|
||||
ps2.pending_cache_miss = 0;
|
||||
|
||||
return ps2_cache[addr];
|
||||
}
|
||||
static uint16_t ps2_read_cache_ramw(uint32_t addr, void *priv)
|
||||
{
|
||||
// pclog("ps2_read_cache_ramw: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc);
|
||||
if (!ps2_cache_valid[addr >> 3])
|
||||
{
|
||||
ps2_cache_valid[addr >> 3] = 1;
|
||||
ps2.mem_regs[2] |= 0x80;
|
||||
}
|
||||
else
|
||||
ps2.pending_cache_miss = 0;
|
||||
|
||||
return *(uint16_t *)&ps2_cache[addr];
|
||||
}
|
||||
static uint32_t ps2_read_cache_raml(uint32_t addr, void *priv)
|
||||
{
|
||||
// pclog("ps2_read_cache_raml: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc);
|
||||
if (!ps2_cache_valid[addr >> 3])
|
||||
{
|
||||
ps2_cache_valid[addr >> 3] = 1;
|
||||
ps2.mem_regs[2] |= 0x80;
|
||||
}
|
||||
else
|
||||
ps2.pending_cache_miss = 0;
|
||||
|
||||
return *(uint32_t *)&ps2_cache[addr];
|
||||
}
|
||||
static void ps2_write_cache_ram(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
// pclog("ps2_write_cache_ram: addr=%08x val=%02x %04x:%04x %i\n", addr, val, CS,cpu_state.pc, ins);
|
||||
ps2_cache[addr] = val;
|
||||
}
|
||||
|
||||
void ps2_cache_clean(void)
|
||||
{
|
||||
memset(ps2_cache_valid, 0, sizeof(ps2_cache_valid));
|
||||
}
|
||||
|
||||
static uint8_t ps2_read_shadow_ram(uint32_t addr, void *priv)
|
||||
{
|
||||
@@ -85,6 +175,37 @@ static void ps2_write_shadow_raml(uint32_t addr, uint32_t val, void *priv)
|
||||
mem_write_raml(addr, val, priv);
|
||||
}
|
||||
|
||||
static uint8_t ps2_read_split_ram(uint32_t addr, void *priv)
|
||||
{
|
||||
addr = (addr % (ps2.split_size << 10)) + ps2.split_phys;
|
||||
return mem_read_ram(addr, priv);
|
||||
}
|
||||
static uint16_t ps2_read_split_ramw(uint32_t addr, void *priv)
|
||||
{
|
||||
addr = (addr % (ps2.split_size << 10)) + ps2.split_phys;
|
||||
return mem_read_ramw(addr, priv);
|
||||
}
|
||||
static uint32_t ps2_read_split_raml(uint32_t addr, void *priv)
|
||||
{
|
||||
addr = (addr % (ps2.split_size << 10)) + ps2.split_phys;
|
||||
return mem_read_raml(addr, priv);
|
||||
}
|
||||
static void ps2_write_split_ram(uint32_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
addr = (addr % (ps2.split_size << 10)) + ps2.split_phys;
|
||||
mem_write_ram(addr, val, priv);
|
||||
}
|
||||
static void ps2_write_split_ramw(uint32_t addr, uint16_t val, void *priv)
|
||||
{
|
||||
addr = (addr % (ps2.split_size << 10)) + ps2.split_phys;
|
||||
mem_write_ramw(addr, val, priv);
|
||||
}
|
||||
static void ps2_write_split_raml(uint32_t addr, uint32_t val, void *priv)
|
||||
{
|
||||
addr = (addr % (ps2.split_size << 10)) + ps2.split_phys;
|
||||
mem_write_raml(addr, val, priv);
|
||||
}
|
||||
|
||||
|
||||
#define PS2_SETUP_IO 0x80
|
||||
#define PS2_SETUP_VGA 0x20
|
||||
@@ -139,6 +260,30 @@ static uint8_t model_55sx_read(uint16_t port)
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static uint8_t model_70_type3_read(uint16_t port)
|
||||
{
|
||||
switch (port)
|
||||
{
|
||||
case 0x100:
|
||||
return 0xff;
|
||||
case 0x101:
|
||||
return 0xf9;
|
||||
case 0x102:
|
||||
return ps2.option[0];
|
||||
case 0x103:
|
||||
return ps2.option[1];
|
||||
case 0x104:
|
||||
return ps2.option[2];
|
||||
case 0x105:
|
||||
return ps2.option[3];
|
||||
case 0x106:
|
||||
return ps2.subaddr_lo;
|
||||
case 0x107:
|
||||
return ps2.subaddr_hi;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static uint8_t model_80_read(uint16_t port)
|
||||
{
|
||||
switch (port)
|
||||
@@ -296,6 +441,56 @@ static void model_55sx_write(uint16_t port, uint8_t val)
|
||||
}
|
||||
}
|
||||
|
||||
static void model_70_type3_write(uint16_t port, uint8_t val)
|
||||
{
|
||||
switch (port)
|
||||
{
|
||||
case 0x100:
|
||||
break;
|
||||
case 0x101:
|
||||
break;
|
||||
case 0x102:
|
||||
lpt1_remove();
|
||||
serial_remove(1);
|
||||
if (val & 0x04)
|
||||
{
|
||||
if (val & 0x08)
|
||||
serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ);
|
||||
else
|
||||
serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ);
|
||||
}
|
||||
else
|
||||
serial_remove(1);
|
||||
if (val & 0x10)
|
||||
{
|
||||
switch ((val >> 5) & 3)
|
||||
{
|
||||
case 0:
|
||||
lpt1_init(0x3bc);
|
||||
break;
|
||||
case 1:
|
||||
lpt1_init(0x378);
|
||||
break;
|
||||
case 2:
|
||||
lpt1_init(0x278);
|
||||
break;
|
||||
}
|
||||
}
|
||||
ps2.option[0] = val;
|
||||
break;
|
||||
case 0x105:
|
||||
ps2.option[3] = val;
|
||||
break;
|
||||
case 0x106:
|
||||
ps2.subaddr_lo = val;
|
||||
break;
|
||||
case 0x107:
|
||||
ps2.subaddr_hi = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void model_80_write(uint16_t port, uint8_t val)
|
||||
{
|
||||
switch (port)
|
||||
@@ -677,7 +872,7 @@ static void ps2_mca_board_model_55sx_init()
|
||||
|
||||
static void mem_encoding_update()
|
||||
{
|
||||
mem_split_disable(ps2.split_size, ps2.split_addr);
|
||||
mem_mapping_disable(&ps2.split_mapping);
|
||||
|
||||
ps2.split_addr = ((uint32_t) (ps2.mem_regs[0] & 0xf)) << 20;
|
||||
|
||||
@@ -699,12 +894,16 @@ static void mem_encoding_update()
|
||||
|
||||
if (!(ps2.mem_regs[1] & 8))
|
||||
{
|
||||
if (ps2.mem_regs[1] & 4)
|
||||
if (ps2.mem_regs[1] & 4) {
|
||||
ps2.split_size = 384;
|
||||
else
|
||||
ps2.split_phys = 0x80000;
|
||||
} else {
|
||||
ps2.split_size = 256;
|
||||
ps2.split_phys = 0xa0000;
|
||||
}
|
||||
|
||||
mem_split_enable(ps2.split_size, ps2.split_addr);
|
||||
mem_mapping_set_exec(&ps2.split_mapping, &ram[ps2.split_phys]);
|
||||
mem_mapping_set_addr(&ps2.split_mapping, ps2.split_addr, ps2.split_size << 10);
|
||||
|
||||
/* pclog("PS/2 Model 80-111: Split memory block enabled at %08X\n", ps2.split_addr); */
|
||||
} /* else {
|
||||
@@ -737,6 +936,169 @@ static void mem_encoding_write(uint16_t addr, uint8_t val, void *p)
|
||||
mem_encoding_update();
|
||||
}
|
||||
|
||||
static uint8_t mem_encoding_read_cached(uint16_t addr, void *p)
|
||||
{
|
||||
switch (addr)
|
||||
{
|
||||
case 0xe0:
|
||||
return ps2.mem_regs[0];
|
||||
case 0xe1:
|
||||
return ps2.mem_regs[1];
|
||||
case 0xe2:
|
||||
return ps2.mem_regs[2];
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
static void mem_encoding_write_cached(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
uint8_t old;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0xe0:
|
||||
ps2.mem_regs[0] = val;
|
||||
break;
|
||||
case 0xe1:
|
||||
ps2.mem_regs[1] = val;
|
||||
break;
|
||||
case 0xe2:
|
||||
old = ps2.mem_regs[2];
|
||||
ps2.mem_regs[2] = (ps2.mem_regs[2] & 0x80) | (val & ~0x88);
|
||||
if (val & 2)
|
||||
{
|
||||
// pclog("Clear latch - %i\n", ps2.pending_cache_miss);
|
||||
if (ps2.pending_cache_miss)
|
||||
ps2.mem_regs[2] |= 0x80;
|
||||
else
|
||||
ps2.mem_regs[2] &= ~0x80;
|
||||
ps2.pending_cache_miss = 0;
|
||||
}
|
||||
|
||||
if ((val & 0x21) == 0x20 && (old & 0x21) != 0x20)
|
||||
ps2.pending_cache_miss = 1;
|
||||
if ((val & 0x21) == 0x01 && (old & 0x21) != 0x01)
|
||||
ps2_cache_clean();
|
||||
if (val & 0x01)
|
||||
ram_mid_mapping.flags |= MEM_MAPPING_ROM;
|
||||
else
|
||||
ram_mid_mapping.flags &= ~MEM_MAPPING_ROM;
|
||||
break;
|
||||
}
|
||||
// pclog("mem_encoding_write: addr=%02x val=%02x %04x:%04x %02x %02x\n", addr, val, CS,cpu_state.pc, ps2.mem_regs[1],ps2.mem_regs[2]);
|
||||
mem_encoding_update();
|
||||
if ((ps2.mem_regs[1] & 0x10) && (ps2.mem_regs[2] & 0x21) == 0x20)
|
||||
{
|
||||
mem_mapping_disable(&ram_low_mapping);
|
||||
mem_mapping_enable(&ps2.cache_mapping);
|
||||
flushmmucache();
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_mapping_disable(&ps2.cache_mapping);
|
||||
mem_mapping_enable(&ram_low_mapping);
|
||||
flushmmucache();
|
||||
}
|
||||
}
|
||||
|
||||
static void ps2_mca_board_model_70_type34_init(int is_type4)
|
||||
{
|
||||
ps2_mca_board_common_init();
|
||||
|
||||
mem_remap_top_256k();
|
||||
ps2.split_addr = mem_size * 1024;
|
||||
mca_init(4);
|
||||
|
||||
ps2.planar_read = model_70_type3_read;
|
||||
ps2.planar_write = model_70_type3_write;
|
||||
|
||||
device_add(&ps2_nvr_device);
|
||||
|
||||
io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached, NULL, NULL, NULL);
|
||||
|
||||
ps2.mem_regs[1] = 2;
|
||||
|
||||
switch (mem_size/1024)
|
||||
{
|
||||
case 2:
|
||||
ps2.option[1] = 0xa6;
|
||||
ps2.option[2] = 0x01;
|
||||
break;
|
||||
case 4:
|
||||
ps2.option[1] = 0xaa;
|
||||
ps2.option[2] = 0x01;
|
||||
break;
|
||||
case 6:
|
||||
ps2.option[1] = 0xca;
|
||||
ps2.option[2] = 0x01;
|
||||
break;
|
||||
case 8:
|
||||
default:
|
||||
ps2.option[1] = 0xca;
|
||||
ps2.option[2] = 0x02;
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_type4)
|
||||
ps2.option[2] |= 0x04; /*486 CPU*/
|
||||
|
||||
mem_mapping_add(&ps2.cache_mapping,
|
||||
0,
|
||||
is_type4 ? (8 * 1024) : (64 * 1024),
|
||||
ps2_read_cache_ram,
|
||||
ps2_read_cache_ramw,
|
||||
ps2_read_cache_raml,
|
||||
ps2_write_cache_ram,
|
||||
NULL,
|
||||
NULL,
|
||||
ps2_cache,
|
||||
MEM_MAPPING_INTERNAL,
|
||||
NULL);
|
||||
mem_mapping_disable(&ps2.cache_mapping);
|
||||
|
||||
if (mem_size > 8192)
|
||||
{
|
||||
/* Only 8 MB supported on planar, create a memory expansion card for the rest */
|
||||
mem_mapping_set_addr(&ram_high_mapping, 0x100000, 0x700000);
|
||||
|
||||
ps2.mem_pos_regs[0] = 0xff;
|
||||
ps2.mem_pos_regs[1] = 0xfc;
|
||||
|
||||
switch (mem_size/1024)
|
||||
{
|
||||
case 10:
|
||||
ps2.mem_pos_regs[4] = 0xfe;
|
||||
break;
|
||||
case 12:
|
||||
ps2.mem_pos_regs[4] = 0xfa;
|
||||
break;
|
||||
case 14:
|
||||
ps2.mem_pos_regs[4] = 0xea;
|
||||
break;
|
||||
case 16:
|
||||
ps2.mem_pos_regs[4] = 0xaa;
|
||||
break;
|
||||
}
|
||||
|
||||
mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL);
|
||||
mem_mapping_add(&ps2.expansion_mapping,
|
||||
0x800000,
|
||||
(mem_size - 8192)*1024,
|
||||
mem_read_ram,
|
||||
mem_read_ramw,
|
||||
mem_read_raml,
|
||||
mem_write_ram,
|
||||
mem_write_ramw,
|
||||
mem_write_raml,
|
||||
&ram[0x800000],
|
||||
MEM_MAPPING_INTERNAL,
|
||||
NULL);
|
||||
mem_mapping_disable(&ps2.expansion_mapping);
|
||||
}
|
||||
|
||||
device_add(&ps1vga_device);
|
||||
}
|
||||
|
||||
static void ps2_mca_board_model_80_type2_init(int is486)
|
||||
{
|
||||
ps2_mca_board_common_init();
|
||||
@@ -783,6 +1145,20 @@ static void ps2_mca_board_model_80_type2_init(int is486)
|
||||
|
||||
ps2.mem_regs[0] |= ((mem_size/1024) & 0x0f);
|
||||
|
||||
mem_mapping_add(&ps2.split_mapping,
|
||||
(mem_size+256) * 1024,
|
||||
256*1024,
|
||||
ps2_read_split_ram,
|
||||
ps2_read_split_ramw,
|
||||
ps2_read_split_raml,
|
||||
ps2_write_split_ram,
|
||||
ps2_write_split_ramw,
|
||||
ps2_write_split_raml,
|
||||
&ram[0xa0000],
|
||||
MEM_MAPPING_INTERNAL,
|
||||
NULL);
|
||||
mem_mapping_disable(&ps2.split_mapping);
|
||||
|
||||
if ((mem_size > 4096) && !is486)
|
||||
{
|
||||
/* Only 4 MB supported on planar, create a memory expansion card for the rest */
|
||||
@@ -876,6 +1252,21 @@ machine_ps2_model_55sx_init(machine_t *model)
|
||||
ps2_mca_board_model_55sx_init();
|
||||
}
|
||||
|
||||
void
|
||||
machine_ps2_model_70_type3_init(machine_t *model)
|
||||
{
|
||||
machine_ps2_common_init(model);
|
||||
|
||||
ps2_mca_board_model_70_type34_init(0);
|
||||
}
|
||||
|
||||
void
|
||||
machine_ps2_model_70_type4_init(machine_t *model)
|
||||
{
|
||||
machine_ps2_common_init(model);
|
||||
|
||||
ps2_mca_board_model_70_type34_init(1);
|
||||
}
|
||||
|
||||
void
|
||||
machine_ps2_model_80_init(machine_t *model)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,59 @@
|
||||
void t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask);
|
||||
/*
|
||||
* 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 Toshiba T1000/T1200 machines.
|
||||
*
|
||||
* Version: @(#)m_xt_t1000.h 1.0.2 2018/03/10
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the:
|
||||
*
|
||||
* Free Software Foundation, Inc.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef MACHINE_T1000_H
|
||||
# define MACHINE_T1000_H
|
||||
|
||||
void t1000_configsys_loadnvr();
|
||||
void t1000_emsboard_loadnvr();
|
||||
|
||||
void t1000_configsys_savenvr();
|
||||
void t1000_emsboard_savenvr();
|
||||
extern device_t t1000_video_device;
|
||||
extern device_t t1200_video_device;
|
||||
|
||||
|
||||
extern void t1000_video_options_set(uint8_t options);
|
||||
extern void t1000_display_set(uint8_t internal);
|
||||
|
||||
extern void t1000_syskey(uint8_t amask, uint8_t omask, uint8_t xmask);
|
||||
|
||||
extern void t1000_configsys_load(void);
|
||||
extern void t1000_configsys_save(void);
|
||||
|
||||
extern void t1000_emsboard_load(void);
|
||||
extern void t1000_emsboard_save(void);
|
||||
|
||||
|
||||
#endif /*MACHINE_T1000_H*/
|
||||
|
||||
753
src/machine/m_xt_t1000_vid.c
Normal file
753
src/machine/m_xt_t1000_vid.c
Normal file
@@ -0,0 +1,753 @@
|
||||
/*
|
||||
* VARCem Virtual ARchaeological Computer EMulator.
|
||||
* An emulator of (mostly) x86-based PC systems and devices,
|
||||
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
|
||||
* spanning the era between 1981 and 1995.
|
||||
*
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implementation of the Toshiba T1000 plasma display, which
|
||||
* has a fixed resolution of 640x200 pixels.
|
||||
*
|
||||
* Version: @(#)m_xt_t1000_vid.c 1.0.4 2018/03/10
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2018 Fred N. van Kempen.
|
||||
* Copyright 2018 Miran Grca.
|
||||
* Copyright 2018 Sarah Walker.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the:
|
||||
*
|
||||
* Free Software Foundation, Inc.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include "../86box.h"
|
||||
#include "../device.h"
|
||||
#include "../io.h"
|
||||
#include "../mem.h"
|
||||
#include "../timer.h"
|
||||
#include "../cpu/cpu.h"
|
||||
#include "../video/video.h"
|
||||
#include "../video/vid_cga.h"
|
||||
#include "m_xt_t1000.h"
|
||||
|
||||
|
||||
#define T1000_XSIZE 640
|
||||
#define T1000_YSIZE 200
|
||||
|
||||
|
||||
/* Mapping of attributes to colours */
|
||||
static uint32_t blue, grey;
|
||||
static uint8_t boldcols[256]; /* Which attributes use the bold font */
|
||||
static uint32_t blinkcols[256][2];
|
||||
static uint32_t normcols[256][2];
|
||||
static uint8_t language;
|
||||
|
||||
|
||||
/* Video options set by the motherboard; they will be picked up by the card
|
||||
* on the next poll.
|
||||
*
|
||||
* Bit 1: Danish
|
||||
* Bit 0: Thin font
|
||||
*/
|
||||
static uint8_t st_video_options;
|
||||
static int8_t st_display_internal = -1;
|
||||
|
||||
void t1000_video_options_set(uint8_t options)
|
||||
{
|
||||
st_video_options = options & 1;
|
||||
st_video_options |= language;
|
||||
}
|
||||
|
||||
void t1000_display_set(uint8_t internal)
|
||||
{
|
||||
st_display_internal = (int8_t)internal;
|
||||
}
|
||||
|
||||
uint8_t t1000_display_get()
|
||||
{
|
||||
return (uint8_t)st_display_internal;
|
||||
}
|
||||
|
||||
|
||||
typedef struct t1000_t
|
||||
{
|
||||
mem_mapping_t mapping;
|
||||
|
||||
cga_t cga; /* The CGA is used for the external
|
||||
* display; most of its registers are
|
||||
* ignored by the plasma display. */
|
||||
|
||||
int font; /* Current font, 0-3 */
|
||||
int enabled; /* Hardware enabled, 0 or 1 */
|
||||
int internal; /* Using internal display? */
|
||||
uint8_t attrmap; /* Attribute mapping register */
|
||||
|
||||
int dispontime, dispofftime;
|
||||
|
||||
int linepos, displine;
|
||||
int vc;
|
||||
int dispon;
|
||||
int vsynctime;
|
||||
uint8_t video_options;
|
||||
|
||||
uint8_t *vram;
|
||||
} t1000_t;
|
||||
|
||||
|
||||
static void t1000_recalctimings(t1000_t *t1000);
|
||||
static void t1000_write(uint32_t addr, uint8_t val, void *p);
|
||||
static uint8_t t1000_read(uint32_t addr, void *p);
|
||||
static void t1000_recalcattrs(t1000_t *t1000);
|
||||
|
||||
|
||||
static void t1000_out(uint16_t addr, uint8_t val, void *p)
|
||||
{
|
||||
t1000_t *t1000 = (t1000_t *)p;
|
||||
switch (addr)
|
||||
{
|
||||
/* Emulated CRTC, register select */
|
||||
case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6:
|
||||
cga_out(addr, val, &t1000->cga);
|
||||
break;
|
||||
|
||||
/* Emulated CRTC, value */
|
||||
case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7:
|
||||
/* Register 0x12 controls the attribute mappings for the
|
||||
* LCD screen. */
|
||||
if (t1000->cga.crtcreg == 0x12)
|
||||
{
|
||||
t1000->attrmap = val;
|
||||
t1000_recalcattrs(t1000);
|
||||
return;
|
||||
}
|
||||
cga_out(addr, val, &t1000->cga);
|
||||
|
||||
t1000_recalctimings(t1000);
|
||||
return;
|
||||
|
||||
/* CGA control register */
|
||||
case 0x3D8:
|
||||
cga_out(addr, val, &t1000->cga);
|
||||
return;
|
||||
/* CGA colour register */
|
||||
case 0x3D9:
|
||||
cga_out(addr, val, &t1000->cga);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t t1000_in(uint16_t addr, void *p)
|
||||
{
|
||||
t1000_t *t1000 = (t1000_t *)p;
|
||||
uint8_t val;
|
||||
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7:
|
||||
if (t1000->cga.crtcreg == 0x12)
|
||||
{
|
||||
val = t1000->attrmap & 0x0F;
|
||||
if (t1000->internal) val |= 0x20; /* LCD / CRT */
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
return cga_in(addr, &t1000->cga);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static void t1000_write(uint32_t addr, uint8_t val, void *p)
|
||||
{
|
||||
t1000_t *t1000 = (t1000_t *)p;
|
||||
egawrites++;
|
||||
|
||||
// pclog("CGA_WRITE %04X %02X\n", addr, val);
|
||||
t1000->vram[addr & 0x3fff] = val;
|
||||
cycles -= 4;
|
||||
}
|
||||
|
||||
static uint8_t t1000_read(uint32_t addr, void *p)
|
||||
{
|
||||
t1000_t *t1000 = (t1000_t *)p;
|
||||
egareads++;
|
||||
cycles -= 4;
|
||||
|
||||
// pclog("CGA_READ %04X\n", addr);
|
||||
return t1000->vram[addr & 0x3fff];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void t1000_recalctimings(t1000_t *t1000)
|
||||
{
|
||||
double disptime;
|
||||
double _dispontime, _dispofftime;
|
||||
|
||||
if (!t1000->internal)
|
||||
{
|
||||
cga_recalctimings(&t1000->cga);
|
||||
return;
|
||||
}
|
||||
disptime = 651;
|
||||
_dispontime = 640;
|
||||
_dispofftime = disptime - _dispontime;
|
||||
t1000->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT));
|
||||
t1000->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT));
|
||||
}
|
||||
|
||||
/* Draw a row of text in 80-column mode */
|
||||
static void t1000_text_row80(t1000_t *t1000)
|
||||
{
|
||||
uint32_t cols[2];
|
||||
int x, c;
|
||||
uint8_t chr, attr;
|
||||
int drawcursor;
|
||||
int cursorline;
|
||||
int bold;
|
||||
int blink;
|
||||
uint16_t addr;
|
||||
uint8_t sc;
|
||||
uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff;
|
||||
uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff;
|
||||
|
||||
sc = (t1000->displine) & 7;
|
||||
addr = ((ma & ~1) + (t1000->displine >> 3) * 80) * 2;
|
||||
ma += (t1000->displine >> 3) * 80;
|
||||
|
||||
if ((t1000->cga.crtc[10] & 0x60) == 0x20)
|
||||
{
|
||||
cursorline = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) &&
|
||||
((t1000->cga.crtc[11] & 0x0F) >= sc);
|
||||
}
|
||||
for (x = 0; x < 80; x++)
|
||||
{
|
||||
chr = t1000->vram[(addr + 2 * x) & 0x3FFF];
|
||||
attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF];
|
||||
drawcursor = ((ma == ca) && cursorline &&
|
||||
(t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16));
|
||||
|
||||
blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) &&
|
||||
(attr & 0x80) && !drawcursor);
|
||||
|
||||
if (t1000->video_options & 1)
|
||||
bold = boldcols[attr] ? chr : chr + 256;
|
||||
else
|
||||
bold = boldcols[attr] ? chr + 256 : chr;
|
||||
if (t1000->video_options & 2)
|
||||
bold += 512;
|
||||
|
||||
if (t1000->cga.cgamode & 0x20) /* Blink */
|
||||
{
|
||||
cols[1] = blinkcols[attr][1];
|
||||
cols[0] = blinkcols[attr][0];
|
||||
if (blink) cols[1] = cols[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
cols[1] = normcols[attr][1];
|
||||
cols[0] = normcols[attr][0];
|
||||
}
|
||||
if (drawcursor)
|
||||
{
|
||||
for (c = 0; c < 8; c++)
|
||||
{
|
||||
((uint32_t *)buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (c = 0; c < 8; c++)
|
||||
((uint32_t *)buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0];
|
||||
}
|
||||
++ma;
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw a row of text in 40-column mode */
|
||||
static void t1000_text_row40(t1000_t *t1000)
|
||||
{
|
||||
uint32_t cols[2];
|
||||
int x, c;
|
||||
uint8_t chr, attr;
|
||||
int drawcursor;
|
||||
int cursorline;
|
||||
int bold;
|
||||
int blink;
|
||||
uint16_t addr;
|
||||
uint8_t sc;
|
||||
uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff;
|
||||
uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff;
|
||||
|
||||
sc = (t1000->displine) & 7;
|
||||
addr = ((ma & ~1) + (t1000->displine >> 3) * 40) * 2;
|
||||
ma += (t1000->displine >> 3) * 40;
|
||||
|
||||
if ((t1000->cga.crtc[10] & 0x60) == 0x20)
|
||||
{
|
||||
cursorline = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) &&
|
||||
((t1000->cga.crtc[11] & 0x0F) >= sc);
|
||||
}
|
||||
for (x = 0; x < 40; x++)
|
||||
{
|
||||
chr = t1000->vram[(addr + 2 * x) & 0x3FFF];
|
||||
attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF];
|
||||
drawcursor = ((ma == ca) && cursorline &&
|
||||
(t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16));
|
||||
|
||||
blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) &&
|
||||
(attr & 0x80) && !drawcursor);
|
||||
|
||||
if (t1000->video_options & 1)
|
||||
bold = boldcols[attr] ? chr : chr + 256;
|
||||
else
|
||||
bold = boldcols[attr] ? chr + 256 : chr;
|
||||
if (t1000->video_options & 2)
|
||||
bold += 512;
|
||||
|
||||
if (t1000->cga.cgamode & 0x20) /* Blink */
|
||||
{
|
||||
cols[1] = blinkcols[attr][1];
|
||||
cols[0] = blinkcols[attr][0];
|
||||
if (blink) cols[1] = cols[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
cols[1] = normcols[attr][1];
|
||||
cols[0] = normcols[attr][0];
|
||||
}
|
||||
if (drawcursor)
|
||||
{
|
||||
for (c = 0; c < 8; c++)
|
||||
{
|
||||
((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] =
|
||||
((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2 + 1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (c = 0; c < 8; c++)
|
||||
{
|
||||
((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] =
|
||||
((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2+1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0];
|
||||
}
|
||||
}
|
||||
++ma;
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw a line in CGA 640x200 mode */
|
||||
static void t1000_cgaline6(t1000_t *t1000)
|
||||
{
|
||||
int x, c;
|
||||
uint8_t dat;
|
||||
uint32_t ink = 0;
|
||||
uint16_t addr;
|
||||
uint32_t fg = (t1000->cga.cgacol & 0x0F) ? blue : grey;
|
||||
uint32_t bg = grey;
|
||||
|
||||
uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff;
|
||||
|
||||
addr = ((t1000->displine) & 1) * 0x2000 +
|
||||
(t1000->displine >> 1) * 80 +
|
||||
((ma & ~1) << 1);
|
||||
|
||||
for (x = 0; x < 80; x++)
|
||||
{
|
||||
dat = t1000->vram[addr & 0x3FFF];
|
||||
addr++;
|
||||
|
||||
for (c = 0; c < 8; c++)
|
||||
{
|
||||
ink = (dat & 0x80) ? fg : bg;
|
||||
if (!(t1000->cga.cgamode & 8))
|
||||
ink = grey;
|
||||
((uint32_t *)buffer32->line[t1000->displine])[x*8+c] = ink;
|
||||
dat = dat << 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw a line in CGA 320x200 mode. Here the CGA colours are converted to
|
||||
* dither patterns: colour 1 to 25% grey, colour 2 to 50% grey */
|
||||
static void t1000_cgaline4(t1000_t *t1000)
|
||||
{
|
||||
int x, c;
|
||||
uint8_t dat, pattern;
|
||||
uint32_t ink0, ink1;
|
||||
uint16_t addr;
|
||||
|
||||
uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff;
|
||||
addr = ((t1000->displine) & 1) * 0x2000 +
|
||||
(t1000->displine >> 1) * 80 +
|
||||
((ma & ~1) << 1);
|
||||
|
||||
for (x = 0; x < 80; x++)
|
||||
{
|
||||
dat = t1000->vram[addr & 0x3FFF];
|
||||
addr++;
|
||||
|
||||
for (c = 0; c < 4; c++)
|
||||
{
|
||||
pattern = (dat & 0xC0) >> 6;
|
||||
if (!(t1000->cga.cgamode & 8)) pattern = 0;
|
||||
|
||||
switch (pattern & 3)
|
||||
{
|
||||
default:
|
||||
case 0: ink0 = ink1 = grey; break;
|
||||
case 1: if (t1000->displine & 1)
|
||||
{
|
||||
ink0 = grey; ink1 = grey;
|
||||
}
|
||||
else
|
||||
{
|
||||
ink0 = blue; ink1 = grey;
|
||||
}
|
||||
break;
|
||||
case 2: if (t1000->displine & 1)
|
||||
{
|
||||
ink0 = grey; ink1 = blue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ink0 = blue; ink1 = grey;
|
||||
}
|
||||
break;
|
||||
case 3: ink0 = ink1 = blue; break;
|
||||
|
||||
}
|
||||
((uint32_t *)buffer32->line[t1000->displine])[x*8+2*c] = ink0;
|
||||
((uint32_t *)buffer32->line[t1000->displine])[x*8+2*c+1] = ink1;
|
||||
dat = dat << 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void t1000_poll(void *p)
|
||||
{
|
||||
t1000_t *t1000 = (t1000_t *)p;
|
||||
|
||||
if (t1000->video_options != st_video_options)
|
||||
{
|
||||
t1000->video_options = st_video_options;
|
||||
|
||||
/* Set the font used for the external display */
|
||||
t1000->cga.fontbase = ((t1000->video_options & 3) * 256);
|
||||
}
|
||||
/* Switch between internal plasma and external CRT display. */
|
||||
if (st_display_internal != -1 && st_display_internal != t1000->internal)
|
||||
{
|
||||
t1000->internal = st_display_internal;
|
||||
t1000_recalctimings(t1000);
|
||||
}
|
||||
if (!t1000->internal)
|
||||
{
|
||||
cga_poll(&t1000->cga);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t1000->linepos)
|
||||
{
|
||||
t1000->cga.vidtime += t1000->dispofftime;
|
||||
t1000->cga.cgastat |= 1;
|
||||
t1000->linepos = 1;
|
||||
if (t1000->dispon)
|
||||
{
|
||||
if (t1000->displine == 0)
|
||||
{
|
||||
video_wait_for_buffer();
|
||||
}
|
||||
|
||||
/* Graphics */
|
||||
if (t1000->cga.cgamode & 0x02)
|
||||
{
|
||||
if (t1000->cga.cgamode & 0x10)
|
||||
t1000_cgaline6(t1000);
|
||||
else t1000_cgaline4(t1000);
|
||||
}
|
||||
else
|
||||
if (t1000->cga.cgamode & 0x01) /* High-res text */
|
||||
{
|
||||
t1000_text_row80(t1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
t1000_text_row40(t1000);
|
||||
}
|
||||
}
|
||||
t1000->displine++;
|
||||
/* Hardcode a fixed refresh rate and VSYNC timing */
|
||||
if (t1000->displine == 200) /* Start of VSYNC */
|
||||
{
|
||||
t1000->cga.cgastat |= 8;
|
||||
t1000->dispon = 0;
|
||||
}
|
||||
if (t1000->displine == 216) /* End of VSYNC */
|
||||
{
|
||||
t1000->displine = 0;
|
||||
t1000->cga.cgastat &= ~8;
|
||||
t1000->dispon = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t1000->dispon)
|
||||
{
|
||||
t1000->cga.cgastat &= ~1;
|
||||
}
|
||||
t1000->cga.vidtime += t1000->dispontime;
|
||||
t1000->linepos = 0;
|
||||
|
||||
if (t1000->displine == 200)
|
||||
{
|
||||
/* Hardcode 640x200 window size */
|
||||
if (T1000_XSIZE != xsize || T1000_YSIZE != ysize)
|
||||
{
|
||||
xsize = T1000_XSIZE;
|
||||
ysize = T1000_YSIZE;
|
||||
if (xsize < 64) xsize = 656;
|
||||
if (ysize < 32) ysize = 200;
|
||||
set_screen_size(xsize, ysize);
|
||||
}
|
||||
video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize);
|
||||
|
||||
frames++;
|
||||
/* Fixed 640x200 resolution */
|
||||
video_res_x = T1000_XSIZE;
|
||||
video_res_y = T1000_YSIZE;
|
||||
|
||||
if (t1000->cga.cgamode & 0x02)
|
||||
{
|
||||
if (t1000->cga.cgamode & 0x10)
|
||||
video_bpp = 1;
|
||||
else video_bpp = 2;
|
||||
|
||||
}
|
||||
else video_bpp = 0;
|
||||
t1000->cga.cgablink++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void t1000_recalcattrs(t1000_t *t1000)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* val behaves as follows:
|
||||
* Bit 0: Attributes 01-06, 08-0E are inverse video
|
||||
* Bit 1: Attributes 01-06, 08-0E are bold
|
||||
* Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF
|
||||
* are inverse video
|
||||
* Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF
|
||||
* are bold */
|
||||
|
||||
/* Set up colours */
|
||||
blue = makecol(0x2D, 0x39, 0x5A);
|
||||
grey = makecol(0x85, 0xa0, 0xD6);
|
||||
|
||||
/* Initialise the attribute mapping. Start by defaulting everything
|
||||
* to grey on blue, and with bold set by bit 3 */
|
||||
for (n = 0; n < 256; n++)
|
||||
{
|
||||
boldcols[n] = (n & 8) != 0;
|
||||
blinkcols[n][0] = normcols[n][0] = blue;
|
||||
blinkcols[n][1] = normcols[n][1] = grey;
|
||||
}
|
||||
|
||||
/* Colours 0x11-0xFF are controlled by bits 2 and 3 of the
|
||||
* passed value. Exclude x0 and x8, which are always grey on
|
||||
* blue. */
|
||||
for (n = 0x11; n <= 0xFF; n++)
|
||||
{
|
||||
if ((n & 7) == 0) continue;
|
||||
if (t1000->attrmap & 4) /* Inverse */
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = blue;
|
||||
blinkcols[n][1] = normcols[n][1] = grey;
|
||||
}
|
||||
else /* Normal */
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = grey;
|
||||
blinkcols[n][1] = normcols[n][1] = blue;
|
||||
}
|
||||
if (t1000->attrmap & 8) boldcols[n] = 1; /* Bold */
|
||||
}
|
||||
/* Set up the 01-0E range, controlled by bits 0 and 1 of the
|
||||
* passed value. When blinking is enabled this also affects 81-8E. */
|
||||
for (n = 0x01; n <= 0x0E; n++)
|
||||
{
|
||||
if (n == 7) continue;
|
||||
if (t1000->attrmap & 1)
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = blue;
|
||||
blinkcols[n][1] = normcols[n][1] = grey;
|
||||
blinkcols[n+128][0] = blue;
|
||||
blinkcols[n+128][1] = grey;
|
||||
}
|
||||
else
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = grey;
|
||||
blinkcols[n][1] = normcols[n][1] = blue;
|
||||
blinkcols[n+128][0] = grey;
|
||||
blinkcols[n+128][1] = blue;
|
||||
}
|
||||
if (t1000->attrmap & 2) boldcols[n] = 1;
|
||||
}
|
||||
/* Colours 07 and 0F are always blue on grey. If blinking is
|
||||
* enabled so are 87 and 8F. */
|
||||
for (n = 0x07; n <= 0x0F; n += 8)
|
||||
{
|
||||
blinkcols[n][0] = normcols[n][0] = grey;
|
||||
blinkcols[n][1] = normcols[n][1] = blue;
|
||||
blinkcols[n+128][0] = grey;
|
||||
blinkcols[n+128][1] = blue;
|
||||
}
|
||||
/* When not blinking, colours 81-8F are always blue on grey. */
|
||||
for (n = 0x81; n <= 0x8F; n ++)
|
||||
{
|
||||
normcols[n][0] = grey;
|
||||
normcols[n][1] = blue;
|
||||
boldcols[n] = (n & 0x08) != 0;
|
||||
}
|
||||
|
||||
|
||||
/* Finally do the ones which are solid grey. These differ between
|
||||
* the normal and blinking mappings */
|
||||
for (n = 0; n <= 0xFF; n += 0x11)
|
||||
{
|
||||
normcols[n][0] = normcols[n][1] = grey;
|
||||
}
|
||||
/* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are grey */
|
||||
for (n = 0; n <= 0x77; n += 0x11)
|
||||
{
|
||||
blinkcols[n][0] = blinkcols[n][1] = grey;
|
||||
blinkcols[n+128][0] = blinkcols[n+128][1] = grey;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void *t1000_init(device_t *info)
|
||||
{
|
||||
t1000_t *t1000 = malloc(sizeof(t1000_t));
|
||||
memset(t1000, 0, sizeof(t1000_t));
|
||||
cga_init(&t1000->cga);
|
||||
|
||||
t1000->internal = 1;
|
||||
|
||||
/* 16k video RAM */
|
||||
t1000->vram = malloc(0x4000);
|
||||
|
||||
timer_add(t1000_poll, &t1000->cga.vidtime, TIMER_ALWAYS_ENABLED, t1000);
|
||||
|
||||
/* Occupy memory between 0xB8000 and 0xBFFFF */
|
||||
mem_mapping_add(&t1000->mapping, 0xb8000, 0x8000, t1000_read, NULL, NULL, t1000_write, NULL, NULL, NULL, 0, t1000);
|
||||
/* Respond to CGA I/O ports */
|
||||
io_sethandler(0x03d0, 0x000c, t1000_in, NULL, NULL, t1000_out, NULL, NULL, t1000);
|
||||
|
||||
/* Default attribute mapping is 4 */
|
||||
t1000->attrmap = 4;
|
||||
t1000_recalcattrs(t1000);
|
||||
|
||||
/* Start off in 80x25 text mode */
|
||||
t1000->cga.cgastat = 0xF4;
|
||||
t1000->cga.vram = t1000->vram;
|
||||
t1000->enabled = 1;
|
||||
t1000->video_options = 0x01;
|
||||
language = device_get_config_int("display_language") ? 2 : 0;
|
||||
return t1000;
|
||||
}
|
||||
|
||||
static void t1000_close(void *p)
|
||||
{
|
||||
t1000_t *t1000 = (t1000_t *)p;
|
||||
|
||||
free(t1000->vram);
|
||||
free(t1000);
|
||||
}
|
||||
|
||||
static void t1000_speed_changed(void *p)
|
||||
{
|
||||
t1000_t *t1000 = (t1000_t *)p;
|
||||
|
||||
t1000_recalctimings(t1000);
|
||||
}
|
||||
|
||||
static device_config_t t1000_config[] =
|
||||
{
|
||||
{
|
||||
.name = "display_language",
|
||||
.description = "Language",
|
||||
.type = CONFIG_SELECTION,
|
||||
.selection =
|
||||
{
|
||||
{
|
||||
.description = "USA",
|
||||
.value = 0
|
||||
},
|
||||
{
|
||||
.description = "Danish",
|
||||
.value = 1
|
||||
}
|
||||
},
|
||||
.default_int = 0
|
||||
},
|
||||
{
|
||||
.type = -1
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
device_t t1000_video_device = {
|
||||
"Toshiba T1000 Video",
|
||||
0, 0,
|
||||
t1000_init, t1000_close, NULL,
|
||||
NULL,
|
||||
t1000_speed_changed,
|
||||
NULL,
|
||||
NULL,
|
||||
t1000_config
|
||||
};
|
||||
|
||||
|
||||
device_t t1200_video_device = {
|
||||
"Toshiba T1200 Video",
|
||||
0, 0,
|
||||
t1000_init, t1000_close, NULL,
|
||||
NULL,
|
||||
t1000_speed_changed,
|
||||
NULL,
|
||||
NULL,
|
||||
t1000_config
|
||||
};
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Handling of the emulated machines.
|
||||
*
|
||||
* Version: @(#)machine.c 1.0.29 2018/01/16
|
||||
* Version: @(#)machine.c 1.0.30 2018/03/15
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -52,6 +52,9 @@ machine_init(void)
|
||||
AT = IS_ARCH(machine, MACHINE_AT);
|
||||
PCI = IS_ARCH(machine, MACHINE_PCI);
|
||||
|
||||
/* Resize the memory. */
|
||||
mem_resize();
|
||||
|
||||
/* Load the machine's ROM BIOS. */
|
||||
rom_load_bios(romset);
|
||||
mem_add_bios();
|
||||
|
||||
@@ -162,6 +162,8 @@ extern void machine_ps1_m2133_init(machine_t *);
|
||||
extern void machine_ps2_m30_286_init(machine_t *);
|
||||
extern void machine_ps2_model_50_init(machine_t *);
|
||||
extern void machine_ps2_model_55sx_init(machine_t *);
|
||||
extern void machine_ps2_model_70_type3_init(machine_t *);
|
||||
extern void machine_ps2_model_70_type4_init(machine_t *);
|
||||
extern void machine_ps2_model_80_init(machine_t *);
|
||||
#ifdef WALTJE
|
||||
extern void machine_ps2_model_80_486_init(machine_t *);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
* NOTES: OpenAT wip for 286-class machine with open BIOS.
|
||||
* PS2_M80-486 wip, pending receipt of TRM's for machine.
|
||||
*
|
||||
* Version: @(#)machine_table.c 1.0.24 2018/03/06
|
||||
* Version: @(#)machine_table.c 1.0.25 2018/03/13
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -44,14 +44,14 @@ machine_t machines[] = {
|
||||
{ "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL },
|
||||
{ "[8088] Juko XT clone", ROM_JUKOPC, "jukopc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL },
|
||||
{ "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL, NULL },
|
||||
{ "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 0, machine_europc_init, NULL, NULL },
|
||||
{ "[8088] Schneider EuroPC", ROM_EUROPC, "europc", {{"Siemens",cpus_europc}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_HDC | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 15, machine_europc_init, NULL, NULL },
|
||||
{ "[8088] Tandy 1000", ROM_TANDY, "tandy", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 128, 640, 128, 0, machine_tandy1k_init, tandy1k_get_device, NULL },
|
||||
{ "[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 256, 640, 128, 0, machine_tandy1k_init, tandy1k_hx_get_device, NULL },
|
||||
{ "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 0, machine_xt_t1000_init, t1000_get_device, NULL },
|
||||
{ "[8088] Toshiba 1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, NULL, NULL },
|
||||
#if defined(DEV_BRANCH) && defined(USE_LASERXT)
|
||||
{ "[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 512, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL },
|
||||
#endif
|
||||
{ "[8088] Xi8088", ROM_XI8088, "xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, xi8088_get_device, nvr_at_close },
|
||||
{ "[8088] Xi8088", ROM_XI8088, "xi8088", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 64, 1024, 128, 127, machine_xt_xi8088_init, NULL, nvr_at_close },
|
||||
|
||||
{ "[8086] Amstrad PC1512", ROM_PC1512, "pc1512", {{"", cpus_pc1512}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close },
|
||||
{ "[8086] Amstrad PC1640", ROM_PC1640, "pc1640", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL, nvr_at_close },
|
||||
@@ -60,7 +60,7 @@ machine_t machines[] = {
|
||||
{ "[8086] Amstrad PC20(0)", ROM_PC200, "pc200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 512, 640, 128, 63, machine_amstrad_init, NULL, nvr_at_close },
|
||||
{ "[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 128, 640, 128, 0, machine_olim24_init, NULL, NULL },
|
||||
{ "[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA, 512, 768, 128, 0, machine_tandy1k_init, NULL, NULL },
|
||||
{ "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 0, machine_xt_t1200_init, t1200_get_device, NULL },
|
||||
{ "[8086] Toshiba 1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, NULL, NULL },
|
||||
#if defined(DEV_BRANCH) && defined(USE_LASERXT)
|
||||
{ "[8086] VTech Laser XT3", ROM_LXT3, "lxt3", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 256, 512, 256, 0, machine_xt_laserxt_init, NULL, NULL },
|
||||
#endif
|
||||
@@ -104,6 +104,7 @@ machine_t machines[] = {
|
||||
#if defined(DEV_BRANCH) && defined(USE_PORTABLE3)
|
||||
{ "[386DX ISA] Compaq Portable III (386)", ROM_PORTABLEIII386, "portableiii386", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_VIDEO, 1, 14, 1, 127, machine_at_compaq_init, NULL, nvr_at_close },
|
||||
#endif
|
||||
{ "[386DX MCA] IBM PS/2 model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 16, 2, 63, machine_ps2_model_70_type3_init, NULL, nvr_at_close },
|
||||
|
||||
{ "[386DX MCA] IBM PS/2 model 80", ROM_IBMPS2_M80, "ibmps2_m80", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 12, 1, 63, machine_ps2_model_80_init, NULL, nvr_at_close },
|
||||
|
||||
@@ -113,6 +114,8 @@ machine_t machines[] = {
|
||||
{ "[486 ISA] DTK PKM-0038S E-2", ROM_DTK486, "dtk486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 128, 1, 127, machine_at_dtk486_init, NULL, nvr_at_close },
|
||||
{ "[486 ISA] IBM PS/1 model 2133", ROM_IBMPS1_2133, "ibmps1_2133", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 1, 64, 1, 127, machine_ps1_m2133_init, NULL, nvr_at_close },
|
||||
|
||||
{ "[486 MCA] IBM PS/2 model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 2, 64, 2, 63, machine_ps2_model_70_type4_init, NULL, nvr_at_close },
|
||||
|
||||
#ifdef WALTJE
|
||||
{ "[486 MCA] IBM PS/2 model 80-486", ROM_IBMPS2_M80_486, "ibmps2_m80-486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 32, 1, 63, machine_ps2_model_80_486_init, NULL, nvr_at_close },
|
||||
#endif
|
||||
@@ -135,9 +138,7 @@ machine_t machines[] = {
|
||||
{ "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL, nvr_at_close },
|
||||
|
||||
{ "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close },
|
||||
#if defined(DEV_BRANCH) && defined(USE_MRTHOR)
|
||||
{ "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close },
|
||||
#endif
|
||||
|
||||
{ "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL, nvr_at_close },
|
||||
{ "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"AMD", cpus_K56}, {"Cyrix", cpus_6x86},{"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL, nvr_at_close },
|
||||
@@ -158,9 +159,7 @@ machine_t machines[] = {
|
||||
{ "[Socket 5 FX] President Award 430FX PCI",ROM_PRESIDENT, "president", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 8, 128, 8, 127, machine_at_president_init, NULL, nvr_at_close },
|
||||
|
||||
{ "[Socket 7 FX] Intel Advanced/ATX", ROM_THOR, "thor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close },
|
||||
#if defined(DEV_BRANCH) && defined(USE_MRTHOR)
|
||||
{ "[Socket 7 FX] MR Intel Advanced/ATX", ROM_MRTHOR, "mrthor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_thor_init, NULL, nvr_at_close },
|
||||
#endif
|
||||
|
||||
{ "[Socket 7 HX] Acer M3a", ROM_ACERM3A, "acerm3a", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerm3a_init, NULL, nvr_at_close },
|
||||
{ "[Socket 7 HX] Acer V35n", ROM_ACERV35N, "acerv35n", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 192, 8, 127, machine_at_acerv35n_init, NULL, nvr_at_close },
|
||||
|
||||
@@ -3,3 +3,5 @@ extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int add
|
||||
extern void mca_set_index(int index);
|
||||
extern uint8_t mca_read(uint16_t port);
|
||||
extern void mca_write(uint16_t port, uint8_t val);
|
||||
|
||||
extern void ps2_cache_clean(void);
|
||||
181
src/mem.c
181
src/mem.c
@@ -389,15 +389,14 @@ uint8_t *getpccache(uint32_t a)
|
||||
}
|
||||
a&=rammask;
|
||||
|
||||
if (isram[a>>16])
|
||||
{
|
||||
if ((a >> 16) != 0xF || shadowbios)
|
||||
addreadlookup(a2, a);
|
||||
return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)];
|
||||
}
|
||||
|
||||
if (_mem_exec[a >> 14])
|
||||
{
|
||||
if (_mem_mapping_r[a >> 14]->flags & MEM_MAPPING_ROM)
|
||||
cpu_prefetch_cycles = cpu_rom_prefetch_cycles;
|
||||
else
|
||||
cpu_prefetch_cycles = cpu_mem_prefetch_cycles;
|
||||
|
||||
|
||||
return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xFFF)];
|
||||
}
|
||||
|
||||
@@ -1282,24 +1281,24 @@ void mem_add_bios()
|
||||
{
|
||||
if (AT || (romset == ROM_XI8088 && xi8088_bios_128kb()))
|
||||
{
|
||||
mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL, 0);
|
||||
mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||
mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||
mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||
mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0);
|
||||
}
|
||||
mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||
mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||
mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||
mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), MEM_MAPPING_EXTERNAL, 0);
|
||||
mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0);
|
||||
|
||||
mem_mapping_add(&bios_high_mapping[0], (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, 0, 0);
|
||||
mem_mapping_add(&bios_high_mapping[1], (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), 0, 0);
|
||||
mem_mapping_add(&bios_high_mapping[2], (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), 0, 0);
|
||||
mem_mapping_add(&bios_high_mapping[3], (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), 0, 0);
|
||||
mem_mapping_add(&bios_high_mapping[4], (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), 0, 0);
|
||||
mem_mapping_add(&bios_high_mapping[5], (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), 0, 0);
|
||||
mem_mapping_add(&bios_high_mapping[6], (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), 0, 0);
|
||||
mem_mapping_add(&bios_high_mapping[7], (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), 0, 0);
|
||||
mem_mapping_add(&bios_high_mapping[0], (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_high_mapping[1], (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_high_mapping[2], (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_high_mapping[3], (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_high_mapping[4], (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_high_mapping[5], (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_high_mapping[6], (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_ROM, 0);
|
||||
mem_mapping_add(&bios_high_mapping[7], (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), MEM_MAPPING_ROM, 0);
|
||||
}
|
||||
|
||||
int mem_a20_key = 0, mem_a20_alt = 0;
|
||||
@@ -1318,6 +1317,45 @@ void mem_a20_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
void mem_destroy_pages(void)
|
||||
{
|
||||
if (pages) {
|
||||
free(pages);
|
||||
pages = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void mem_resize_pages(void)
|
||||
{
|
||||
int total_size, c;
|
||||
|
||||
mem_destroy_pages();
|
||||
|
||||
if (AT) {
|
||||
if (cpu_16bitbus)
|
||||
total_size = 4096;
|
||||
else {
|
||||
total_size = (mem_size + 384) >> 2;
|
||||
if ((total_size << 2) < (mem_size + 384))
|
||||
total_size++;
|
||||
if (total_size < 4096)
|
||||
total_size = 4096;
|
||||
}
|
||||
} else
|
||||
total_size = 256;
|
||||
|
||||
pages = malloc(total_size * sizeof(page_t));
|
||||
|
||||
memset(pages, 0, total_size * sizeof(page_t));
|
||||
|
||||
for (c = 0; c < total_size; c++)
|
||||
{
|
||||
pages[c].mem = &ram[c << 12];
|
||||
pages[c].write_b = mem_write_ramb_page;
|
||||
pages[c].write_w = mem_write_ramw_page;
|
||||
pages[c].write_l = mem_write_raml_page;
|
||||
}
|
||||
}
|
||||
|
||||
void mem_init(void)
|
||||
{
|
||||
@@ -1339,22 +1377,13 @@ void mem_init(void)
|
||||
writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t));
|
||||
rom = NULL;
|
||||
biosmask = 0xffff;
|
||||
pages = malloc((1 << 20) * sizeof(page_t));
|
||||
page_lookup = malloc((1 << 20) * sizeof(page_t *));
|
||||
|
||||
memset(pages, 0, (1 << 20) * sizeof(page_t));
|
||||
|
||||
memset(page_lookup, 0, (1 << 20) * sizeof(page_t *));
|
||||
|
||||
memset(ram_mapped_addr, 0, 64 * sizeof(uint32_t));
|
||||
|
||||
for (c = 0; c < (1 << 20); c++)
|
||||
{
|
||||
pages[c].mem = &ram[c << 12];
|
||||
pages[c].write_b = mem_write_ramb_page;
|
||||
pages[c].write_w = mem_write_ramw_page;
|
||||
pages[c].write_l = mem_write_raml_page;
|
||||
}
|
||||
|
||||
page_lookup = malloc((1 << 20) * sizeof(page_t *));
|
||||
memset(page_lookup, 0, (1 << 20) * sizeof(page_t *));
|
||||
|
||||
mem_resize_pages();
|
||||
|
||||
memset(isram, 0, sizeof(isram));
|
||||
for (c = 0; c < (mem_size / 64); c++)
|
||||
@@ -1443,70 +1472,6 @@ void mem_remap_top_384k()
|
||||
mem_remap_top(384);
|
||||
}
|
||||
|
||||
void mem_split_enable(int max_size, uint32_t addr)
|
||||
{
|
||||
int c;
|
||||
|
||||
uint8_t *mem_split_buffer = &ram[0x80000];
|
||||
|
||||
if (split_mapping_enabled)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
pclog("Split mapping enable at %08X\n", addr);
|
||||
#endif
|
||||
|
||||
mem_set_mem_state(addr, max_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL);
|
||||
mem_mapping_set_addr(&ram_split_mapping, addr, max_size * 1024);
|
||||
mem_mapping_set_exec(&ram_split_mapping, &ram[addr]);
|
||||
|
||||
if (max_size == 384)
|
||||
memcpy(&ram[addr], mem_split_buffer, max_size);
|
||||
else
|
||||
memcpy(&ram[addr], &mem_split_buffer[128 * 1024], max_size);
|
||||
|
||||
for (c = ((addr / 1024) / 64); c < (((addr / 1024) + max_size - 1) / 64); c++)
|
||||
{
|
||||
isram[c] = 1;
|
||||
}
|
||||
|
||||
flushmmucache();
|
||||
|
||||
split_mapping_enabled = 1;
|
||||
}
|
||||
|
||||
void mem_split_disable(int max_size, uint32_t addr)
|
||||
{
|
||||
int c;
|
||||
|
||||
uint8_t *mem_split_buffer = &ram[0x80000];
|
||||
|
||||
if (!split_mapping_enabled)
|
||||
return;
|
||||
|
||||
#if 0
|
||||
pclog("Split mapping disable at %08X\n", addr);
|
||||
#endif
|
||||
|
||||
if (max_size == 384)
|
||||
memcpy(mem_split_buffer, &ram[addr], max_size);
|
||||
else
|
||||
memcpy(&mem_split_buffer[128 * 1024], &ram[addr], max_size);
|
||||
|
||||
mem_mapping_disable(&ram_split_mapping);
|
||||
mem_set_mem_state(addr, max_size * 1024, 0);
|
||||
mem_mapping_set_exec(&ram_split_mapping, NULL);
|
||||
|
||||
for (c = ((addr / 1024) / 64); c < (((addr / 1024) + max_size - 1) / 64); c++)
|
||||
{
|
||||
isram[c] = 0;
|
||||
}
|
||||
|
||||
flushmmucache();
|
||||
|
||||
split_mapping_enabled = 0;
|
||||
}
|
||||
|
||||
void mem_resize()
|
||||
{
|
||||
int c;
|
||||
@@ -1525,15 +1490,6 @@ void mem_resize()
|
||||
memset(ram, 0, (mem_size + 384) * 1024);
|
||||
}
|
||||
|
||||
memset(pages, 0, (1 << 20) * sizeof(page_t));
|
||||
for (c = 0; c < (1 << 20); c++)
|
||||
{
|
||||
pages[c].mem = &ram[c << 12];
|
||||
pages[c].write_b = mem_write_ramb_page;
|
||||
pages[c].write_w = mem_write_ramw_page;
|
||||
pages[c].write_l = mem_write_raml_page;
|
||||
}
|
||||
|
||||
memset(isram, 0, sizeof(isram));
|
||||
for (c = 0; c < (mem_size / 64); c++)
|
||||
{
|
||||
@@ -1542,6 +1498,8 @@ void mem_resize()
|
||||
isram[c] = 0;
|
||||
}
|
||||
|
||||
mem_resize_pages();
|
||||
|
||||
memset(_mem_read_b, 0, sizeof(_mem_read_b));
|
||||
memset(_mem_read_w, 0, sizeof(_mem_read_w));
|
||||
memset(_mem_read_l, 0, sizeof(_mem_read_l));
|
||||
@@ -1588,6 +1546,9 @@ void mem_resize()
|
||||
void mem_reset_page_blocks()
|
||||
{
|
||||
int c;
|
||||
|
||||
if (!pages)
|
||||
return;
|
||||
|
||||
for (c = 0; c < ((mem_size * 1024) >> 12); c++)
|
||||
{
|
||||
|
||||
@@ -68,6 +68,8 @@ typedef struct mem_mapping_t
|
||||
#define MEM_MAPPING_EXTERNAL 1
|
||||
/*Only present on internal bus (RAM)*/
|
||||
#define MEM_MAPPING_INTERNAL 2
|
||||
/*Executing from ROM may involve additional wait states*/
|
||||
#define MEM_MAPPING_ROM 4
|
||||
|
||||
extern uint8_t *ram,*rom;
|
||||
extern uint8_t romext[32768];
|
||||
@@ -229,15 +231,15 @@ extern void flushmmucache_cr3(void);
|
||||
extern void flushmmucache_nopc(void);
|
||||
extern void mmu_invalidate(uint32_t addr);
|
||||
|
||||
extern void mem_split_enable(int max_size, uint32_t addr);
|
||||
extern void mem_split_disable(int max_size, uint32_t addr);
|
||||
|
||||
|
||||
extern void mem_add_bios(void);
|
||||
|
||||
extern void mem_init(void);
|
||||
extern void mem_resize(void);
|
||||
|
||||
extern void mem_destroy_pages(void);
|
||||
extern void mem_resize_pages(void);
|
||||
|
||||
extern uint8_t port_92_read(uint16_t port, void *priv);
|
||||
extern void port_92_write(uint16_t port, uint8_t val, void *priv);
|
||||
extern void port_92_clear_reset(void);
|
||||
|
||||
721
src/nvr.c
721
src/nvr.c
@@ -1,200 +1,50 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
* 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 86Box distribution.
|
||||
* This file is part of the VARCem Project.
|
||||
*
|
||||
* Implement a more-or-less defacto-standard RTC/NVRAM.
|
||||
* Implement a generic NVRAM/CMOS/RTC device.
|
||||
*
|
||||
* When IBM released the PC/AT machine, it came standard with a
|
||||
* battery-backed RTC chip to keep the time of day, something
|
||||
* that was optional on standard PC's with a myriad variants
|
||||
* being put on the market, often on cheap multi-I/O cards.
|
||||
* NOTE: I should re-do 'intclk' using a TM struct.
|
||||
*
|
||||
* The PC/AT had an on-board DS12885-series chip ("the black
|
||||
* block") which was an RTC/clock chip with onboard oscillator
|
||||
* and a backup battery (hence the big size.) The chip also had
|
||||
* a smal amount of RAM bytes available to the user, which was
|
||||
* used by IBM's ROM BIOS to store machine configuration data.
|
||||
* Version: @(#)nvr.c 1.0.2 2018/03/11
|
||||
*
|
||||
* Since then, pretty much any PC has an implementation of that
|
||||
* device, which became known as the "nvr" or "cmos".
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* NOTES Info extracted from the data sheets:
|
||||
*
|
||||
* * The century register at location 32h is a BCD register
|
||||
* designed to automatically load the BCD value 20 as the
|
||||
* year register changes from 99 to 00. The MSB of this
|
||||
* register is not affected when the load of 20 occurs,
|
||||
* and remains at the value written by the user.
|
||||
*
|
||||
* * Rate Selector (RS3:RS0)
|
||||
* These four rate-selection bits select one of the 13
|
||||
* taps on the 15-stage divider or disable the divider
|
||||
* output. The tap selected can be used to generate an
|
||||
* output square wave (SQW pin) and/or a periodic interrupt.
|
||||
*
|
||||
* The user can do one of the following:
|
||||
* - enable the interrupt with the PIE bit;
|
||||
* - enable the SQW output pin with the SQWE bit;
|
||||
* - enable both at the same time and the same rate; or
|
||||
* - enable neither.
|
||||
*
|
||||
* Table 3 lists the periodic interrupt rates and the square
|
||||
* wave frequencies that can be chosen with the RS bits.
|
||||
* These four read/write bits are not affected by !RESET.
|
||||
*
|
||||
* * Oscillator (DV2:DV0)
|
||||
* These three bits are used to turn the oscillator on or
|
||||
* off and to reset the countdown chain. A pattern of 010
|
||||
* is the only combination of bits that turn the oscillator
|
||||
* on and allow the RTC to keep time. A pattern of 11x
|
||||
* enables the oscillator but holds the countdown chain in
|
||||
* reset. The next update occurs at 500ms after a pattern
|
||||
* of 010 is written to DV0, DV1, and DV2.
|
||||
*
|
||||
* * Update-In-Progress (UIP)
|
||||
* This bit is a status flag that can be monitored. When the
|
||||
* UIP bit is a 1, the update transfer occurs soon. When
|
||||
* UIP is a 0, the update transfer does not occur for at
|
||||
* least 244us. The time, calendar, and alarm information
|
||||
* in RAM is fully available for access when the UIP bit
|
||||
* is 0. The UIP bit is read-only and is not affected by
|
||||
* !RESET. Writing the SET bit in Register B to a 1
|
||||
* inhibits any update transfer and clears the UIP status bit.
|
||||
*
|
||||
* * Daylight Saving Enable (DSE)
|
||||
* This bit is a read/write bit that enables two daylight
|
||||
* saving adjustments when DSE is set to 1. On the first
|
||||
* Sunday in April (or the last Sunday in April in the
|
||||
* MC146818A), the time increments from 1:59:59 AM to
|
||||
* 3:00:00 AM. On the last Sunday in October when the time
|
||||
* first reaches 1:59:59 AM, it changes to 1:00:00 AM.
|
||||
*
|
||||
* When DSE is enabled, the internal logic test for the
|
||||
* first/last Sunday condition at midnight. If the DSE bit
|
||||
* is not set when the test occurs, the daylight saving
|
||||
* function does not operate correctly. These adjustments
|
||||
* do not occur when the DSE bit is 0. This bit is not
|
||||
* affected by internal functions or !RESET.
|
||||
*
|
||||
* * 24/12
|
||||
* The 24/12 control bit establishes the format of the hours
|
||||
* byte. A 1 indicates the 24-hour mode and a 0 indicates
|
||||
* the 12-hour mode. This bit is read/write and is not
|
||||
* affected by internal functions or !RESET.
|
||||
*
|
||||
* * Data Mode (DM)
|
||||
* This bit indicates whether time and calendar information
|
||||
* is in binary or BCD format. The DM bit is set by the
|
||||
* program to the appropriate format and can be read as
|
||||
* required. This bit is not modified by internal functions
|
||||
* or !RESET. A 1 in DM signifies binary data, while a 0 in
|
||||
* DM specifies BCD data.
|
||||
*
|
||||
* * Square-Wave Enable (SQWE)
|
||||
* When this bit is set to 1, a square-wave signal at the
|
||||
* frequency set by the rate-selection bits RS3-RS0 is driven
|
||||
* out on the SQW pin. When the SQWE bit is set to 0, the
|
||||
* SQW pin is held low. SQWE is a read/write bit and is
|
||||
* cleared by !RESET. SQWE is low if disabled, and is high
|
||||
* impedance when VCC is below VPF. SQWE is cleared to 0 on
|
||||
* !RESET.
|
||||
*
|
||||
* * Update-Ended Interrupt Enable (UIE)
|
||||
* This bit is a read/write bit that enables the update-end
|
||||
* flag (UF) bit in Register C to assert !IRQ. The !RESET
|
||||
* pin going low or the SET bit going high clears the UIE bit.
|
||||
* The internal functions of the device do not affect the UIE
|
||||
* bit, but is cleared to 0 on !RESET.
|
||||
*
|
||||
* * Alarm Interrupt Enable (AIE)
|
||||
* This bit is a read/write bit that, when set to 1, permits
|
||||
* the alarm flag (AF) bit in Register C to assert !IRQ. An
|
||||
* alarm interrupt occurs for each second that the three time
|
||||
* bytes equal the three alarm bytes, including a don't-care
|
||||
* alarm code of binary 11XXXXXX. The AF bit does not
|
||||
* initiate the !IRQ signal when the AIE bit is set to 0.
|
||||
* The internal functions of the device do not affect the AIE
|
||||
* bit, but is cleared to 0 on !RESET.
|
||||
*
|
||||
* * Periodic Interrupt Enable (PIE)
|
||||
* The PIE bit is a read/write bit that allows the periodic
|
||||
* interrupt flag (PF) bit in Register C to drive the !IRQ pin
|
||||
* low. When the PIE bit is set to 1, periodic interrupts are
|
||||
* generated by driving the !IRQ pin low at a rate specified
|
||||
* by the RS3-RS0 bits of Register A. A 0 in the PIE bit
|
||||
* blocks the !IRQ output from being driven by a periodic
|
||||
* interrupt, but the PF bit is still set at the periodic
|
||||
* rate. PIE is not modified b any internal device functions,
|
||||
* but is cleared to 0 on !RESET.
|
||||
*
|
||||
* * SET
|
||||
* When the SET bit is 0, the update transfer functions
|
||||
* normally by advancing the counts once per second. When
|
||||
* the SET bit is written to 1, any update transfer is
|
||||
* inhibited, and the program can initialize the time and
|
||||
* calendar bytes without an update occurring in the midst of
|
||||
* initializing. Read cycles can be executed in a similar
|
||||
* manner. SET is a read/write bit and is not affected by
|
||||
* !RESET or internal functions of the device.
|
||||
*
|
||||
* * Update-Ended Interrupt Flag (UF)
|
||||
* This bit is set after each update cycle. When the UIE
|
||||
* bit is set to 1, the 1 in UF causes the IRQF bit to be
|
||||
* a 1, which asserts the !IRQ pin. This bit can be
|
||||
* cleared by reading Register C or with a !RESET.
|
||||
*
|
||||
* * Alarm Interrupt Flag (AF)
|
||||
* A 1 in the AF bit indicates that the current time has
|
||||
* matched the alarm time. If the AIE bit is also 1, the
|
||||
* !IRQ pin goes low and a 1 appears in the IRQF bit. This
|
||||
* bit can be cleared by reading Register C or with a
|
||||
* !RESET.
|
||||
*
|
||||
* * Periodic Interrupt Flag (PF)
|
||||
* This bit is read-only and is set to 1 when an edge is
|
||||
* detected on the selected tap of the divider chain. The
|
||||
* RS3 through RS0 bits establish the periodic rate. PF is
|
||||
* set to 1 independent of the state of the PIE bit. When
|
||||
* both PF and PIE are 1s, the !IRQ signal is active and
|
||||
* sets the IRQF bit. This bit can be cleared by reading
|
||||
* Register C or with a !RESET.
|
||||
*
|
||||
* * Interrupt Request Flag (IRQF)
|
||||
* The interrupt request flag (IRQF) is set to a 1 when one
|
||||
* or more of the following are true:
|
||||
* - PF == PIE == 1
|
||||
* - AF == AIE == 1
|
||||
* - UF == UIE == 1
|
||||
* Any time the IRQF bit is a 1, the !IRQ pin is driven low.
|
||||
* All flag bits are cleared after Register C is read by the
|
||||
* program or when the !RESET pin is low.
|
||||
*
|
||||
* * Valid RAM and Time (VRT)
|
||||
* This bit indicates the condition of the battery connected
|
||||
* to the VBAT pin. This bit is not writeable and should
|
||||
* always be 1 when read. If a 0 is ever present, an
|
||||
* exhausted internal lithium energy source is indicated and
|
||||
* both the contents of the RTC data and RAM data are
|
||||
* questionable. This bit is unaffected by !RESET.
|
||||
*
|
||||
* This file implements an internal RTC clock, plus a generic
|
||||
* version of the RTC/NVRAM chip, including the later update
|
||||
* (DS12887A) which implemented a "century" register to be
|
||||
* compatible with Y2K.
|
||||
*
|
||||
* Version: @(#)nvr.c 1.0.15 2018/02/26
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Mahod,
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* 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 <stdio.h>
|
||||
#include <stdint.h>
|
||||
@@ -203,33 +53,37 @@
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
#include "86box.h"
|
||||
#include "machine/machine.h"
|
||||
#include "pic.h"
|
||||
#include "pit.h"
|
||||
#include "timer.h"
|
||||
#include "machine/machine.h"
|
||||
#include "plat.h"
|
||||
#include "nvr.h"
|
||||
|
||||
|
||||
int enable_sync; /* configuration variable: enable time sync */
|
||||
int nvr_dosave; /* NVR is dirty, needs saved */
|
||||
|
||||
|
||||
static nvr_t *saved_nvr = NULL;
|
||||
static int8_t days_in_month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||
static struct {
|
||||
/* Define the internal clock. */
|
||||
typedef struct {
|
||||
int16_t year;
|
||||
int8_t sec;
|
||||
int8_t min;
|
||||
int8_t hour;
|
||||
int8_t mday;
|
||||
int8_t mon;
|
||||
} intclk; /* the internal clock */
|
||||
} intclk_t;
|
||||
|
||||
|
||||
int enable_sync; /* configuration variable: enable time sync */
|
||||
int nvr_dosave; /* NVR is dirty, needs saved */
|
||||
|
||||
|
||||
static int8_t days_in_month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
|
||||
static intclk_t intclk;
|
||||
static nvr_t *saved_nvr = NULL;
|
||||
|
||||
|
||||
/* Determine whether or not the year is leap. */
|
||||
static int8_t
|
||||
is_leap(int8_t year)
|
||||
int
|
||||
nvr_is_leap(int year)
|
||||
{
|
||||
if (year % 400 == 0) return(1);
|
||||
if (year % 100 == 0) return(0);
|
||||
@@ -240,13 +94,13 @@ is_leap(int8_t year)
|
||||
|
||||
|
||||
/* Determine the days in the current month. */
|
||||
static int8_t
|
||||
get_days(int8_t month, int8_t year)
|
||||
int
|
||||
nvr_get_days(int month, int year)
|
||||
{
|
||||
if (month != 2)
|
||||
return(days_in_month[month - 1]);
|
||||
|
||||
return(is_leap(year) ? 29 : 28);
|
||||
return(nvr_is_leap(year) ? 29 : 28);
|
||||
}
|
||||
|
||||
|
||||
@@ -267,7 +121,7 @@ rtc_tick(void)
|
||||
intclk.hour = 0;
|
||||
intclk.mday++;
|
||||
}
|
||||
if (intclk.mday == (get_days(intclk.mon, intclk.year) + 1)) {
|
||||
if (intclk.mday == (nvr_get_days(intclk.mon, intclk.year) + 1)) {
|
||||
intclk.mday = 1;
|
||||
intclk.mon++;
|
||||
}
|
||||
@@ -278,107 +132,6 @@ rtc_tick(void)
|
||||
}
|
||||
|
||||
|
||||
/* Store the broken-down local time into the NVR. */
|
||||
static void
|
||||
rtc_getnvr(uint8_t *nvr, struct tm *tm)
|
||||
{
|
||||
if (nvr[RTC_REGB] & REGB_DM) {
|
||||
/* NVR is in Binary data mode. */
|
||||
nvr[RTC_SECONDS] = tm->tm_sec;
|
||||
nvr[RTC_MINUTES] = tm->tm_min;
|
||||
nvr[RTC_DOW] = tm->tm_wday+1;
|
||||
nvr[RTC_DOM] = tm->tm_mday;
|
||||
nvr[RTC_MONTH] = tm->tm_mon+1;
|
||||
nvr[RTC_YEAR] = tm->tm_year%100;
|
||||
|
||||
if (nvr[RTC_REGB] & REGB_2412) {
|
||||
/* NVR is in 24h mode. */
|
||||
nvr[RTC_HOURS] = tm->tm_hour;
|
||||
} else {
|
||||
/* NVR is in 12h mode. */
|
||||
nvr[RTC_HOURS] = (tm->tm_hour % 12) ? (tm->tm_hour % 12) : 12;
|
||||
if (tm->tm_hour > 11)
|
||||
nvr[RTC_HOURS] |= RTC_AMPM;
|
||||
}
|
||||
} else {
|
||||
/* NVR is in BCD data mode. */
|
||||
nvr[RTC_SECONDS] = RTC_BCD(tm->tm_sec);
|
||||
nvr[RTC_MINUTES] = RTC_BCD(tm->tm_min);
|
||||
nvr[RTC_DOW] = RTC_BCD(tm->tm_wday+1);
|
||||
nvr[RTC_DOM] = RTC_BCD(tm->tm_mday);
|
||||
nvr[RTC_MONTH] = RTC_BCD(tm->tm_mon+1);
|
||||
nvr[RTC_YEAR] = RTC_BCD(tm->tm_year%100);
|
||||
|
||||
if (nvr[RTC_REGB] & REGB_2412) {
|
||||
/* NVR is in 24h mode. */
|
||||
nvr[RTC_HOURS] = RTC_BCD(tm->tm_hour);
|
||||
} else {
|
||||
/* NVR is in 12h mode. */
|
||||
nvr[RTC_HOURS] = (tm->tm_hour % 12)
|
||||
? RTC_BCD(tm->tm_hour % 12)
|
||||
: RTC_BCD(12);
|
||||
if (tm->tm_hour > 11)
|
||||
nvr[RTC_HOURS] |= RTC_AMPM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Load local time from the NVR. */
|
||||
static void
|
||||
rtc_setnvr(uint8_t *nvr)
|
||||
{
|
||||
int8_t temp;
|
||||
|
||||
if (nvr[RTC_REGB] & REGB_DM) {
|
||||
intclk.sec = nvr[RTC_SECONDS];
|
||||
intclk.min = nvr[RTC_MINUTES];
|
||||
temp = nvr[RTC_HOURS];
|
||||
intclk.mday = nvr[RTC_DOM];
|
||||
intclk.mon = nvr[RTC_MONTH];
|
||||
intclk.year = nvr[RTC_YEAR];
|
||||
intclk.year += 1900;
|
||||
} else {
|
||||
intclk.sec = RTC_DCB(nvr[RTC_SECONDS]);
|
||||
intclk.min = RTC_DCB(nvr[RTC_MINUTES]);
|
||||
temp = RTC_DCB(nvr[RTC_HOURS]);
|
||||
intclk.mday = RTC_DCB(nvr[RTC_DOM]);
|
||||
intclk.mon = RTC_DCB(nvr[RTC_MONTH]);
|
||||
intclk.year = RTC_DCB(nvr[RTC_YEAR]);
|
||||
intclk.year += (RTC_DCB(nvr[RTC_CENTURY]) * 100);
|
||||
}
|
||||
|
||||
/* Adjust for 12/24 hour mode. */
|
||||
if (nvr[RTC_REGB] & REGB_2412)
|
||||
intclk.hour = temp;
|
||||
else
|
||||
intclk.hour = ((temp & ~RTC_AMPM) % 12) + ((temp & RTC_AMPM) ? 12 : 0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rtc_sync(uint8_t *nvr)
|
||||
{
|
||||
struct tm *tm;
|
||||
time_t now;
|
||||
|
||||
/* Get the current time of day, and convert to local time. */
|
||||
(void)time(&now);
|
||||
tm = localtime(&now);
|
||||
|
||||
/* Set the internal clock. */
|
||||
intclk.sec = tm->tm_sec;
|
||||
intclk.min = tm->tm_min;
|
||||
intclk.hour = tm->tm_hour;
|
||||
intclk.mday = tm->tm_mday;
|
||||
intclk.mon = tm->tm_mon+1;
|
||||
intclk.year = tm->tm_year+1900;
|
||||
|
||||
/* Set the NVR registers. */
|
||||
rtc_getnvr(nvr, tm);
|
||||
}
|
||||
|
||||
|
||||
/* This is the RTC one-second timer. */
|
||||
static void
|
||||
onesec_timer(void *priv)
|
||||
@@ -386,20 +139,13 @@ onesec_timer(void *priv)
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
|
||||
if (++nvr->onesec_cnt >= 100) {
|
||||
if (! (nvr->regs[RTC_REGB] & REGB_SET)) {
|
||||
nvr->upd_stat = REGA_UIP;
|
||||
/* Update the internal clock. */
|
||||
rtc_tick();
|
||||
|
||||
/* Update the system RTC. */
|
||||
rtc_tick();
|
||||
/* Update the RTC device if needed. */
|
||||
if (nvr->tick != NULL)
|
||||
(*nvr->tick)(nvr);
|
||||
|
||||
if (nvr->hook != NULL)
|
||||
(*nvr->hook)(nvr);
|
||||
|
||||
/* Re-calculate the timer. */
|
||||
nvr_recalc();
|
||||
|
||||
nvr->upd_ecount = (int64_t)((244.0 + 1984.0) * TIMER_USEC);
|
||||
}
|
||||
nvr->onesec_cnt = 0;
|
||||
}
|
||||
|
||||
@@ -407,241 +153,47 @@ onesec_timer(void *priv)
|
||||
}
|
||||
|
||||
|
||||
/* Check if the current time matches a set alarm time. */
|
||||
static int8_t
|
||||
check_alarm(nvr_t *nvr, int8_t addr)
|
||||
{
|
||||
#define ALARM_DONTCARE 0xc0
|
||||
return((nvr->regs[addr+1] == nvr->regs[addr]) ||
|
||||
((nvr->regs[addr+1] & ALARM_DONTCARE) == ALARM_DONTCARE));
|
||||
}
|
||||
|
||||
|
||||
/* This is the general update timer. */
|
||||
static void
|
||||
update_timer(void *priv)
|
||||
{
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
struct tm tm;
|
||||
int8_t dom, mon, sum, wd;
|
||||
int16_t cent, yr;
|
||||
|
||||
if (! (nvr->regs[RTC_REGB] & REGB_SET)) {
|
||||
/* Get the current time from the internal clock. */
|
||||
tm.tm_sec = intclk.sec;
|
||||
tm.tm_min = intclk.min;
|
||||
tm.tm_hour = intclk.hour;
|
||||
dom = intclk.mday;
|
||||
mon = intclk.mon;
|
||||
yr = intclk.year % 100;
|
||||
cent = ((intclk.year - yr) / 100) % 4;
|
||||
sum = dom+mon+yr+cent;
|
||||
wd = ((sum + 6) % 7);
|
||||
tm.tm_wday = wd;
|
||||
tm.tm_mday = intclk.mday;
|
||||
tm.tm_mon = intclk.mon-1;
|
||||
tm.tm_year = intclk.year-1900;
|
||||
rtc_getnvr(nvr->regs, &tm);
|
||||
|
||||
/* Clear update status. */
|
||||
nvr->upd_stat = 0;
|
||||
|
||||
if (check_alarm(nvr, RTC_SECONDS) &&
|
||||
check_alarm(nvr, RTC_MINUTES) &&
|
||||
check_alarm(nvr, RTC_HOURS)) {
|
||||
nvr->regs[RTC_REGC] |= REGC_AF;
|
||||
if (nvr->regs[RTC_REGB] & REGB_AIE) {
|
||||
nvr->regs[RTC_REGC] |= REGC_IRQF;
|
||||
|
||||
/* Generate an interrupt. */
|
||||
if (nvr->irq != -1)
|
||||
picint(1<<nvr->irq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The flag and interrupt should be issued
|
||||
* on update ended, not started.
|
||||
*/
|
||||
nvr->regs[RTC_REGC] |= REGC_UF;
|
||||
if (nvr->regs[RTC_REGB] & REGB_UIE) {
|
||||
nvr->regs[RTC_REGC] |= REGC_IRQF;
|
||||
|
||||
/* Generate an interrupt. */
|
||||
if (nvr->irq != -1)
|
||||
picint(1<<nvr->irq);
|
||||
}
|
||||
}
|
||||
|
||||
nvr->upd_ecount = 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ticker_timer(void *priv)
|
||||
{
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
int64_t c;
|
||||
|
||||
if (! (nvr->regs[RTC_REGA] & REGA_RS)) {
|
||||
nvr->rtctime = 0x7fffffff;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update our ticker interval. */
|
||||
c = 1 << ((nvr->regs[RTC_REGA] & REGA_RS) - 1);
|
||||
nvr->rtctime += (int64_t)(RTCCONST*c*(1<<TIMER_SHIFT));
|
||||
|
||||
nvr->regs[RTC_REGC] |= REGC_PF;
|
||||
if (nvr->regs[RTC_REGB] & REGB_PIE) {
|
||||
nvr->regs[RTC_REGC] |= REGC_IRQF;
|
||||
|
||||
/* Generate an interrupt. */
|
||||
if (nvr->irq != -1)
|
||||
picint(1<<nvr->irq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Set one of the chip's registers. */
|
||||
static void
|
||||
nvr_write(nvr_t *nvr, uint16_t reg, uint8_t val)
|
||||
{
|
||||
uint8_t old;
|
||||
int64_t c;
|
||||
|
||||
old = nvr->regs[reg];
|
||||
switch(reg) {
|
||||
case RTC_REGA:
|
||||
nvr->regs[reg] = val;
|
||||
if (val & REGA_RS) {
|
||||
c = 1 << ((val & REGA_RS) - 1);
|
||||
nvr->rtctime += (int64_t)(RTCCONST*c*(1<<TIMER_SHIFT));
|
||||
} else {
|
||||
nvr->rtctime = 0x7fffffff;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTC_REGB:
|
||||
nvr->regs[reg] = val;
|
||||
if (((old^val) & REGB_SET) && (val®B_SET)) {
|
||||
/* This has to be done according to the datasheet. */
|
||||
nvr->regs[RTC_REGA] &= ~REGA_UIP;
|
||||
|
||||
/* This also has to happen per the specification. */
|
||||
nvr->regs[RTC_REGB] &= ~REGB_UIE;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTC_REGC: /* R/O */
|
||||
case RTC_REGD: /* R/O */
|
||||
break;
|
||||
|
||||
default: /* non-RTC registers are just NVRAM */
|
||||
if (nvr->regs[reg] != val) {
|
||||
nvr->regs[reg] = val;
|
||||
|
||||
nvr_dosave = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((reg < RTC_REGA) || (reg == RTC_CENTURY)) {
|
||||
if ((reg != 1) && (reg != 3) && (reg != 5)) {
|
||||
if ((old != val) && !enable_sync) {
|
||||
/* Update internal clock. */
|
||||
rtc_setnvr(nvr->regs);
|
||||
|
||||
nvr_dosave = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Get one of the chip's registers. */
|
||||
static uint8_t
|
||||
nvr_read(nvr_t *nvr, uint16_t reg)
|
||||
{
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
switch(reg) {
|
||||
case RTC_REGA:
|
||||
ret = (nvr->regs[RTC_REGA] & 0x7f) | nvr->upd_stat;
|
||||
break;
|
||||
|
||||
case RTC_REGC:
|
||||
picintc(1<<nvr->irq);
|
||||
ret = nvr->regs[RTC_REGC];
|
||||
nvr->regs[RTC_REGC] = 0x00;
|
||||
break;
|
||||
|
||||
case RTC_REGD:
|
||||
nvr->regs[RTC_REGD] |= REGD_VRT;
|
||||
ret = nvr->regs[RTC_REGD];
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = nvr->regs[reg];
|
||||
break;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* Initialize the virtual RTC/NVRAM chip. */
|
||||
/* Initialize the generic NVRAM/RTC device. */
|
||||
void
|
||||
nvr_init(nvr_t *nvr)
|
||||
{
|
||||
char temp[32];
|
||||
int64_t c;
|
||||
char temp[64];
|
||||
struct tm *tm;
|
||||
time_t now;
|
||||
int c;
|
||||
|
||||
/* Clear some of it. */
|
||||
nvr->upd_stat = 0;
|
||||
nvr->upd_ecount = 0;
|
||||
nvr->onesec_time = 0;
|
||||
nvr->onesec_cnt = 0;
|
||||
memset(&intclk, 0x00, sizeof(intclk));
|
||||
|
||||
/* Pre-initialize the NVR file's name here. */
|
||||
sprintf(temp, "%s.nvr", machine_get_internal_name_ex(machine));
|
||||
/* Set up the NVR file's name. */
|
||||
sprintf(temp, "%s.nvr", machine_get_internal_name());
|
||||
c = strlen(temp)+1;
|
||||
nvr->fname = (wchar_t *)malloc(c*sizeof(wchar_t));
|
||||
mbstowcs(nvr->fname, temp, c);
|
||||
nvr->fn = (wchar_t *)malloc(c*sizeof(wchar_t));
|
||||
mbstowcs(nvr->fn, temp, c);
|
||||
|
||||
/* Set up our local handlers. */
|
||||
nvr->get = nvr_read;
|
||||
nvr->set = nvr_write;
|
||||
/* Initialize the internal clock as needed. */
|
||||
memset(&intclk, 0x00, sizeof(intclk));
|
||||
if (enable_sync) {
|
||||
/* Get the current time of day, and convert to local time. */
|
||||
(void)time(&now);
|
||||
tm = localtime(&now);
|
||||
|
||||
/* Set up our timers. */
|
||||
timer_add(ticker_timer, &nvr->rtctime, TIMER_ALWAYS_ENABLED, nvr);
|
||||
/* Set the internal clock. */
|
||||
nvr_time_set(tm);
|
||||
} else {
|
||||
/* Reset the internal clock to 1980/01/01 00:00. */
|
||||
intclk.mon = 1;
|
||||
intclk.year = 1980;
|
||||
}
|
||||
|
||||
/* Set up our timer. */
|
||||
timer_add(onesec_timer, &nvr->onesec_time, TIMER_ALWAYS_ENABLED, nvr);
|
||||
|
||||
timer_add(update_timer, &nvr->upd_ecount, &nvr->upd_ecount, nvr);
|
||||
|
||||
/* It does not need saving yet. */
|
||||
nvr_dosave = 0;
|
||||
|
||||
/* Save the NVR data pointer. */
|
||||
saved_nvr = nvr;
|
||||
}
|
||||
|
||||
|
||||
/* Re-calculate the timer values. */
|
||||
void
|
||||
nvr_recalc(void)
|
||||
{
|
||||
int64_t c, nt;
|
||||
|
||||
/* Make sure we have been initialized. */
|
||||
if (saved_nvr == NULL) return;
|
||||
|
||||
c = 1 << ((saved_nvr->regs[RTC_REGA] & REGA_RS) - 1);
|
||||
nt = (int64_t)(RTCCONST * c * (1<<TIMER_SHIFT));
|
||||
if (saved_nvr->rtctime > nt)
|
||||
saved_nvr->rtctime = nt;
|
||||
/* Try to load the saved data. */
|
||||
(void)nvr_load();
|
||||
}
|
||||
|
||||
|
||||
@@ -659,7 +211,6 @@ nvr_recalc(void)
|
||||
int
|
||||
nvr_load(void)
|
||||
{
|
||||
int64_t c;
|
||||
FILE *f;
|
||||
|
||||
/* Make sure we have been initialized. */
|
||||
@@ -669,41 +220,23 @@ nvr_load(void)
|
||||
memset(saved_nvr->regs, 0xff, sizeof(saved_nvr->regs));
|
||||
|
||||
/* Set the defaults. */
|
||||
memset(saved_nvr->regs, 0x00, RTC_REGS);
|
||||
saved_nvr->regs[RTC_DOM] = 1;
|
||||
saved_nvr->regs[RTC_MONTH] = 1;
|
||||
saved_nvr->regs[RTC_YEAR] = RTC_BCD(80);
|
||||
saved_nvr->regs[RTC_CENTURY] = RTC_BCD(19);
|
||||
|
||||
if (saved_nvr->load == NULL) {
|
||||
/* We are responsible for loading. */
|
||||
f = NULL;
|
||||
if (saved_nvr->mask != 0) {
|
||||
pclog("Opening NVR file: %ls...\n", nvr_path(saved_nvr->fname));
|
||||
f = plat_fopen(nvr_path(saved_nvr->fname), L"rb");
|
||||
}
|
||||
if (saved_nvr->reset != NULL)
|
||||
saved_nvr->reset(saved_nvr);
|
||||
|
||||
/* Load the (relevant) part of the NVR contents. */
|
||||
if (saved_nvr->size != 0) {
|
||||
pclog("NVR: loading from '%ls'\n", nvr_path(saved_nvr->fn));
|
||||
f = plat_fopen(nvr_path(saved_nvr->fn), L"rb");
|
||||
if (f != NULL) {
|
||||
/* Read NVR contents from file. */
|
||||
fread(saved_nvr->regs, sizeof(saved_nvr->regs), 1, f);
|
||||
(void)fread(saved_nvr->regs, saved_nvr->size, 1, f);
|
||||
(void)fclose(f);
|
||||
}
|
||||
} else {
|
||||
/* OK, use alternate function. */
|
||||
(*saved_nvr->load)(saved_nvr->fname);
|
||||
}
|
||||
|
||||
/* Update the internal clock state based on the NVR registers. */
|
||||
if (enable_sync)
|
||||
rtc_sync(saved_nvr->regs);
|
||||
else
|
||||
rtc_setnvr(saved_nvr->regs);
|
||||
|
||||
/* Get the local RTC running! */
|
||||
saved_nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1);
|
||||
saved_nvr->regs[RTC_REGB] = REGB_2412;
|
||||
c = 1 << ((saved_nvr->regs[RTC_REGA] & REGA_RS) - 1);
|
||||
saved_nvr->rtctime += (int64_t)(RTCCONST * c * (1<<TIMER_SHIFT));
|
||||
if (saved_nvr->start != NULL)
|
||||
saved_nvr->start(saved_nvr);
|
||||
|
||||
return(1);
|
||||
}
|
||||
@@ -718,22 +251,14 @@ nvr_save(void)
|
||||
/* Make sure we have been initialized. */
|
||||
if (saved_nvr == NULL) return(0);
|
||||
|
||||
if (saved_nvr->save == NULL) {
|
||||
/* We are responsible for saving. */
|
||||
f = NULL;
|
||||
if (saved_nvr->mask != 0) {
|
||||
pclog("Saving NVR file: %ls...\n", nvr_path(saved_nvr->fname));
|
||||
f = plat_fopen(nvr_path(saved_nvr->fname), L"wb");
|
||||
}
|
||||
|
||||
if (saved_nvr->size != 0) {
|
||||
pclog("NVR: saving to '%ls'\n", nvr_path(saved_nvr->fn));
|
||||
f = plat_fopen(nvr_path(saved_nvr->fn), L"wb");
|
||||
if (f != NULL) {
|
||||
/* Save NVR contents to file. */
|
||||
(void)fwrite(saved_nvr->regs, sizeof(saved_nvr->regs), 1, f);
|
||||
(void)fclose(f);
|
||||
(void)fwrite(saved_nvr->regs, saved_nvr->size, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
} else {
|
||||
/* OK, use alternate function. */
|
||||
(*saved_nvr->save)(saved_nvr->fname);
|
||||
}
|
||||
|
||||
/* Device is clean again. */
|
||||
@@ -743,6 +268,42 @@ nvr_save(void)
|
||||
}
|
||||
|
||||
|
||||
/* Get current time from internal clock. */
|
||||
void
|
||||
nvr_time_get(struct tm *tm)
|
||||
{
|
||||
int8_t dom, mon, sum, wd;
|
||||
int16_t cent, yr;
|
||||
|
||||
tm->tm_sec = intclk.sec;
|
||||
tm->tm_min = intclk.min;
|
||||
tm->tm_hour = intclk.hour;
|
||||
dom = intclk.mday;
|
||||
mon = intclk.mon;
|
||||
yr = (intclk.year % 100);
|
||||
cent = ((intclk.year - yr) / 100) % 4;
|
||||
sum = dom+mon+yr+cent;
|
||||
wd = ((sum + 6) % 7);
|
||||
tm->tm_wday = wd;
|
||||
tm->tm_mday = intclk.mday;
|
||||
tm->tm_mon = (intclk.mon - 1);
|
||||
tm->tm_year = (intclk.year - 1900);
|
||||
}
|
||||
|
||||
|
||||
/* Set internal clock time. */
|
||||
void
|
||||
nvr_time_set(struct tm *tm)
|
||||
{
|
||||
intclk.sec = tm->tm_sec;
|
||||
intclk.min = tm->tm_min;
|
||||
intclk.hour = tm->tm_hour;
|
||||
intclk.mday = tm->tm_mday;
|
||||
intclk.mon = (tm->tm_mon + 1);
|
||||
intclk.year = (tm->tm_year + 1900);
|
||||
}
|
||||
|
||||
|
||||
/* Get an absolute path to the NVR folder. */
|
||||
wchar_t *
|
||||
nvr_path(wchar_t *str)
|
||||
@@ -759,11 +320,7 @@ nvr_path(wchar_t *str)
|
||||
plat_dir_create(temp);
|
||||
|
||||
/* Now append the actual filename. */
|
||||
#ifdef _WIN32
|
||||
wcscat(temp, L"\\");
|
||||
#else
|
||||
wcscat(temp, L"/");
|
||||
#endif
|
||||
plat_path_slash(temp);
|
||||
wcscat(temp, str);
|
||||
|
||||
return(temp);
|
||||
|
||||
218
src/nvr.h
218
src/nvr.h
@@ -1,119 +1,99 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Definitions for a defacto-standard RTC/NVRAM device.
|
||||
*
|
||||
* Version: @(#)nvr.h 1.0.5 2017/11/22
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Mahod,
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2016-2017 Miran Grca.
|
||||
* Copyright 2016-2017 Mahod.
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#ifndef EMU_NVR_H
|
||||
# define EMU_NVR_H
|
||||
|
||||
|
||||
/* Conversion from BCD to Binary and vice versa. */
|
||||
#define RTC_BCD(x) (((x) % 10) | (((x) / 10) << 4))
|
||||
#define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f))
|
||||
|
||||
/* RTC registers and bit definitions. */
|
||||
#define RTC_SECONDS 0
|
||||
#define RTC_ALSECONDS 1
|
||||
#define RTC_MINUTES 2
|
||||
#define RTC_ALMINUTES 3
|
||||
#define RTC_HOURS 4
|
||||
# define RTC_AMPM 0x80 /* PM flag if 12h format in use */
|
||||
#define RTC_ALHOURS 5
|
||||
#define RTC_DOW 6
|
||||
#define RTC_DOM 7
|
||||
#define RTC_MONTH 8
|
||||
#define RTC_YEAR 9
|
||||
#define RTC_REGA 10
|
||||
# define REGA_UIP 0x80
|
||||
# define REGA_DV2 0x40
|
||||
# define REGA_DV1 0x20
|
||||
# define REGA_DV0 0x10
|
||||
# define REGA_DV 0x70
|
||||
# define REGA_RS3 0x08
|
||||
# define REGA_RS2 0x04
|
||||
# define REGA_RS1 0x02
|
||||
# define REGA_RS0 0x01
|
||||
# define REGA_RS 0x0f
|
||||
#define RTC_REGB 11
|
||||
# define REGB_SET 0x80
|
||||
# define REGB_PIE 0x40
|
||||
# define REGB_AIE 0x20
|
||||
# define REGB_UIE 0x10
|
||||
# define REGB_SQWE 0x08
|
||||
# define REGB_DM 0x04
|
||||
# define REGB_2412 0x02
|
||||
# define REGB_DSE 0x01
|
||||
#define RTC_REGC 12
|
||||
# define REGC_IRQF 0x80
|
||||
# define REGC_PF 0x40
|
||||
# define REGC_AF 0x20
|
||||
# define REGC_UF 0x10
|
||||
#define RTC_REGD 13
|
||||
# define REGD_VRT 0x80
|
||||
#define RTC_CENTURY 0x32 /* century register */
|
||||
#define RTC_REGS 14 /* number of registers */
|
||||
|
||||
|
||||
|
||||
/* Define a (defacto-standard) RTC/NVRAM chip. */
|
||||
typedef struct _nvr_ {
|
||||
uint8_t regs[RTC_REGS+114]; /* these are the registers */
|
||||
|
||||
int64_t mask,
|
||||
irq,
|
||||
addr;
|
||||
|
||||
wchar_t *fname;
|
||||
|
||||
int64_t upd_stat,
|
||||
upd_ecount,
|
||||
onesec_time,
|
||||
onesec_cnt,
|
||||
rtctime,
|
||||
oldmachine;
|
||||
|
||||
/* Hooks to internal RTC I/O functions. */
|
||||
void (*set)(struct _nvr_ *, uint16_t, uint8_t);
|
||||
uint8_t (*get)(struct _nvr_ *, uint16_t);
|
||||
|
||||
/* Hooks to alternative load/save functions. */
|
||||
int8_t (*load)(wchar_t *fname);
|
||||
int8_t (*save)(wchar_t *fname);
|
||||
|
||||
/* Hook to RTC ticker handler. */
|
||||
void (*hook)(struct _nvr_ *);
|
||||
} nvr_t;
|
||||
|
||||
|
||||
extern int enable_sync;
|
||||
extern int nvr_dosave;
|
||||
|
||||
|
||||
extern void nvr_init(nvr_t *);
|
||||
extern int nvr_load(void);
|
||||
extern int nvr_save(void);
|
||||
extern void nvr_recalc(void);
|
||||
|
||||
extern wchar_t *nvr_path(wchar_t *str);
|
||||
extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode);
|
||||
|
||||
extern void nvr_at_init(int64_t irq);
|
||||
extern void nvr_at_close(void);
|
||||
|
||||
|
||||
#endif /*EMU_NVR_H*/
|
||||
/*
|
||||
* 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 generic NVRAM/CMOS driver.
|
||||
*
|
||||
* Version: @(#)nvr.h 1.0.2 2018/03/11
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* 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 EMU_NVR_H
|
||||
# define EMU_NVR_H
|
||||
|
||||
|
||||
#define NVR_MAXSIZE 128 /* max size of NVR data */
|
||||
|
||||
/* Conversion from BCD to Binary and vice versa. */
|
||||
#define RTC_BCD(x) (((x) % 10) | (((x) / 10) << 4))
|
||||
#define RTC_DCB(x) ((((x) & 0xf0) >> 4) * 10 + ((x) & 0x0f))
|
||||
#define RTC_BCDINC(x,y) RTC_BCD(RTC_DCB(x) + y)
|
||||
|
||||
|
||||
/* Define a generic RTC/NVRAM device. */
|
||||
typedef struct _nvr_ {
|
||||
uint8_t regs[NVR_MAXSIZE]; /* these are the registers */
|
||||
wchar_t *fn;
|
||||
/* pathname of image file */
|
||||
uint16_t size;
|
||||
/* device configuration */
|
||||
int8_t irq;
|
||||
|
||||
int8_t upd_stat, /* FIXME: move to private struct */
|
||||
addr;
|
||||
int64_t upd_ecount, /* FIXME: move to private struct */
|
||||
onesec_time,
|
||||
onesec_cnt,
|
||||
rtctime;
|
||||
|
||||
/* Hooks to device functions. */
|
||||
void (*reset)(struct _nvr_ *);
|
||||
void (*start)(struct _nvr_ *);
|
||||
void (*tick)(struct _nvr_ *);
|
||||
} nvr_t;
|
||||
|
||||
|
||||
extern int nvr_dosave;
|
||||
|
||||
|
||||
extern void nvr_init(nvr_t *);
|
||||
extern int nvr_load(void);
|
||||
extern int nvr_save(void);
|
||||
|
||||
extern int nvr_is_leap(int year);
|
||||
extern int nvr_get_days(int month, int year);
|
||||
extern void nvr_time_get(struct tm *);
|
||||
extern void nvr_time_set(struct tm *);
|
||||
|
||||
extern wchar_t *nvr_path(wchar_t *str);
|
||||
extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode);
|
||||
|
||||
extern void nvr_at_init(int irq);
|
||||
extern void nvr_at_close(void);
|
||||
|
||||
|
||||
785
src/nvr_at.c
785
src/nvr_at.c
@@ -1,124 +1,661 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* IBM PC/AT RTC/NVRAM ("CMOS") emulation.
|
||||
*
|
||||
* The original PC/AT series had DS12885 series modules; later
|
||||
* versions and clones used the 12886 and/or 1288(C)7 series,
|
||||
* or the MC146818 series, all with an external battery. Many
|
||||
* of those batteries would create corrosion issues later on
|
||||
* in mainboard life...
|
||||
*
|
||||
* Version: @(#)nvr_at.c 1.0.9 2018/02/27
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include "cpu/cpu.h"
|
||||
#include "io.h"
|
||||
#include "device.h"
|
||||
#include "machine/machine.h"
|
||||
#include "mem.h"
|
||||
#include "nmi.h"
|
||||
#include "nvr.h"
|
||||
#include "rom.h"
|
||||
|
||||
|
||||
static nvr_t *nvrp;
|
||||
|
||||
|
||||
static void
|
||||
nvr_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
if (! (addr & 1)) {
|
||||
nvr->addr = (val & nvr->mask);
|
||||
if (!(machines[machine].flags & MACHINE_MCA) && (romset != ROM_IBMPS1_2133))
|
||||
nmi_mask = (~val & 0x80);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Write the chip's registers. */
|
||||
(*nvr->set)(nvr, nvr->addr, val);
|
||||
}
|
||||
|
||||
|
||||
static uint8_t
|
||||
nvr_read(uint16_t addr, void *priv)
|
||||
{
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
uint8_t ret;
|
||||
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
if (addr & 1) {
|
||||
/* Read from the chip's registers. */
|
||||
ret = (*nvr->get)(nvr, nvr->addr);
|
||||
} else {
|
||||
ret = nvr->addr;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nvr_at_close(void)
|
||||
{
|
||||
if (nvrp == NULL)
|
||||
return;
|
||||
|
||||
if (nvrp->fname != NULL)
|
||||
free(nvrp->fname);
|
||||
|
||||
free(nvrp);
|
||||
|
||||
nvrp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nvr_at_init(int64_t irq)
|
||||
{
|
||||
nvr_t *nvr;
|
||||
|
||||
/* Allocate an NVR for this machine. */
|
||||
nvr = (nvr_t *)malloc(sizeof(nvr_t));
|
||||
if (nvr == NULL) return;
|
||||
memset(nvr, 0x00, sizeof(nvr_t));
|
||||
|
||||
/* This is machine specific. */
|
||||
nvr->mask = machines[machine].nvrmask;
|
||||
nvr->irq = irq;
|
||||
|
||||
/* Set up any local handlers here. */
|
||||
|
||||
/* Initialize the actual NVR. */
|
||||
nvr_init(nvr);
|
||||
|
||||
/* Set up the PC/AT handler for this device. */
|
||||
io_sethandler(0x0070, 2,
|
||||
nvr_read, NULL, NULL, nvr_write, NULL, NULL, nvr);
|
||||
|
||||
/* Load the NVR into memory! */
|
||||
(void)nvr_load();
|
||||
|
||||
nvrp = nvr;
|
||||
}
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Implement a more-or-less defacto-standard RTC/NVRAM.
|
||||
*
|
||||
* When IBM released the PC/AT machine, it came standard with a
|
||||
* battery-backed RTC chip to keep the time of day, something
|
||||
* that was optional on standard PC's with a myriad variants
|
||||
* being put on the market, often on cheap multi-I/O cards.
|
||||
*
|
||||
* The PC/AT had an on-board DS12885-series chip ("the black
|
||||
* block") which was an RTC/clock chip with onboard oscillator
|
||||
* and a backup battery (hence the big size.) The chip also had
|
||||
* a small amount of RAM bytes available to the user, which was
|
||||
* used by IBM's ROM BIOS to store machine configuration data.
|
||||
* Later versions and clones used the 12886 and/or 1288(C)7
|
||||
* series, or the MC146818 series, all with an external battery.
|
||||
* Many of those batteries would create corrosion issues later
|
||||
* on in mainboard life...
|
||||
*
|
||||
* Since then, pretty much any PC has an implementation of that
|
||||
* device, which became known as the "nvr" or "cmos".
|
||||
*
|
||||
* NOTES Info extracted from the data sheets:
|
||||
*
|
||||
* * The century register at location 32h is a BCD register
|
||||
* designed to automatically load the BCD value 20 as the
|
||||
* year register changes from 99 to 00. The MSB of this
|
||||
* register is not affected when the load of 20 occurs,
|
||||
* and remains at the value written by the user.
|
||||
*
|
||||
* * Rate Selector (RS3:RS0)
|
||||
* These four rate-selection bits select one of the 13
|
||||
* taps on the 15-stage divider or disable the divider
|
||||
* output. The tap selected can be used to generate an
|
||||
* output square wave (SQW pin) and/or a periodic interrupt.
|
||||
*
|
||||
* The user can do one of the following:
|
||||
* - enable the interrupt with the PIE bit;
|
||||
* - enable the SQW output pin with the SQWE bit;
|
||||
* - enable both at the same time and the same rate; or
|
||||
* - enable neither.
|
||||
*
|
||||
* Table 3 lists the periodic interrupt rates and the square
|
||||
* wave frequencies that can be chosen with the RS bits.
|
||||
* These four read/write bits are not affected by !RESET.
|
||||
*
|
||||
* * Oscillator (DV2:DV0)
|
||||
* These three bits are used to turn the oscillator on or
|
||||
* off and to reset the countdown chain. A pattern of 010
|
||||
* is the only combination of bits that turn the oscillator
|
||||
* on and allow the RTC to keep time. A pattern of 11x
|
||||
* enables the oscillator but holds the countdown chain in
|
||||
* reset. The next update occurs at 500ms after a pattern
|
||||
* of 010 is written to DV0, DV1, and DV2.
|
||||
*
|
||||
* * Update-In-Progress (UIP)
|
||||
* This bit is a status flag that can be monitored. When the
|
||||
* UIP bit is a 1, the update transfer occurs soon. When
|
||||
* UIP is a 0, the update transfer does not occur for at
|
||||
* least 244us. The time, calendar, and alarm information
|
||||
* in RAM is fully available for access when the UIP bit
|
||||
* is 0. The UIP bit is read-only and is not affected by
|
||||
* !RESET. Writing the SET bit in Register B to a 1
|
||||
* inhibits any update transfer and clears the UIP status bit.
|
||||
*
|
||||
* * Daylight Saving Enable (DSE)
|
||||
* This bit is a read/write bit that enables two daylight
|
||||
* saving adjustments when DSE is set to 1. On the first
|
||||
* Sunday in April (or the last Sunday in April in the
|
||||
* MC146818A), the time increments from 1:59:59 AM to
|
||||
* 3:00:00 AM. On the last Sunday in October when the time
|
||||
* first reaches 1:59:59 AM, it changes to 1:00:00 AM.
|
||||
*
|
||||
* When DSE is enabled, the internal logic test for the
|
||||
* first/last Sunday condition at midnight. If the DSE bit
|
||||
* is not set when the test occurs, the daylight saving
|
||||
* function does not operate correctly. These adjustments
|
||||
* do not occur when the DSE bit is 0. This bit is not
|
||||
* affected by internal functions or !RESET.
|
||||
*
|
||||
* * 24/12
|
||||
* The 24/12 control bit establishes the format of the hours
|
||||
* byte. A 1 indicates the 24-hour mode and a 0 indicates
|
||||
* the 12-hour mode. This bit is read/write and is not
|
||||
* affected by internal functions or !RESET.
|
||||
*
|
||||
* * Data Mode (DM)
|
||||
* This bit indicates whether time and calendar information
|
||||
* is in binary or BCD format. The DM bit is set by the
|
||||
* program to the appropriate format and can be read as
|
||||
* required. This bit is not modified by internal functions
|
||||
* or !RESET. A 1 in DM signifies binary data, while a 0 in
|
||||
* DM specifies BCD data.
|
||||
*
|
||||
* * Square-Wave Enable (SQWE)
|
||||
* When this bit is set to 1, a square-wave signal at the
|
||||
* frequency set by the rate-selection bits RS3-RS0 is driven
|
||||
* out on the SQW pin. When the SQWE bit is set to 0, the
|
||||
* SQW pin is held low. SQWE is a read/write bit and is
|
||||
* cleared by !RESET. SQWE is low if disabled, and is high
|
||||
* impedance when VCC is below VPF. SQWE is cleared to 0 on
|
||||
* !RESET.
|
||||
*
|
||||
* * Update-Ended Interrupt Enable (UIE)
|
||||
* This bit is a read/write bit that enables the update-end
|
||||
* flag (UF) bit in Register C to assert !IRQ. The !RESET
|
||||
* pin going low or the SET bit going high clears the UIE bit.
|
||||
* The internal functions of the device do not affect the UIE
|
||||
* bit, but is cleared to 0 on !RESET.
|
||||
*
|
||||
* * Alarm Interrupt Enable (AIE)
|
||||
* This bit is a read/write bit that, when set to 1, permits
|
||||
* the alarm flag (AF) bit in Register C to assert !IRQ. An
|
||||
* alarm interrupt occurs for each second that the three time
|
||||
* bytes equal the three alarm bytes, including a don't-care
|
||||
* alarm code of binary 11XXXXXX. The AF bit does not
|
||||
* initiate the !IRQ signal when the AIE bit is set to 0.
|
||||
* The internal functions of the device do not affect the AIE
|
||||
* bit, but is cleared to 0 on !RESET.
|
||||
*
|
||||
* * Periodic Interrupt Enable (PIE)
|
||||
* The PIE bit is a read/write bit that allows the periodic
|
||||
* interrupt flag (PF) bit in Register C to drive the !IRQ pin
|
||||
* low. When the PIE bit is set to 1, periodic interrupts are
|
||||
* generated by driving the !IRQ pin low at a rate specified
|
||||
* by the RS3-RS0 bits of Register A. A 0 in the PIE bit
|
||||
* blocks the !IRQ output from being driven by a periodic
|
||||
* interrupt, but the PF bit is still set at the periodic
|
||||
* rate. PIE is not modified b any internal device functions,
|
||||
* but is cleared to 0 on !RESET.
|
||||
*
|
||||
* * SET
|
||||
* When the SET bit is 0, the update transfer functions
|
||||
* normally by advancing the counts once per second. When
|
||||
* the SET bit is written to 1, any update transfer is
|
||||
* inhibited, and the program can initialize the time and
|
||||
* calendar bytes without an update occurring in the midst of
|
||||
* initializing. Read cycles can be executed in a similar
|
||||
* manner. SET is a read/write bit and is not affected by
|
||||
* !RESET or internal functions of the device.
|
||||
*
|
||||
* * Update-Ended Interrupt Flag (UF)
|
||||
* This bit is set after each update cycle. When the UIE
|
||||
* bit is set to 1, the 1 in UF causes the IRQF bit to be
|
||||
* a 1, which asserts the !IRQ pin. This bit can be
|
||||
* cleared by reading Register C or with a !RESET.
|
||||
*
|
||||
* * Alarm Interrupt Flag (AF)
|
||||
* A 1 in the AF bit indicates that the current time has
|
||||
* matched the alarm time. If the AIE bit is also 1, the
|
||||
* !IRQ pin goes low and a 1 appears in the IRQF bit. This
|
||||
* bit can be cleared by reading Register C or with a
|
||||
* !RESET.
|
||||
*
|
||||
* * Periodic Interrupt Flag (PF)
|
||||
* This bit is read-only and is set to 1 when an edge is
|
||||
* detected on the selected tap of the divider chain. The
|
||||
* RS3 through RS0 bits establish the periodic rate. PF is
|
||||
* set to 1 independent of the state of the PIE bit. When
|
||||
* both PF and PIE are 1s, the !IRQ signal is active and
|
||||
* sets the IRQF bit. This bit can be cleared by reading
|
||||
* Register C or with a !RESET.
|
||||
*
|
||||
* * Interrupt Request Flag (IRQF)
|
||||
* The interrupt request flag (IRQF) is set to a 1 when one
|
||||
* or more of the following are true:
|
||||
* - PF == PIE == 1
|
||||
* - AF == AIE == 1
|
||||
* - UF == UIE == 1
|
||||
* Any time the IRQF bit is a 1, the !IRQ pin is driven low.
|
||||
* All flag bits are cleared after Register C is read by the
|
||||
* program or when the !RESET pin is low.
|
||||
*
|
||||
* * Valid RAM and Time (VRT)
|
||||
* This bit indicates the condition of the battery connected
|
||||
* to the VBAT pin. This bit is not writeable and should
|
||||
* always be 1 when read. If a 0 is ever present, an
|
||||
* exhausted internal lithium energy source is indicated and
|
||||
* both the contents of the RTC data and RAM data are
|
||||
* questionable. This bit is unaffected by !RESET.
|
||||
*
|
||||
* This file implements a generic version of the RTC/NVRAM chip,
|
||||
* including the later update (DS12887A) which implemented a
|
||||
* "century" register to be compatible with Y2K.
|
||||
*
|
||||
* Version: @(#)nvr_at.c 1.0.3 2018/03/11
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Mahod,
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the:
|
||||
*
|
||||
* Free Software Foundation, Inc.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <time.h>
|
||||
#include "86box.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "machine/machine.h"
|
||||
#include "io.h"
|
||||
#include "pic.h"
|
||||
#include "pit.h"
|
||||
#include "mem.h"
|
||||
#include "nmi.h"
|
||||
#include "timer.h"
|
||||
#include "device.h"
|
||||
#include "nvr.h"
|
||||
#include "rom.h"
|
||||
|
||||
|
||||
/* RTC registers and bit definitions. */
|
||||
#define RTC_SECONDS 0
|
||||
#define RTC_ALSECONDS 1
|
||||
#define RTC_MINUTES 2
|
||||
#define RTC_ALMINUTES 3
|
||||
#define RTC_HOURS 4
|
||||
# define RTC_AMPM 0x80 /* PM flag if 12h format in use */
|
||||
#define RTC_ALHOURS 5
|
||||
#define RTC_DOW 6
|
||||
#define RTC_DOM 7
|
||||
#define RTC_MONTH 8
|
||||
#define RTC_YEAR 9
|
||||
#define RTC_REGA 10
|
||||
# define REGA_UIP 0x80
|
||||
# define REGA_DV2 0x40
|
||||
# define REGA_DV1 0x20
|
||||
# define REGA_DV0 0x10
|
||||
# define REGA_DV 0x70
|
||||
# define REGA_RS3 0x08
|
||||
# define REGA_RS2 0x04
|
||||
# define REGA_RS1 0x02
|
||||
# define REGA_RS0 0x01
|
||||
# define REGA_RS 0x0f
|
||||
#define RTC_REGB 11
|
||||
# define REGB_SET 0x80
|
||||
# define REGB_PIE 0x40
|
||||
# define REGB_AIE 0x20
|
||||
# define REGB_UIE 0x10
|
||||
# define REGB_SQWE 0x08
|
||||
# define REGB_DM 0x04
|
||||
# define REGB_2412 0x02
|
||||
# define REGB_DSE 0x01
|
||||
#define RTC_REGC 12
|
||||
# define REGC_IRQF 0x80
|
||||
# define REGC_PF 0x40
|
||||
# define REGC_AF 0x20
|
||||
# define REGC_UF 0x10
|
||||
#define RTC_REGD 13
|
||||
# define REGD_VRT 0x80
|
||||
#define RTC_CENTURY 0x32 /* century register */
|
||||
#define RTC_REGS 14 /* number of registers */
|
||||
|
||||
|
||||
static nvr_t *nvrp;
|
||||
|
||||
|
||||
/* Get the current NVR time. */
|
||||
static void
|
||||
time_get(uint8_t *regs, struct tm *tm)
|
||||
{
|
||||
int8_t temp;
|
||||
|
||||
if (regs[RTC_REGB] & REGB_DM) {
|
||||
/* NVR is in Binary data mode. */
|
||||
tm->tm_sec = regs[RTC_SECONDS];
|
||||
tm->tm_min = regs[RTC_MINUTES];
|
||||
temp = regs[RTC_HOURS];
|
||||
tm->tm_wday = (regs[RTC_DOW] - 1);
|
||||
tm->tm_mday = regs[RTC_DOM];
|
||||
tm->tm_mon = (regs[RTC_MONTH] - 1);
|
||||
tm->tm_year = regs[RTC_YEAR];
|
||||
tm->tm_year += (regs[RTC_CENTURY] * 100) - 1900;
|
||||
} else {
|
||||
/* NVR is in BCD data mode. */
|
||||
tm->tm_sec = RTC_DCB(regs[RTC_SECONDS]);
|
||||
tm->tm_min = RTC_DCB(regs[RTC_MINUTES]);
|
||||
temp = RTC_DCB(regs[RTC_HOURS]);
|
||||
tm->tm_wday = (RTC_DCB(regs[RTC_DOW]) - 1);
|
||||
tm->tm_mday = RTC_DCB(regs[RTC_DOM]);
|
||||
tm->tm_mon = (RTC_DCB(regs[RTC_MONTH]) - 1);
|
||||
tm->tm_year = RTC_DCB(regs[RTC_YEAR]);
|
||||
tm->tm_year += (RTC_DCB(regs[RTC_CENTURY]) * 100) - 1900;
|
||||
}
|
||||
|
||||
/* Adjust for 12/24 hour mode. */
|
||||
if (regs[RTC_REGB] & REGB_2412)
|
||||
tm->tm_hour = temp;
|
||||
else
|
||||
tm->tm_hour = ((temp & ~RTC_AMPM)%12) + ((temp&RTC_AMPM) ? 12 : 0);
|
||||
}
|
||||
|
||||
|
||||
/* Set the current NVR time. */
|
||||
static void
|
||||
time_set(uint8_t *regs, struct tm *tm)
|
||||
{
|
||||
int year = (tm->tm_year + 1900);
|
||||
|
||||
if (regs[RTC_REGB] & REGB_DM) {
|
||||
/* NVR is in Binary data mode. */
|
||||
regs[RTC_SECONDS] = tm->tm_sec;
|
||||
regs[RTC_MINUTES] = tm->tm_min;
|
||||
regs[RTC_DOW] = (tm->tm_wday + 1);
|
||||
regs[RTC_DOM] = tm->tm_mday;
|
||||
regs[RTC_MONTH] = (tm->tm_mon + 1);
|
||||
regs[RTC_YEAR] = (year % 100);
|
||||
regs[RTC_CENTURY] = (year / 100);
|
||||
|
||||
if (regs[RTC_REGB] & REGB_2412) {
|
||||
/* NVR is in 24h mode. */
|
||||
regs[RTC_HOURS] = tm->tm_hour;
|
||||
} else {
|
||||
/* NVR is in 12h mode. */
|
||||
regs[RTC_HOURS] = (tm->tm_hour % 12) ? (tm->tm_hour % 12) : 12;
|
||||
if (tm->tm_hour > 11)
|
||||
regs[RTC_HOURS] |= RTC_AMPM;
|
||||
}
|
||||
} else {
|
||||
/* NVR is in BCD data mode. */
|
||||
regs[RTC_SECONDS] = RTC_BCD(tm->tm_sec);
|
||||
regs[RTC_MINUTES] = RTC_BCD(tm->tm_min);
|
||||
regs[RTC_DOW] = (RTC_BCD(tm->tm_wday) + 1);
|
||||
regs[RTC_DOM] = RTC_BCD(tm->tm_mday);
|
||||
regs[RTC_MONTH] = (RTC_BCD(tm->tm_mon) + 1);
|
||||
regs[RTC_YEAR] = RTC_BCD(year % 100);
|
||||
regs[RTC_CENTURY] = RTC_BCD(year / 100);
|
||||
|
||||
if (regs[RTC_REGB] & REGB_2412) {
|
||||
/* NVR is in 24h mode. */
|
||||
regs[RTC_HOURS] = RTC_BCD(tm->tm_hour);
|
||||
} else {
|
||||
/* NVR is in 12h mode. */
|
||||
regs[RTC_HOURS] = (tm->tm_hour % 12)
|
||||
? RTC_BCD(tm->tm_hour % 12)
|
||||
: RTC_BCD(12);
|
||||
if (tm->tm_hour > 11)
|
||||
regs[RTC_HOURS] |= RTC_AMPM;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Check if the current time matches a set alarm time. */
|
||||
static int8_t
|
||||
check_alarm(uint8_t *regs, int8_t addr)
|
||||
{
|
||||
#define ALARM_DONTCARE 0xc0
|
||||
return((regs[addr+1] == regs[addr]) ||
|
||||
((regs[addr+1] & ALARM_DONTCARE) == ALARM_DONTCARE));
|
||||
}
|
||||
|
||||
|
||||
/* Update the NVR registers from the internal clock. */
|
||||
static void
|
||||
update_timer(void *priv)
|
||||
{
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
struct tm tm;
|
||||
|
||||
if (! (nvr->regs[RTC_REGB] & REGB_SET)) {
|
||||
/* Get the current time from the internal clock. */
|
||||
nvr_time_get(&tm);
|
||||
|
||||
/* Update registers with current time. */
|
||||
time_set(nvr->regs, &tm);
|
||||
|
||||
|
||||
/* Clear update status. */
|
||||
nvr->upd_stat = 0x00;
|
||||
|
||||
/* Check for any alarms we need to handle. */
|
||||
if (check_alarm(nvr->regs, RTC_SECONDS) &&
|
||||
check_alarm(nvr->regs, RTC_MINUTES) &&
|
||||
check_alarm(nvr->regs, RTC_HOURS)) {
|
||||
nvr->regs[RTC_REGC] |= REGC_AF;
|
||||
if (nvr->regs[RTC_REGB] & REGB_AIE) {
|
||||
nvr->regs[RTC_REGC] |= REGC_IRQF;
|
||||
|
||||
/* Generate an interrupt. */
|
||||
if (nvr->irq != -1)
|
||||
picint(1<<nvr->irq);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The flag and interrupt should be issued
|
||||
* on update ended, not started.
|
||||
*/
|
||||
nvr->regs[RTC_REGC] |= REGC_UF;
|
||||
if (nvr->regs[RTC_REGB] & REGB_UIE) {
|
||||
nvr->regs[RTC_REGC] |= REGC_IRQF;
|
||||
|
||||
/* Generate an interrupt. */
|
||||
if (nvr->irq != -1)
|
||||
picint(1<<nvr->irq);
|
||||
}
|
||||
}
|
||||
|
||||
nvr->upd_ecount = 0;
|
||||
}
|
||||
|
||||
|
||||
/* Re-calculate the timer values. */
|
||||
static void
|
||||
rtc_timer_recalc(nvr_t *nvr, int add)
|
||||
{
|
||||
int64_t c, nt;
|
||||
|
||||
c = 1 << ((nvr->regs[RTC_REGA] & REGA_RS) - 1);
|
||||
nt = (int64_t)(RTCCONST * c * (1<<TIMER_SHIFT));
|
||||
if (add)
|
||||
nvr->rtctime += nt;
|
||||
else if (nvr->rtctime > nt)
|
||||
nvr->rtctime = nt;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
rtc_timer(void *priv)
|
||||
{
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
|
||||
if (! (nvr->regs[RTC_REGA] & REGA_RS)) {
|
||||
nvr->rtctime = 0x7fffffff;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Update our timer interval. */
|
||||
rtc_timer_recalc(nvr, 1);
|
||||
|
||||
nvr->regs[RTC_REGC] |= REGC_PF;
|
||||
if (nvr->regs[RTC_REGB] & REGB_PIE) {
|
||||
nvr->regs[RTC_REGC] |= REGC_IRQF;
|
||||
|
||||
/* Generate an interrupt. */
|
||||
if (nvr->irq != -1)
|
||||
picint(1<<nvr->irq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Callback from internal clock, another second passed. */
|
||||
static void
|
||||
tick_timer(nvr_t *nvr)
|
||||
{
|
||||
if (nvr->regs[RTC_REGB] & REGB_SET) return;
|
||||
|
||||
nvr->upd_stat = REGA_UIP;
|
||||
|
||||
nvr->upd_ecount = (int64_t)((244.0 + 1984.0) * TIMER_USEC);
|
||||
}
|
||||
|
||||
|
||||
/* Write to one of the NVR registers. */
|
||||
static void
|
||||
nvr_write(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
struct tm tm;
|
||||
uint8_t old;
|
||||
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
if (addr & 1) {
|
||||
old = nvr->regs[nvr->addr];
|
||||
switch(nvr->addr) {
|
||||
case RTC_REGA:
|
||||
nvr->regs[RTC_REGA] = val;
|
||||
if (val & REGA_RS)
|
||||
rtc_timer_recalc(nvr, 1);
|
||||
else
|
||||
nvr->rtctime = 0x7fffffff;
|
||||
break;
|
||||
|
||||
case RTC_REGB:
|
||||
nvr->regs[RTC_REGB] = val;
|
||||
if (((old^val) & REGB_SET) && (val®B_SET)) {
|
||||
/* According to the datasheet... */
|
||||
nvr->regs[RTC_REGA] &= ~REGA_UIP;
|
||||
nvr->regs[RTC_REGB] &= ~REGB_UIE;
|
||||
}
|
||||
break;
|
||||
|
||||
case RTC_REGC: /* R/O */
|
||||
case RTC_REGD: /* R/O */
|
||||
break;
|
||||
|
||||
default: /* non-RTC registers are just NVRAM */
|
||||
if (nvr->regs[nvr->addr] != val) {
|
||||
nvr->regs[nvr->addr] = val;
|
||||
nvr_dosave = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if ((nvr->addr < RTC_REGA) || (nvr->addr == RTC_CENTURY)) {
|
||||
if ((nvr->addr != 1) && (nvr->addr != 3) && (nvr->addr != 5)) {
|
||||
if ((old != val) && !enable_sync) {
|
||||
/* Update internal clock. */
|
||||
time_get(nvr->regs, &tm);
|
||||
nvr_time_set(&tm);
|
||||
nvr_dosave = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nvr->addr = (val & (nvr->size - 1));
|
||||
if (!(machines[machine].flags & MACHINE_MCA) &&
|
||||
(romset != ROM_IBMPS1_2133))
|
||||
nmi_mask = (~val & 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Read from one of the NVR registers. */
|
||||
static uint8_t
|
||||
nvr_read(uint16_t addr, void *priv)
|
||||
{
|
||||
nvr_t *nvr = (nvr_t *)priv;
|
||||
uint8_t ret;
|
||||
|
||||
cycles -= ISA_CYCLES(8);
|
||||
|
||||
if (addr & 1) switch(nvr->addr) {
|
||||
case RTC_REGA:
|
||||
ret = (nvr->regs[RTC_REGA] & 0x7f) | nvr->upd_stat;
|
||||
break;
|
||||
|
||||
case RTC_REGC:
|
||||
picintc(1<<nvr->irq);
|
||||
ret = nvr->regs[RTC_REGC];
|
||||
nvr->regs[RTC_REGC] = 0x00;
|
||||
break;
|
||||
|
||||
case RTC_REGD:
|
||||
nvr->regs[RTC_REGD] |= REGD_VRT;
|
||||
ret = nvr->regs[RTC_REGD];
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = nvr->regs[nvr->addr];
|
||||
break;
|
||||
} else {
|
||||
ret = nvr->addr;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
|
||||
/* Reset the RTC state to 1980/01/01 00:00. */
|
||||
static void
|
||||
nvr_at_reset(nvr_t *nvr)
|
||||
{
|
||||
memset(nvr->regs, 0x00, RTC_REGS);
|
||||
nvr->regs[RTC_DOM] = 1;
|
||||
nvr->regs[RTC_MONTH] = 1;
|
||||
nvr->regs[RTC_YEAR] = RTC_BCD(80);
|
||||
nvr->regs[RTC_CENTURY] = RTC_BCD(19);
|
||||
}
|
||||
|
||||
|
||||
/* Process after loading from file. */
|
||||
static void
|
||||
nvr_at_start(nvr_t *nvr)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
/* Initialize the internal and chip times. */
|
||||
if (enable_sync) {
|
||||
/* Use the internal clock's time. */
|
||||
nvr_time_get(&tm);
|
||||
time_set(nvr->regs, &tm);
|
||||
} else {
|
||||
/* Set the internal clock from the chip time. */
|
||||
time_get(nvr->regs, &tm);
|
||||
nvr_time_set(&tm);
|
||||
}
|
||||
|
||||
/* Start the RTC. */
|
||||
nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1);
|
||||
nvr->regs[RTC_REGB] = REGB_2412;
|
||||
rtc_timer_recalc(nvr, 0);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nvr_at_init(int irq)
|
||||
{
|
||||
nvr_t *nvr;
|
||||
|
||||
/* Allocate an NVR for this machine. */
|
||||
nvr = (nvr_t *)malloc(sizeof(nvr_t));
|
||||
if (nvr == NULL) return;
|
||||
memset(nvr, 0x00, sizeof(nvr_t));
|
||||
|
||||
/* This is machine specific. */
|
||||
nvr->size = machines[machine].nvrmask + 1;
|
||||
nvr->irq = irq;
|
||||
|
||||
/* Set up any local handlers here. */
|
||||
nvr->reset = nvr_at_reset;
|
||||
nvr->start = nvr_at_start;
|
||||
nvr->tick = tick_timer;
|
||||
|
||||
/* Initialize the generic NVR. */
|
||||
nvr_init(nvr);
|
||||
|
||||
/* Start the timers. */
|
||||
timer_add(update_timer, &nvr->upd_ecount, &nvr->upd_ecount, nvr);
|
||||
timer_add(rtc_timer, &nvr->rtctime, TIMER_ALWAYS_ENABLED, nvr);
|
||||
|
||||
/* Set up the I/O handler for this device. */
|
||||
io_sethandler(0x0070, 2,
|
||||
nvr_read,NULL,NULL, nvr_write,NULL,NULL, nvr);
|
||||
|
||||
nvrp = nvr;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nvr_at_close(void)
|
||||
{
|
||||
if (nvrp == NULL) return;
|
||||
|
||||
if (nvrp->fn != NULL)
|
||||
free(nvrp->fn);
|
||||
|
||||
free(nvrp);
|
||||
|
||||
nvrp = NULL;
|
||||
|
||||
220
src/nvr_ps2.c
220
src/nvr_ps2.c
@@ -1,116 +1,168 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Handling of the PS/2 series CMOS devices.
|
||||
*
|
||||
* Version: @(#)nvr_ps2.c 1.0.4 2018/03/13
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the:
|
||||
*
|
||||
* Free Software Foundation, Inc.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include "86box.h"
|
||||
#include "machine/machine.h"
|
||||
#include "cpu/cpu.h"
|
||||
#include "machine/machine.h"
|
||||
#include "device.h"
|
||||
#include "io.h"
|
||||
#include "mem.h"
|
||||
#include "rom.h"
|
||||
#include "nvr.h"
|
||||
#include "nvr_ps2.h"
|
||||
#include "rom.h"
|
||||
|
||||
|
||||
typedef struct ps2_nvr_t
|
||||
{
|
||||
int addr;
|
||||
uint8_t ram[8192];
|
||||
typedef struct {
|
||||
int addr;
|
||||
|
||||
uint8_t ram[8192];
|
||||
} ps2_nvr_t;
|
||||
|
||||
|
||||
static uint8_t ps2_nvr_read(uint16_t port, void *p)
|
||||
static uint8_t
|
||||
ps2_nvr_read(uint16_t port, void *priv)
|
||||
{
|
||||
ps2_nvr_t *nvr = (ps2_nvr_t *)p;
|
||||
|
||||
switch (port)
|
||||
{
|
||||
case 0x74:
|
||||
return nvr->addr & 0xff;
|
||||
case 0x75:
|
||||
return nvr->addr >> 8;
|
||||
case 0x76:
|
||||
return nvr->ram[nvr->addr];
|
||||
}
|
||||
|
||||
return 0xff;
|
||||
ps2_nvr_t *nvr = (ps2_nvr_t *)priv;
|
||||
uint8_t ret = 0xff;
|
||||
|
||||
switch (port) {
|
||||
case 0x74:
|
||||
ret = nvr->addr & 0xff;
|
||||
break;
|
||||
|
||||
case 0x75:
|
||||
ret = nvr->addr >> 8;
|
||||
break;
|
||||
|
||||
case 0x76:
|
||||
ret = nvr->ram[nvr->addr];
|
||||
break;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static void ps2_nvr_write(uint16_t port, uint8_t val, void *p)
|
||||
|
||||
static void
|
||||
ps2_nvr_write(uint16_t port, uint8_t val, void *priv)
|
||||
{
|
||||
ps2_nvr_t *nvr = (ps2_nvr_t *)p;
|
||||
|
||||
switch (port)
|
||||
{
|
||||
case 0x74:
|
||||
nvr->addr = (nvr->addr & 0x1f00) | val;
|
||||
break;
|
||||
case 0x75:
|
||||
nvr->addr = (nvr->addr & 0xff) | ((val & 0x1f) << 8);
|
||||
break;
|
||||
case 0x76:
|
||||
nvr->ram[nvr->addr] = val;
|
||||
break;
|
||||
}
|
||||
ps2_nvr_t *nvr = (ps2_nvr_t *)priv;
|
||||
|
||||
switch (port) {
|
||||
case 0x74:
|
||||
nvr->addr = (nvr->addr & 0x1f00) | val;
|
||||
break;
|
||||
|
||||
case 0x75:
|
||||
nvr->addr = (nvr->addr & 0xff) | ((val & 0x1f) << 8);
|
||||
break;
|
||||
|
||||
case 0x76:
|
||||
nvr->ram[nvr->addr] = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void *ps2_nvr_init(device_t *info)
|
||||
|
||||
static void *
|
||||
ps2_nvr_init(device_t *info)
|
||||
{
|
||||
ps2_nvr_t *nvr = (ps2_nvr_t *)malloc(sizeof(ps2_nvr_t));
|
||||
FILE *f = NULL;
|
||||
ps2_nvr_t *nvr;
|
||||
FILE *f = NULL;
|
||||
|
||||
memset(nvr, 0, sizeof(ps2_nvr_t));
|
||||
|
||||
io_sethandler(0x0074, 0x0003, ps2_nvr_read, NULL, NULL, ps2_nvr_write, NULL, NULL, nvr);
|
||||
nvr = (ps2_nvr_t *)malloc(sizeof(ps2_nvr_t));
|
||||
memset(nvr, 0x00, sizeof(ps2_nvr_t));
|
||||
|
||||
io_sethandler(0x0074, 3,
|
||||
ps2_nvr_read,NULL,NULL, ps2_nvr_write,NULL,NULL, nvr);
|
||||
|
||||
switch (romset)
|
||||
{
|
||||
case ROM_IBMPS2_M80: f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"rb"); break;
|
||||
#ifdef WALTJE
|
||||
case ROM_IBMPS2_M80_486: f = nvr_fopen(L"ibmps2_m80-486_sec.nvr", L"rb"); break;
|
||||
#endif
|
||||
}
|
||||
if (f)
|
||||
{
|
||||
fread(nvr->ram, 8192, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
memset(nvr->ram, 0xFF, 8192);
|
||||
|
||||
return nvr;
|
||||
switch (romset) {
|
||||
case ROM_IBMPS2_M80:
|
||||
f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"rb");
|
||||
break;
|
||||
}
|
||||
|
||||
memset(nvr->ram, 0xff, 8192);
|
||||
if (f != NULL) {
|
||||
(void)fread(nvr->ram, 8192, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
return(nvr);
|
||||
}
|
||||
|
||||
void ps2_nvr_close(void *p)
|
||||
{
|
||||
ps2_nvr_t *nvr = (ps2_nvr_t *)p;
|
||||
FILE *f = NULL;
|
||||
|
||||
switch (romset)
|
||||
{
|
||||
case ROM_IBMPS2_M80: f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"wb"); break;
|
||||
#ifdef WALTJE
|
||||
case ROM_IBMPS2_M80_486: f = nvr_fopen(L"ibmps2_m80-486_sec.nvr", L"wb"); break;
|
||||
#endif
|
||||
}
|
||||
if (f)
|
||||
{
|
||||
fwrite(nvr->ram, 8192, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
free(nvr);
|
||||
static void
|
||||
ps2_nvr_close(void *priv)
|
||||
{
|
||||
ps2_nvr_t *nvr = (ps2_nvr_t *)priv;
|
||||
FILE *f = NULL;
|
||||
|
||||
switch (romset) {
|
||||
case ROM_IBMPS2_M70_TYPE3:
|
||||
f = nvr_fopen(L"ibmps2_m70_type3_sec.nvr", L"rb");
|
||||
break;
|
||||
case ROM_IBMPS2_M70_TYPE4:
|
||||
f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"rb");
|
||||
break;
|
||||
case ROM_IBMPS2_M80:
|
||||
f = nvr_fopen(L"ibmps2_m80_sec.nvr", L"wb");
|
||||
break;
|
||||
}
|
||||
|
||||
if (f != NULL) {
|
||||
(void)fwrite(nvr->ram, 8192, 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
free(nvr->ram);
|
||||
|
||||
free(nvr);
|
||||
}
|
||||
|
||||
device_t ps2_nvr_device =
|
||||
{
|
||||
"PS/2 NVRRAM",
|
||||
0,
|
||||
0,
|
||||
ps2_nvr_init,
|
||||
ps2_nvr_close,
|
||||
NULL,
|
||||
NULL, NULL, NULL, NULL
|
||||
|
||||
device_t ps2_nvr_device = {
|
||||
"PS/2 Secondary NVRAM",
|
||||
0, 0,
|
||||
ps2_nvr_init, ps2_nvr_close, NULL,
|
||||
NULL, NULL, NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -1 +1,44 @@
|
||||
extern device_t ps2_nvr_device;
|
||||
/*
|
||||
* 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 PS/2 cmos/nvr device.
|
||||
*
|
||||
* Version: @(#)nvr_ps2.h 1.0.1 2018/02/14
|
||||
*
|
||||
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Sarah Walker, <tommowalker@tommowalker.co.uk>
|
||||
*
|
||||
* Copyright 2017,2018 Fred N. van Kempen.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the:
|
||||
*
|
||||
* Free Software Foundation, Inc.
|
||||
* 59 Temple Place - Suite 330
|
||||
* Boston, MA 02111-1307
|
||||
* USA.
|
||||
*/
|
||||
#ifndef EMU_NVRPS2_H
|
||||
# define EMU_NVRPS2_H
|
||||
|
||||
|
||||
extern device_t ps2_nvr_device;
|
||||
|
||||
|
||||
#endif /*EMU_NVRPS2_H*/
|
||||
|
||||
115
src/nvr_tc8521.c
115
src/nvr_tc8521.c
@@ -1,115 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include <wchar.h>
|
||||
#include "86box.h"
|
||||
#include "mem.h"
|
||||
#include "io.h"
|
||||
#include "nvr.h"
|
||||
#include "nvr_tc8521.h"
|
||||
#include "rtc_tc8521.h"
|
||||
#include "pic.h"
|
||||
#include "pit.h"
|
||||
#include "plat.h"
|
||||
#include "rom.h"
|
||||
#include "timer.h"
|
||||
#include "config.h"
|
||||
#include "nmi.h"
|
||||
#include "machine/machine.h"
|
||||
|
||||
int oldromset;
|
||||
int nvrmask=63;
|
||||
uint8_t nvrram[128];
|
||||
int nvraddr;
|
||||
|
||||
int nvr_dosave = 0;
|
||||
|
||||
static int64_t nvr_onesec_time = 0, nvr_onesec_cnt = 0;
|
||||
|
||||
static void tc8521_onesec(void *p)
|
||||
{
|
||||
nvr_onesec_cnt++;
|
||||
if (nvr_onesec_cnt >= 100)
|
||||
{
|
||||
tc8521_tick();
|
||||
nvr_onesec_cnt = 0;
|
||||
}
|
||||
nvr_onesec_time += (int)(10000 * TIMER_USEC);
|
||||
}
|
||||
|
||||
void write_tc8521(uint16_t addr, uint8_t val, void *priv)
|
||||
{
|
||||
uint8_t page = nvrram[0x0D] & 3;
|
||||
|
||||
addr &= 0x0F;
|
||||
if (addr < 0x0D) addr += 16 * page;
|
||||
|
||||
if (addr >= 0x10 && nvrram[addr] != val)
|
||||
nvr_dosave = 1;
|
||||
|
||||
nvrram[addr] = val;
|
||||
}
|
||||
|
||||
|
||||
uint8_t read_tc8521(uint16_t addr, void *priv)
|
||||
{
|
||||
uint8_t page = nvrram[0x0D] & 3;
|
||||
|
||||
addr &= 0x0F;
|
||||
if (addr < 0x0D) addr += 16 * page;
|
||||
|
||||
return nvrram[addr];
|
||||
}
|
||||
|
||||
|
||||
void tc8521_loadnvr()
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
nvrmask=63;
|
||||
oldromset=romset;
|
||||
switch (romset)
|
||||
{
|
||||
case ROM_T1000: f = plat_fopen(nvr_path(L"t1000.nvr"), L"rb"); break;
|
||||
case ROM_T1200: f = plat_fopen(nvr_path(L"t1200.nvr"), L"rb"); break;
|
||||
default: return;
|
||||
}
|
||||
if (!f)
|
||||
{
|
||||
memset(nvrram,0xFF,64);
|
||||
nvrram[0x0E] = 0; /* Test register */
|
||||
if (!enable_sync)
|
||||
{
|
||||
memset(nvrram, 0, 16);
|
||||
}
|
||||
return;
|
||||
}
|
||||
fread(nvrram,64,1,f);
|
||||
if (enable_sync)
|
||||
tc8521_internal_sync(nvrram);
|
||||
else
|
||||
tc8521_internal_set_nvrram(nvrram); /* Update the internal clock state based on the NVR registers. */
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
|
||||
void tc8521_savenvr()
|
||||
{
|
||||
FILE *f;
|
||||
switch (oldromset)
|
||||
{
|
||||
case ROM_T1000: f = plat_fopen(nvr_path(L"t1000.nvr"), L"wb"); break;
|
||||
case ROM_T1200: f = plat_fopen(nvr_path(L"t1200.nvr"), L"wb"); break;
|
||||
default: return;
|
||||
}
|
||||
fwrite(nvrram,64,1,f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void nvr_tc8521_init()
|
||||
{
|
||||
io_sethandler(0x2C0, 0x10, read_tc8521, NULL, NULL, write_tc8521, NULL, NULL, NULL);
|
||||
timer_add(tc8521_onesec, &nvr_onesec_time, TIMER_ALWAYS_ENABLED, NULL);
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
void nvr_tc8521_init();
|
||||
|
||||
extern int enable_sync;
|
||||
|
||||
extern int nvr_dosave;
|
||||
|
||||
void tc8521_loadnvr();
|
||||
void tc8521_savenvr();
|
||||
|
||||
void tc8521_nvr_recalc();
|
||||
|
||||
FILE *nvrfopen(char *fn, char *mode);
|
||||
12
src/pc.c
12
src/pc.c
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Main emulator module where most things are controlled.
|
||||
*
|
||||
* Version: @(#)pc.c 1.0.62 2018/03/06
|
||||
* Version: @(#)pc.c 1.0.64 2018/03/15
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -126,6 +126,7 @@ int cpu_manufacturer = 0, /* (C) cpu manufacturer */
|
||||
cpu_use_dynarec = 0, /* (C) cpu uses/needs Dyna */
|
||||
cpu = 3, /* (C) cpu type */
|
||||
enable_external_fpu = 0; /* (C) enable external FPU */
|
||||
int enable_sync = 0; /* (C) enable time sync */
|
||||
|
||||
|
||||
/* Statistics. */
|
||||
@@ -500,8 +501,6 @@ pc_full_speed(void)
|
||||
setpitclock(14318184.0);
|
||||
}
|
||||
atfullspeed = 1;
|
||||
|
||||
nvr_recalc();
|
||||
}
|
||||
|
||||
|
||||
@@ -512,8 +511,6 @@ pc_speed_changed(void)
|
||||
setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed);
|
||||
else
|
||||
setpitclock(14318184.0);
|
||||
|
||||
nvr_recalc();
|
||||
}
|
||||
|
||||
|
||||
@@ -782,7 +779,6 @@ pc_reset_hard_init(void)
|
||||
/* Reset the general machine support modules. */
|
||||
io_init();
|
||||
// cpu_set();
|
||||
mem_resize();
|
||||
timer_reset();
|
||||
device_init();
|
||||
|
||||
@@ -970,6 +966,10 @@ pc_close(thread_t *ptr)
|
||||
network_close();
|
||||
|
||||
sound_cd_thread_end();
|
||||
|
||||
mem_destroy_pages();
|
||||
|
||||
ide_destroy_buffers();
|
||||
}
|
||||
|
||||
|
||||
|
||||
35
src/rom.c
35
src/rom.c
@@ -13,7 +13,7 @@
|
||||
* - c386sx16 BIOS fails checksum
|
||||
* - the loadfont() calls should be done elsewhere
|
||||
*
|
||||
* Version: @(#)rom.c 1.0.35 2018/03/06
|
||||
* Version: @(#)rom.c 1.0.35 2018/03/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -256,7 +256,7 @@ rom_init(rom_t *rom, wchar_t *fn, uint32_t addr, int sz, int mask, int off, uint
|
||||
addr, sz,
|
||||
rom_read, rom_readw, rom_readl,
|
||||
mem_write_null, mem_write_nullw, mem_write_nulll,
|
||||
rom->rom, flags, rom);
|
||||
rom->rom, flags | MEM_MAPPING_ROM, rom);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -283,7 +283,7 @@ rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int
|
||||
addr, sz,
|
||||
rom_read, rom_readw, rom_readl,
|
||||
mem_write_null, mem_write_nullw, mem_write_nulll,
|
||||
rom->rom, flags, rom);
|
||||
rom->rom, flags | MEM_MAPPING_ROM, rom);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -674,14 +674,11 @@ rom_load_bios(int rom_id)
|
||||
break;
|
||||
|
||||
case ROM_SPC4216P:
|
||||
if (rom_load_linear(
|
||||
L"roms/machines/spc4216p/phoenix.bin",
|
||||
0x000000, 65536, 0, rom)) return(1);
|
||||
if (rom_load_interleaved(
|
||||
if (! rom_load_interleaved(
|
||||
L"roms/machines/spc4216p/7101.u8",
|
||||
L"roms/machines/spc4216p/ac64.u10",
|
||||
0x000000, 65536, 0, rom)) return(1);
|
||||
break;
|
||||
0x000000, 65536, 0, rom)) break;
|
||||
return(1);
|
||||
|
||||
case ROM_KMXC02:
|
||||
if (rom_load_linear(
|
||||
@@ -720,6 +717,22 @@ rom_load_bios(int rom_id)
|
||||
biosmask = 0x1ffff;
|
||||
return(1);
|
||||
|
||||
case ROM_IBMPS2_M70_TYPE3:
|
||||
if (! rom_load_interleaved(
|
||||
L"roms/machines/ibmps2_m70_type3/70-a_even.bin",
|
||||
L"roms/machines/ibmps2_m70_type3/70-a_odd.bin",
|
||||
0x000000, 131072, 0, rom)) break;
|
||||
biosmask = 0x1ffff;
|
||||
return(1);
|
||||
|
||||
case ROM_IBMPS2_M70_TYPE4:
|
||||
if (! rom_load_interleaved(
|
||||
L"roms/machines/ibmps2_m70_type4/70-b_even.bin",
|
||||
L"roms/machines/ibmps2_m70_type4/70-b_odd.bin",
|
||||
0x000000, 131072, 0, rom)) break;
|
||||
biosmask = 0x1ffff;
|
||||
return(1);
|
||||
|
||||
case ROM_DTK486:
|
||||
if (rom_load_linear(
|
||||
L"roms/machines/dtk486/4siw005.bin",
|
||||
@@ -848,14 +861,12 @@ rom_load_bios(int rom_id)
|
||||
biosmask = 0x1ffff;
|
||||
return(1);
|
||||
|
||||
#if defined(DEV_BRANCH) && defined(USE_MRTHOR)
|
||||
case ROM_MRTHOR:
|
||||
if (! rom_load_linear(
|
||||
L"roms/machines/mrthor/mr_atx.bio",
|
||||
0x000000, 131072, 0, rom)) break;
|
||||
biosmask = 0x1ffff;
|
||||
return(1);
|
||||
#endif
|
||||
|
||||
case ROM_ZAPPA:
|
||||
if (! rom_load_linear(
|
||||
@@ -911,7 +922,6 @@ rom_load_bios(int rom_id)
|
||||
if (!rom_load_linear(
|
||||
L"roms/machines/t1000/t1000.rom",
|
||||
0x000000, 32768, 0, rom)) break;
|
||||
memcpy(rom + 0x8000, rom, 0x8000);
|
||||
biosmask = 0x7fff;
|
||||
return(1);
|
||||
|
||||
@@ -920,7 +930,6 @@ rom_load_bios(int rom_id)
|
||||
if (!rom_load_linear(
|
||||
L"roms/machines/t1200/t1200_019e.ic15.bin",
|
||||
0x000000, 32768, 0, rom)) break;
|
||||
memcpy(rom + 0x8000, rom, 0x8000);
|
||||
biosmask = 0x7fff;
|
||||
return(1);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Definitions for the ROM image handler.
|
||||
*
|
||||
* Version: @(#)rom.h 1.0.17 2018/03/06
|
||||
* Version: @(#)rom.h 1.0.16 2018/03/02
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
* Copyright 2018 Fred N. van Kempen.
|
||||
@@ -127,6 +127,9 @@ enum {
|
||||
#endif
|
||||
ROM_IBMPS1_2133,
|
||||
|
||||
ROM_IBMPS2_M70_TYPE3,
|
||||
ROM_IBMPS2_M70_TYPE4,
|
||||
|
||||
#ifdef WALTJE
|
||||
ROM_IBMPS2_M80_486,
|
||||
#endif
|
||||
@@ -147,9 +150,7 @@ enum {
|
||||
ROM_PRESIDENT, /* President Award 430FX PCI/430FX/Award/Unknown SIO */
|
||||
|
||||
ROM_THOR, /* Intel Advanced_ATX/430FX/AMI/NS PC87306 */
|
||||
#if defined(DEV_BRANCH) && defined(USE_MRTHOR)
|
||||
ROM_MRTHOR, /* Intel Advanced_ATX/430FX/MR.BIOS/NS PC87306 */
|
||||
#endif
|
||||
|
||||
ROM_ACERM3A, /* Acer M3A/430HX/Acer/SMC FDC37C932FR */
|
||||
ROM_ACERV35N, /* Acer V35N/430HX/Acer/SMC FDC37C932FR */
|
||||
|
||||
221
src/rtc_tc8521.c
221
src/rtc_tc8521.c
@@ -1,221 +0,0 @@
|
||||
/* Emulation of:
|
||||
Toshiba TC8521 Real Time Clock */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "nvr.h"
|
||||
#include "rtc_tc8521.h"
|
||||
|
||||
#define peek2(a) (nvrram[(a##1)] + 10 * nvrram[(a##10)])
|
||||
|
||||
struct
|
||||
{
|
||||
int sec;
|
||||
int min;
|
||||
int hour;
|
||||
int mday;
|
||||
int mon;
|
||||
int year;
|
||||
} internal_clock;
|
||||
|
||||
/* Table for days in each month */
|
||||
static int rtc_days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
/* Called to determine whether the year is leap or not */
|
||||
static int rtc_is_leap(int org_year)
|
||||
{
|
||||
if (org_year % 400 == 0) return 1;
|
||||
if (org_year % 100 == 0) return 0;
|
||||
if (org_year % 4 == 0) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Called to determine the days in the current month */
|
||||
static int rtc_get_days(int org_month, int org_year)
|
||||
{
|
||||
if (org_month != 2)
|
||||
return rtc_days_in_month[org_month];
|
||||
else
|
||||
return rtc_is_leap(org_year) ? 29 : 28;
|
||||
}
|
||||
|
||||
/* Called when the internal clock gets updated */
|
||||
static void tc8521_recalc()
|
||||
{
|
||||
if (internal_clock.sec == 60)
|
||||
{
|
||||
internal_clock.sec = 0;
|
||||
internal_clock.min++;
|
||||
}
|
||||
if (internal_clock.min == 60)
|
||||
{
|
||||
internal_clock.min = 0;
|
||||
internal_clock.hour++;
|
||||
}
|
||||
if (internal_clock.hour == 24)
|
||||
{
|
||||
internal_clock.hour = 0;
|
||||
internal_clock.mday++;
|
||||
}
|
||||
if (internal_clock.mday == (rtc_get_days(internal_clock.mon, internal_clock.year) + 1))
|
||||
{
|
||||
internal_clock.mday = 1;
|
||||
internal_clock.mon++;
|
||||
}
|
||||
if (internal_clock.mon == 13)
|
||||
{
|
||||
internal_clock.mon = 1;
|
||||
internal_clock.year++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when ticking the second */
|
||||
void tc8521_tick()
|
||||
{
|
||||
internal_clock.sec++;
|
||||
tc8521_recalc();
|
||||
}
|
||||
|
||||
/* Called when modifying the NVR registers */
|
||||
void tc8521_update(uint8_t *nvrram, int reg)
|
||||
{
|
||||
int temp;
|
||||
|
||||
switch(reg)
|
||||
{
|
||||
case TC8521_SECOND1:
|
||||
case TC8521_SECOND10:
|
||||
internal_clock.sec = peek2(TC8521_SECOND);
|
||||
break;
|
||||
case TC8521_MINUTE1:
|
||||
case TC8521_MINUTE10:
|
||||
internal_clock.min = peek2(TC8521_MINUTE);
|
||||
break;
|
||||
case TC8521_HOUR1:
|
||||
case TC8521_HOUR10:
|
||||
temp = peek2(TC8521_HOUR);
|
||||
if (nvrram[TC8521_24HR] & 1)
|
||||
internal_clock.hour = temp;
|
||||
else
|
||||
internal_clock.hour = ((temp & ~0x20) % 12) + ((temp & 0x20) ? 12 : 0);
|
||||
break;
|
||||
case TC8521_DAY1:
|
||||
case TC8521_DAY10:
|
||||
internal_clock.mday = peek2(TC8521_DAY);
|
||||
break;
|
||||
case TC8521_MONTH1:
|
||||
case TC8521_MONTH10:
|
||||
internal_clock.mon = peek2(TC8521_MONTH);
|
||||
break;
|
||||
case TC8521_YEAR1:
|
||||
case TC8521_YEAR10:
|
||||
internal_clock.year = 1980 + peek2(TC8521_YEAR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Called to obtain the current day of the week based on the internal clock */
|
||||
static int time_week_day()
|
||||
{
|
||||
int day_of_month = internal_clock.mday;
|
||||
int month2 = internal_clock.mon;
|
||||
int year2 = internal_clock.year % 100;
|
||||
int century = ((internal_clock.year - year2) / 100) % 4;
|
||||
int sum = day_of_month + month2 + year2 + century;
|
||||
/* (Sum mod 7) gives 0 for Saturday, we need it for Sunday, so +6 for Saturday to get 6 and Sunday 0 */
|
||||
int raw_wd = ((sum + 6) % 7);
|
||||
return raw_wd;
|
||||
}
|
||||
|
||||
/* Called to get time into the internal clock */
|
||||
static void tc8521_internal_get(struct tm *time_var)
|
||||
{
|
||||
time_var->tm_sec = internal_clock.sec;
|
||||
time_var->tm_min = internal_clock.min;
|
||||
time_var->tm_hour = internal_clock.hour;
|
||||
time_var->tm_wday = time_week_day();
|
||||
time_var->tm_mday = internal_clock.mday;
|
||||
time_var->tm_mon = internal_clock.mon - 1;
|
||||
time_var->tm_year = internal_clock.year - 1900;
|
||||
}
|
||||
|
||||
static void tc8521_internal_set(struct tm *time_var)
|
||||
{
|
||||
internal_clock.sec = time_var->tm_sec;
|
||||
internal_clock.min = time_var->tm_min;
|
||||
internal_clock.hour = time_var->tm_hour;
|
||||
internal_clock.mday = time_var->tm_mday;
|
||||
internal_clock.mon = time_var->tm_mon + 1;
|
||||
internal_clock.year = time_var->tm_year + 1900;
|
||||
}
|
||||
|
||||
static void tc8521_set_nvrram(uint8_t *nvrram, struct tm *cur_time_tm)
|
||||
{
|
||||
nvrram[TC8521_SECOND1] = cur_time_tm->tm_sec % 10;
|
||||
nvrram[TC8521_SECOND10] = cur_time_tm->tm_sec / 10;
|
||||
nvrram[TC8521_MINUTE1] = cur_time_tm->tm_min % 10;
|
||||
nvrram[TC8521_MINUTE10] = cur_time_tm->tm_min / 10;
|
||||
if (nvrram[TC8521_24HR] & 1)
|
||||
{
|
||||
nvrram[TC8521_HOUR1] = cur_time_tm->tm_hour % 10;
|
||||
nvrram[TC8521_HOUR10] = cur_time_tm->tm_hour / 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
nvrram[TC8521_HOUR1] = (cur_time_tm->tm_hour % 12) % 10;
|
||||
nvrram[TC8521_HOUR10] = ((cur_time_tm->tm_hour % 12) / 10)
|
||||
| (cur_time_tm->tm_hour >= 12) ? 2 : 0;
|
||||
}
|
||||
nvrram[TC8521_WEEKDAY] = cur_time_tm->tm_wday;
|
||||
nvrram[TC8521_DAY1] = cur_time_tm->tm_mday % 10;
|
||||
nvrram[TC8521_DAY10] = cur_time_tm->tm_mday / 10;
|
||||
nvrram[TC8521_MONTH1] = (cur_time_tm->tm_mon + 1) / 10;
|
||||
nvrram[TC8521_MONTH10] = (cur_time_tm->tm_mon + 1) % 10;
|
||||
nvrram[TC8521_YEAR1] = (cur_time_tm->tm_year - 80) % 10;
|
||||
nvrram[TC8521_YEAR10] = ((cur_time_tm->tm_year - 80) % 100) / 10;
|
||||
}
|
||||
|
||||
|
||||
void tc8521_internal_set_nvrram(uint8_t *nvrram)
|
||||
{
|
||||
/* Load the entire internal clock state from the NVR. */
|
||||
internal_clock.sec = peek2(TC8521_SECOND);
|
||||
internal_clock.min = peek2(TC8521_MINUTE);
|
||||
if (nvrram[TC8521_24HR] & 1)
|
||||
{
|
||||
internal_clock.hour = peek2(TC8521_HOUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
internal_clock.hour = (peek2(TC8521_HOUR) % 12)
|
||||
+ (nvrram[TC8521_HOUR10] & 2) ? 12 : 0;
|
||||
}
|
||||
internal_clock.mday = peek2(TC8521_DAY);
|
||||
internal_clock.mon = peek2(TC8521_MONTH);
|
||||
internal_clock.year = 1980 + peek2(TC8521_YEAR);
|
||||
}
|
||||
|
||||
void tc8521_internal_sync(uint8_t *nvrram)
|
||||
{
|
||||
struct tm *cur_time_tm;
|
||||
time_t cur_time;
|
||||
|
||||
time(&cur_time);
|
||||
cur_time_tm = localtime(&cur_time);
|
||||
|
||||
tc8521_internal_set(cur_time_tm);
|
||||
|
||||
tc8521_set_nvrram(nvrram, cur_time_tm);
|
||||
}
|
||||
|
||||
void tc8521_get(uint8_t *nvrram)
|
||||
{
|
||||
struct tm cur_time_tm;
|
||||
|
||||
tc8521_internal_get(&cur_time_tm);
|
||||
|
||||
tc8521_set_nvrram(nvrram, &cur_time_tm);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
/* The TC8521 is a 4-bit RTC, so each memory location can only hold a single
|
||||
* BCD digit. Hence everything has 'ones' and 'tens' digits. */
|
||||
enum TC8521_ADDR
|
||||
{
|
||||
/* Page 0 registers */
|
||||
TC8521_SECOND1,
|
||||
TC8521_SECOND10,
|
||||
TC8521_MINUTE1,
|
||||
TC8521_MINUTE10,
|
||||
TC8521_HOUR1,
|
||||
TC8521_HOUR10,
|
||||
TC8521_WEEKDAY,
|
||||
TC8521_DAY1,
|
||||
TC8521_DAY10,
|
||||
TC8521_MONTH1,
|
||||
TC8521_MONTH10,
|
||||
TC8521_YEAR1,
|
||||
TC8521_YEAR10,
|
||||
TC8521_PAGE, /* PAGE register */
|
||||
TC8521_TEST, /* TEST register */
|
||||
TC8521_RESET, /* RESET register */
|
||||
/* Page 1 registers */
|
||||
TC8521_24HR = 0x1A,
|
||||
TC8521_LEAPYEAR = 0x1B
|
||||
};
|
||||
|
||||
|
||||
void tc8521_tick();
|
||||
void tc8521_update(uint8_t *nvrram, int reg);
|
||||
void tc8521_get(uint8_t *nvrram);
|
||||
void tc8521_internal_set_nvrram(uint8_t *nvrram);
|
||||
void tc8521_internal_sync(uint8_t *nvrram);
|
||||
@@ -9,7 +9,7 @@
|
||||
* Implementation of the SMC FDC37C932FR and FDC37C935 Super
|
||||
* I/O Chips.
|
||||
*
|
||||
* Version: @(#)sio_fdc37c93x.c 1.0.10 2018/01/16
|
||||
* Version: @(#)sio_fdc37c93x.c 1.0.11 2018/03/14
|
||||
*
|
||||
* Author: Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
@@ -36,7 +36,7 @@ static int fdc37c93x_curreg = 0;
|
||||
static int fdc37c93x_gpio_reg = 0;
|
||||
static uint8_t fdc37c93x_regs[48];
|
||||
static uint8_t fdc37c93x_ld_regs[10][256];
|
||||
static uint8_t fdc37c93x_gpio_base = 0x00EA;
|
||||
static uint16_t fdc37c93x_gpio_base = 0x00EA;
|
||||
static fdc_t *fdc37c93x_fdc;
|
||||
|
||||
static uint8_t tries;
|
||||
@@ -122,12 +122,12 @@ static void fdc37c93x_auxio_handler(void)
|
||||
{
|
||||
uint16_t ld_port = 0;
|
||||
|
||||
uint8_t local_enable = !!fdc37c93x_ld_regs[3][0x30];
|
||||
uint8_t local_enable = !!fdc37c93x_ld_regs[8][0x30];
|
||||
|
||||
io_removehandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL);
|
||||
if (local_enable)
|
||||
{
|
||||
fdc37c93x_gpio_base = ld_port = make_port(3);
|
||||
fdc37c93x_gpio_base = ld_port = make_port(8);
|
||||
/* pclog("fdc37c93x: Setting Auxiliary I/O port to %04X\n", ld_port); */
|
||||
if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF))
|
||||
io_sethandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL);
|
||||
@@ -377,7 +377,7 @@ process_value:
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
/* Serial port 2 */
|
||||
/* Auxiliary I/O */
|
||||
switch(fdc37c93x_curreg)
|
||||
{
|
||||
case 0x30:
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#define HAVE_STDARG_H
|
||||
#include "../86box.h"
|
||||
#include "../device.h"
|
||||
@@ -15,6 +16,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;
|
||||
|
||||
@@ -55,6 +62,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;
|
||||
@@ -490,6 +500,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);
|
||||
@@ -501,6 +512,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);
|
||||
@@ -996,15 +1008,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++;
|
||||
@@ -1012,20 +1069,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)
|
||||
@@ -1043,51 +1144,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)
|
||||
@@ -1095,12 +1180,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()
|
||||
{
|
||||
es1371_t *es1371 = malloc(sizeof(es1371_t));
|
||||
@@ -1111,6 +1232,8 @@ static void *es1371_init()
|
||||
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;
|
||||
}
|
||||
@@ -1128,6 +1251,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);
|
||||
}
|
||||
|
||||
device_t es1371_device =
|
||||
{
|
||||
@@ -1140,6 +1311,6 @@ device_t es1371_device =
|
||||
NULL,
|
||||
es1371_speed_changed,
|
||||
NULL,
|
||||
NULL,
|
||||
es1371_add_status_info,
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* ATI 18800 emulation (VGA Edge-16)
|
||||
*
|
||||
* Version: @(#)vid_ati18800.c 1.0.5 2018/02/07
|
||||
* Version: @(#)vid_ati18800.c 1.0.7 2018/03/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -31,6 +31,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/ati18800/VGA_Wonder_V3-1.02.bin"
|
||||
@@ -149,6 +150,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;
|
||||
@@ -159,6 +193,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(device_t *info)
|
||||
{
|
||||
ati18800_t *ati18800 = malloc(sizeof(ati18800_t));
|
||||
@@ -178,7 +234,7 @@ static void *ati18800_init(device_t *info)
|
||||
};
|
||||
|
||||
svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/
|
||||
NULL,
|
||||
ati18800_recalctimings,
|
||||
ati18800_in, ati18800_out,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* ATI 28800 emulation (VGA Charger and Korean VGA)
|
||||
*
|
||||
* Version: @(#)vid_ati28800.c 1.0.9 2018/03/05
|
||||
* Version: @(#)vid_ati28800.c 1.0.12 2018/03/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -59,7 +59,7 @@ typedef struct ati28800_t
|
||||
uint8_t regs[256];
|
||||
int index;
|
||||
|
||||
uint32_t memory;
|
||||
uint32_t memory;
|
||||
} ati28800_t;
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ int in_get_korean_font_kind_set;
|
||||
int get_korean_font_enabled;
|
||||
int get_korean_font_index;
|
||||
uint16_t get_korean_font_base;
|
||||
extern int dbcs_mode_enabled;
|
||||
int ksc5601_mode_enabled;
|
||||
|
||||
|
||||
static void ati28800_out(uint16_t addr, uint8_t val, void *p)
|
||||
@@ -106,9 +106,14 @@ static void ati28800_out(uint16_t addr, uint8_t val, void *p)
|
||||
case 0xb3:
|
||||
ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1);
|
||||
break;
|
||||
case 0xb6:
|
||||
if((old ^ val) & 0x10) svga_recalctimings(svga);
|
||||
break;
|
||||
case 0xb6:
|
||||
if((old ^ val) & 0x10) svga_recalctimings(svga);
|
||||
break;
|
||||
case 0xb8:
|
||||
if((old ^ val) & 0x40) svga_recalctimings(svga);
|
||||
break;
|
||||
case 0xb9:
|
||||
if((old ^ val) & 2) svga_recalctimings(svga);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -149,7 +154,7 @@ void ati28800k_out(uint16_t addr, uint8_t val, void *p)
|
||||
case 0x1CF:
|
||||
if(ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20))
|
||||
{
|
||||
dbcs_mode_enabled = val & 0x20;
|
||||
ksc5601_mode_enabled = val & 0x20;
|
||||
svga_recalctimings(svga);
|
||||
|
||||
}
|
||||
@@ -241,6 +246,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;
|
||||
@@ -268,7 +306,7 @@ 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;
|
||||
@@ -291,13 +329,44 @@ static void ati28800_recalctimings(svga_t *svga)
|
||||
{
|
||||
ati28800_t *ati28800 = (ati28800_t *)svga->p;
|
||||
|
||||
if (ati28800->regs[0xb6] & 0x10)
|
||||
{
|
||||
switch(((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1) | ((svga->miscout & 0x0C) >> 2))
|
||||
{
|
||||
case 0x00: svga->clock = cpuclock / 42954000.0; break;
|
||||
case 0x01: svga->clock = cpuclock / 48771000.0; break;
|
||||
case 0x03: svga->clock = cpuclock / 36000000.0; break;
|
||||
case 0x04: svga->clock = cpuclock / 50350000.0; break;
|
||||
case 0x05: svga->clock = cpuclock / 56640000.0; break;
|
||||
case 0x07: svga->clock = cpuclock / 44900000.0; break;
|
||||
case 0x08: svga->clock = cpuclock / 30240000.0; break;
|
||||
case 0x09: svga->clock = cpuclock / 32000000.0; break;
|
||||
case 0x0A: svga->clock = cpuclock / 37500000.0; break;
|
||||
case 0x0B: svga->clock = cpuclock / 39000000.0; break;
|
||||
case 0x0C: svga->clock = cpuclock / 40000000.0; break;
|
||||
case 0x0D: svga->clock = cpuclock / 56644000.0; break;
|
||||
case 0x0E: svga->clock = cpuclock / 75000000.0; break;
|
||||
case 0x0F: svga->clock = cpuclock / 65000000.0; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if(ati28800->regs[0xb8] & 0x40) svga->clock *= 2;
|
||||
|
||||
|
||||
if (ati28800->regs[0xb6] & 0x10)
|
||||
{
|
||||
svga->hdisp <<= 1;
|
||||
svga->htotal <<= 1;
|
||||
svga->rowoffset <<= 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(svga->crtc[0x17] & 4)
|
||||
{
|
||||
svga->vtotal <<= 1;
|
||||
svga->dispend <<= 1;
|
||||
svga->vsyncstart <<= 1;
|
||||
svga->split <<= 1;
|
||||
svga->vblankstart <<= 1;
|
||||
}
|
||||
|
||||
if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/
|
||||
{
|
||||
svga->render = svga_render_8bpp_highres;
|
||||
@@ -307,6 +376,16 @@ static void ati28800_recalctimings(svga_t *svga)
|
||||
}
|
||||
}
|
||||
|
||||
void ati28800k_recalctimings(svga_t *svga)
|
||||
{
|
||||
ati28800_recalctimings(svga);
|
||||
|
||||
if (svga->render == svga_render_text_80 && ksc5601_mode_enabled)
|
||||
{
|
||||
svga->render = svga_render_text_80_ksc5601;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
ati28800k_init(device_t *info)
|
||||
{
|
||||
@@ -321,13 +400,13 @@ ati28800k_init(device_t *info)
|
||||
get_korean_font_enabled = 0;
|
||||
get_korean_font_kind = 0;
|
||||
in_get_korean_font_kind_set = 0;
|
||||
dbcs_mode_enabled = 0;
|
||||
ksc5601_mode_enabled = 0;
|
||||
|
||||
rom_init(&ati28800->bios_rom, BIOS_ATIKOR_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL);
|
||||
loadfont(FONT_ATIKOR_PATH, 6);
|
||||
|
||||
svga_init(&ati28800->svga, ati28800, ati28800->memory << 10, /*Memory size, default 512KB*/
|
||||
ati28800_recalctimings,
|
||||
ati28800k_recalctimings,
|
||||
ati28800k_in, ati28800k_out,
|
||||
NULL,
|
||||
NULL);
|
||||
@@ -457,6 +536,17 @@ ati28800_force_redraw(void *priv)
|
||||
ati->svga.fullchange = changeframecount;
|
||||
}
|
||||
|
||||
void ati28800k_add_status_info(char *s, int max_len, void *p)
|
||||
{
|
||||
ati28800_t *ati28800 = (ati28800_t *)p;
|
||||
char temps[128];
|
||||
|
||||
svga_add_status_info(s, max_len, &ati28800->svga);
|
||||
|
||||
sprintf(temps, "Korean SVGA mode enabled : %s\n\n", ksc5601_mode_enabled ? "Yes" : "No");
|
||||
strncat(s, temps, max_len);
|
||||
}
|
||||
|
||||
static void ati28800_add_status_info(char *s, int max_len, void *priv)
|
||||
{
|
||||
ati28800_t *ati = (ati28800_t *)priv;
|
||||
@@ -537,7 +627,7 @@ device_t ati28800k_device =
|
||||
ati28800k_available,
|
||||
ati28800_speed_changed,
|
||||
ati28800_force_redraw,
|
||||
ati28800_add_status_info,
|
||||
ati28800k_add_status_info,
|
||||
ati28800_config
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* ATi Mach64 graphics card emulation.
|
||||
*
|
||||
* Version: @(#)vid_ati_mach64.c 1.0.14 2018/03/10
|
||||
* Version: @(#)vid_ati_mach64.c 1.0.16 2018/03/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -429,6 +429,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);
|
||||
}
|
||||
@@ -1150,8 +1183,6 @@ void mach64_start_line(mach64_t *mach64)
|
||||
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 READ1BPP(addr, dat, width)
|
||||
|
||||
#define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \
|
||||
{ \
|
||||
case 0x0: dest_dat = ~dest_dat; break; \
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Emulation of select Cirrus Logic cards (CL-GD 5428,
|
||||
* CL-GD 5429, 5430, 5434 and 5436 are supported).
|
||||
* CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported).
|
||||
*
|
||||
* Version: @(#)vid_cl_54xx.c 1.0.11 2018/03/08
|
||||
* Version: @(#)vid_cl_54xx.c 1.0.9 2018/03/02
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Barry Rodewald,
|
||||
@@ -40,8 +40,8 @@
|
||||
#include "vid_cl54xx.h"
|
||||
|
||||
#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"
|
||||
@@ -49,6 +49,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
|
||||
@@ -77,9 +78,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
|
||||
@@ -93,6 +98,13 @@
|
||||
#define CIRRUS_BLTMODE_PIXELWIDTH24 0x20
|
||||
#define CIRRUS_BLTMODE_PIXELWIDTH32 0x30
|
||||
|
||||
// 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
|
||||
@@ -134,7 +146,7 @@ typedef struct gd54xx_t
|
||||
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;
|
||||
@@ -199,7 +211,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;
|
||||
@@ -214,22 +226,29 @@ 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;
|
||||
case 0x17:
|
||||
/* svga->seqregs[0x17] = (svga->seqregs[0x17] & 0x38) | (val & 0xc7); */
|
||||
gd543x_recalc_mapping(gd54xx);
|
||||
break;
|
||||
}
|
||||
@@ -394,8 +413,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) {
|
||||
@@ -421,18 +439,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];
|
||||
return gd54xx->vclk_n[svga->seqaddr-0x0b];
|
||||
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
|
||||
@@ -448,8 +479,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];
|
||||
}
|
||||
@@ -473,7 +502,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*/
|
||||
@@ -492,13 +521,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;
|
||||
@@ -523,7 +552,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;
|
||||
@@ -534,12 +563,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;
|
||||
@@ -552,7 +579,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 {
|
||||
@@ -577,7 +604,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 {
|
||||
@@ -602,45 +629,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])
|
||||
@@ -656,7 +723,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;
|
||||
}
|
||||
@@ -666,47 +733,50 @@ gd54xx_recalctimings(svga_t *svga)
|
||||
svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
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];
|
||||
dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80];
|
||||
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 + cursize + x_add] = 0;
|
||||
((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = 0;
|
||||
if (dat[0] & 0x80)
|
||||
((uint32_t *)buffer32->line[displine + y_add])[offset + cursize + x_add] ^= 0xffffff;
|
||||
((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff;
|
||||
}
|
||||
|
||||
|
||||
offset++;
|
||||
dat[0] <<= 1;
|
||||
dat[1] <<= 1;
|
||||
}
|
||||
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;
|
||||
@@ -751,7 +821,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++;
|
||||
}
|
||||
@@ -1123,7 +1193,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);
|
||||
}
|
||||
|
||||
@@ -1143,7 +1213,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;
|
||||
|
||||
@@ -1199,7 +1269,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) {
|
||||
@@ -1286,7 +1356,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);
|
||||
}
|
||||
|
||||
@@ -1320,7 +1390,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:
|
||||
@@ -1394,7 +1464,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:
|
||||
@@ -1520,7 +1590,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);
|
||||
@@ -1620,7 +1690,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;
|
||||
@@ -1659,7 +1729,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;
|
||||
|
||||
@@ -1680,8 +1750,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;
|
||||
@@ -1799,20 +1869,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;
|
||||
@@ -1826,7 +1884,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga)
|
||||
gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr;
|
||||
gd54xx->blt.width_backup = gd54xx->blt.width;
|
||||
gd54xx->blt.height_internal = gd54xx->blt.height;
|
||||
gd54xx->blt.x_count = 0;
|
||||
gd54xx->blt.x_count = 0;
|
||||
if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND))
|
||||
gd54xx->blt.y_count = gd54xx->blt.src_addr & 7;
|
||||
else
|
||||
@@ -1853,7 +1911,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);
|
||||
@@ -1892,19 +1950,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:
|
||||
@@ -1941,9 +1996,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)];
|
||||
@@ -1966,20 +2019,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);
|
||||
@@ -2039,16 +2091,13 @@ 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 & ~7) | gd54xx->blt.y_count] & (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 & ~7) | gd54xx->blt.y_count] & (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:
|
||||
@@ -2074,7 +2123,7 @@ gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga)
|
||||
switch (gd54xx->blt.rop) {
|
||||
case 0x00: dst = 0; break;
|
||||
case 0x05: dst = src & dst; break;
|
||||
case 0x06: /* dst = dst; */ break;
|
||||
case 0x06: dst = dst; break;
|
||||
case 0x09: dst = src & ~dst; break;
|
||||
case 0x0b: dst = ~ dst; break;
|
||||
case 0x0d: dst = src; break;
|
||||
@@ -2106,7 +2155,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++;
|
||||
@@ -2146,7 +2197,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);
|
||||
@@ -2172,16 +2223,9 @@ 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*/
|
||||
|
||||
@@ -2198,10 +2242,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;
|
||||
@@ -2230,8 +2274,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);
|
||||
@@ -2252,21 +2294,20 @@ static void
|
||||
{
|
||||
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:
|
||||
@@ -2292,7 +2333,6 @@ static void
|
||||
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,
|
||||
@@ -2307,23 +2347,6 @@ static void
|
||||
|
||||
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;
|
||||
|
||||
@@ -2334,10 +2357,10 @@ static void
|
||||
|
||||
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;
|
||||
@@ -2349,19 +2372,17 @@ static void
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -2396,7 +2417,7 @@ void
|
||||
gd54xx_close(void *p)
|
||||
{
|
||||
gd54xx_t *gd54xx = (gd54xx_t *)p;
|
||||
|
||||
|
||||
svga_close(&gd54xx->svga);
|
||||
|
||||
free(gd54xx);
|
||||
@@ -2484,6 +2505,20 @@ static device_config_t gd5434_config[] =
|
||||
}
|
||||
};
|
||||
|
||||
device_t gd5426_vlb_device =
|
||||
{
|
||||
"Cirrus Logic CL-GD 5426 (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
|
||||
};
|
||||
|
||||
device_t gd5428_isa_device =
|
||||
{
|
||||
@@ -2493,7 +2528,7 @@ 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,
|
||||
@@ -2508,7 +2543,7 @@ 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,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* Copyright holders: Sarah Walker
|
||||
see COPYING for more details
|
||||
*/
|
||||
extern device_t gd5426_vlb_device;
|
||||
extern device_t gd5428_isa_device;
|
||||
extern device_t gd5428_vlb_device;
|
||||
extern device_t gd5429_isa_device;
|
||||
|
||||
@@ -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.24 2018/03/05
|
||||
* Version: @(#)vid_svga.c 1.0.26 2018/03/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -69,7 +69,7 @@ void svga_out(uint16_t addr, uint8_t val, void *p)
|
||||
switch (addr)
|
||||
{
|
||||
case 0x3C0:
|
||||
case 0x3C1:
|
||||
case 0x3C1:
|
||||
if (!svga->attrff)
|
||||
{
|
||||
svga->attraddr = val & 31;
|
||||
@@ -109,14 +109,9 @@ void svga_out(uint16_t addr, uint8_t val, void *p)
|
||||
case 0x3C2:
|
||||
svga->miscout = val;
|
||||
svga->vidclock = val & 4;
|
||||
if (val & 1)
|
||||
{
|
||||
io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p);
|
||||
}
|
||||
else
|
||||
{
|
||||
io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p);
|
||||
if (!(val & 1))
|
||||
io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p);
|
||||
}
|
||||
svga_recalctimings(svga);
|
||||
break;
|
||||
case 0x3C4:
|
||||
@@ -300,43 +295,11 @@ uint8_t svga_in(uint16_t addr, void *p)
|
||||
svga->attrff = 0;
|
||||
svga->attrff = 0;
|
||||
|
||||
/* old diagnostic code
|
||||
if (svga->cgastat & 0x01)
|
||||
svga->cgastat &= ~0x30;
|
||||
else
|
||||
svga->cgastat ^= 0x30;
|
||||
return svga->cgastat;
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -390,15 +353,6 @@ void svga_recalctimings(svga_t *svga)
|
||||
if (svga->crtc[9] & 0x20) svga->vblankstart |= 0x200;
|
||||
svga->vblankstart++;
|
||||
|
||||
if(svga->crtc[0x17] & 4)
|
||||
{
|
||||
svga->vtotal <<= 1;
|
||||
svga->dispend <<= 1;
|
||||
svga->vsyncstart <<= 1;
|
||||
svga->split <<= 1;
|
||||
svga->vblankstart <<= 1;
|
||||
}
|
||||
|
||||
svga->hdisp = svga->crtc[1];
|
||||
svga->hdisp++;
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* SVGA renderers.
|
||||
*
|
||||
* Version: @(#)vid_svga_render.c 1.0.7 2018/03/05
|
||||
* Version: @(#)vid_svga_render.c 1.0.9 2018/03/15
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -92,9 +92,6 @@ uint32_t shade[5][256] =
|
||||
}
|
||||
};
|
||||
|
||||
int dbcs_mode_enabled = 0;
|
||||
|
||||
|
||||
void svga_render_blank(svga_t *svga)
|
||||
{
|
||||
int x, xx;
|
||||
@@ -208,7 +205,7 @@ void svga_render_text_80(svga_t *svga)
|
||||
uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add];
|
||||
int x, xx;
|
||||
int drawcursor;
|
||||
uint8_t chr, attr, dat, nextchr;
|
||||
uint8_t chr, attr, dat;
|
||||
uint32_t charaddr;
|
||||
int fg, bg;
|
||||
int xinc = (svga->seqregs[1] & 1) ? 8 : 9;
|
||||
@@ -220,83 +217,6 @@ void svga_render_text_80(svga_t *svga)
|
||||
attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask];
|
||||
|
||||
|
||||
if(dbcs_mode_enabled && x + xinc < svga->hdisp && chr & 0x80)
|
||||
{
|
||||
nextchr = svga->vram[((svga->ma + 4) << 1) & svga->vram_display_mask];
|
||||
if(nextchr & 0x80)
|
||||
{
|
||||
if (drawcursor)
|
||||
{
|
||||
bg = svga->pallook[svga->egapal[attr & 15]];
|
||||
fg = svga->pallook[svga->egapal[attr >> 4]];
|
||||
}
|
||||
else
|
||||
{
|
||||
fg = svga->pallook[svga->egapal[attr & 15]];
|
||||
bg = svga->pallook[svga->egapal[attr >> 4]];
|
||||
if (attr & 0x80 && svga->attrregs[0x10] & 8)
|
||||
{
|
||||
bg = svga->pallook[svga->egapal[(attr >> 4) & 7]];
|
||||
if (svga->blink & 16)
|
||||
fg = bg;
|
||||
}
|
||||
}
|
||||
|
||||
dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc];
|
||||
if (svga->seqregs[1] & 1)
|
||||
{
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
|
||||
if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4))
|
||||
p[8] = bg;
|
||||
else
|
||||
p[8] = (dat & 1) ? fg : bg;
|
||||
}
|
||||
|
||||
attr = svga->vram[(((svga->ma + 4) << 1) + 1) & svga->vram_display_mask];
|
||||
if (drawcursor)
|
||||
{
|
||||
bg = svga->pallook[svga->egapal[attr & 15]];
|
||||
fg = svga->pallook[svga->egapal[attr >> 4]];
|
||||
}
|
||||
else
|
||||
{
|
||||
fg = svga->pallook[svga->egapal[attr & 15]];
|
||||
bg = svga->pallook[svga->egapal[attr >> 4]];
|
||||
if (attr & 0x80 && svga->attrregs[0x10] & 8)
|
||||
{
|
||||
bg = svga->pallook[svga->egapal[(attr >> 4) & 7]];
|
||||
if (svga->blink & 16)
|
||||
fg = bg;
|
||||
}
|
||||
}
|
||||
|
||||
dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc + 16];
|
||||
if (svga->seqregs[1] & 1)
|
||||
{
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
p[xx+8] = (dat & (0x80 >> xx)) ? fg : bg;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
p[xx+9] = (dat & (0x80 >> xx)) ? fg : bg;
|
||||
if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4))
|
||||
p[17] = bg;
|
||||
else
|
||||
p[17] = (dat & 1) ? fg : bg;
|
||||
}
|
||||
svga->ma += 8;
|
||||
p += xinc * 2;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (attr & 8) charaddr = svga->charsetb + (chr * 128);
|
||||
else charaddr = svga->charseta + (chr * 128);
|
||||
|
||||
@@ -342,6 +262,127 @@ void svga_render_text_80(svga_t *svga)
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_text_80_ksc5601(svga_t *svga)
|
||||
{
|
||||
int y_add = enable_overscan ? (overscan_y >> 1) : 0;
|
||||
int x_add = enable_overscan ? 8 : 0;
|
||||
|
||||
if (svga->firstline_draw == 2000)
|
||||
svga->firstline_draw = svga->displine;
|
||||
svga->lastline_draw = svga->displine;
|
||||
|
||||
if (svga->fullchange)
|
||||
{
|
||||
uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add];
|
||||
int x, xx;
|
||||
int drawcursor;
|
||||
uint8_t chr, attr, dat, nextchr;
|
||||
uint32_t charaddr;
|
||||
int fg, bg;
|
||||
int xinc = (svga->seqregs[1] & 1) ? 8 : 9;
|
||||
|
||||
for (x = 0; x < svga->hdisp; x += xinc)
|
||||
{
|
||||
drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron);
|
||||
chr = svga->vram[(svga->ma << 1) & svga->vram_display_mask];
|
||||
nextchr = svga->vram[((svga->ma + 4) << 1) & svga->vram_display_mask];
|
||||
attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask];
|
||||
|
||||
|
||||
if (drawcursor)
|
||||
{
|
||||
bg = svga->pallook[svga->egapal[attr & 15]];
|
||||
fg = svga->pallook[svga->egapal[attr >> 4]];
|
||||
}
|
||||
else
|
||||
{
|
||||
fg = svga->pallook[svga->egapal[attr & 15]];
|
||||
bg = svga->pallook[svga->egapal[attr >> 4]];
|
||||
if (attr & 0x80 && svga->attrregs[0x10] & 8)
|
||||
{
|
||||
bg = svga->pallook[svga->egapal[(attr >> 4) & 7]];
|
||||
if (svga->blink & 16)
|
||||
fg = bg;
|
||||
}
|
||||
}
|
||||
|
||||
fg = svga_color_transform(fg);
|
||||
bg = svga_color_transform(bg);
|
||||
|
||||
if(x + xinc < svga->hdisp && (chr & nextchr & 0x80))
|
||||
{
|
||||
dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc];
|
||||
}
|
||||
else
|
||||
{
|
||||
if (attr & 8) charaddr = svga->charsetb + (chr * 128);
|
||||
else charaddr = svga->charseta + (chr * 128);
|
||||
|
||||
dat = svga->vram[charaddr + (svga->sc << 2)];
|
||||
}
|
||||
if (svga->seqregs[1] & 1)
|
||||
{
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
|
||||
if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4))
|
||||
p[8] = bg;
|
||||
else
|
||||
p[8] = (dat & 1) ? fg : bg;
|
||||
}
|
||||
svga->ma += 4;
|
||||
p += xinc;
|
||||
|
||||
if(x + xinc < svga->hdisp && (chr & nextchr & 0x80))
|
||||
{
|
||||
attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask];
|
||||
|
||||
if (drawcursor)
|
||||
{
|
||||
bg = svga->pallook[svga->egapal[attr & 15]];
|
||||
fg = svga->pallook[svga->egapal[attr >> 4]];
|
||||
}
|
||||
else
|
||||
{
|
||||
fg = svga->pallook[svga->egapal[attr & 15]];
|
||||
bg = svga->pallook[svga->egapal[attr >> 4]];
|
||||
if (attr & 0x80 && svga->attrregs[0x10] & 8)
|
||||
{
|
||||
bg = svga->pallook[svga->egapal[(attr >> 4) & 7]];
|
||||
if (svga->blink & 16)
|
||||
fg = bg;
|
||||
}
|
||||
}
|
||||
|
||||
dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)].chr[svga->sc + 16];
|
||||
if (svga->seqregs[1] & 1)
|
||||
{
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (xx = 0; xx < 8; xx++)
|
||||
p[xx] = (dat & (0x80 >> xx)) ? fg : bg;
|
||||
if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4))
|
||||
p[8] = bg;
|
||||
else
|
||||
p[8] = (dat & 1) ? fg : bg;
|
||||
}
|
||||
|
||||
svga->ma += 4;
|
||||
p += xinc;
|
||||
x += xinc;
|
||||
}
|
||||
}
|
||||
svga->ma &= svga->vram_display_mask;
|
||||
}
|
||||
}
|
||||
|
||||
void svga_render_2bpp_lowres(svga_t *svga)
|
||||
{
|
||||
int changed_offset;
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
*
|
||||
* SVGA renderers.
|
||||
*
|
||||
* Version: @(#)vid_svga_render.h 1.0.0 2017/05/30
|
||||
* Version: @(#)vid_svga_render.h 1.0.1 2018/03/12
|
||||
*
|
||||
* Author: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
* Copyright 2008-2017 Sarah Walker.
|
||||
* Copyright 2016-2017 Miran Grca.
|
||||
* Copyright 2008-2018 Sarah Walker.
|
||||
* Copyright 2016-2018 Miran Grca.
|
||||
*/
|
||||
|
||||
extern int firstline_draw, lastline_draw;
|
||||
@@ -29,9 +29,8 @@ extern uint8_t edatlookup[4][4];
|
||||
|
||||
void svga_render_blank(svga_t *svga);
|
||||
void svga_render_text_40(svga_t *svga);
|
||||
void svga_render_text_40_12(svga_t *svga);
|
||||
void svga_render_text_80(svga_t *svga);
|
||||
void svga_render_text_80_12(svga_t *svga);
|
||||
void svga_render_text_80_ksc5601(svga_t *svga);
|
||||
|
||||
void svga_render_2bpp_lowres(svga_t *svga);
|
||||
void svga_render_2bpp_highres(svga_t *svga);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Define all known video cards.
|
||||
*
|
||||
* Version: @(#)vid_table.c 1.0.24 2018/03/03
|
||||
* Version: @(#)vid_table.c 1.0.24 2018/03/15
|
||||
*
|
||||
* Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
* Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
@@ -85,93 +85,94 @@ typedef struct {
|
||||
|
||||
static VIDEO_CARD
|
||||
video_cards[] = {
|
||||
{"None", "none", NULL, GFX_NONE },
|
||||
{"Internal", "internal", NULL, GFX_INTERNAL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device, GFX_MACH64GX_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{"[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device, GFX_ATIKOREANVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{"[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device, GFX_VGA88, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device, GFX_VGACHARGER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{"[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device, GFX_VGAEDGE16, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "None", "none", NULL, GFX_NONE },
|
||||
{ "Internal", "internal", NULL, GFX_INTERNAL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_isa", &mach64gx_isa_device, GFX_MACH64GX_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{"[ISA] ATI Korean VGA (ATI-28800-5)", "ati28800k", &ati28800k_device, GFX_ATIKOREANVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{ "[ISA] ATI VGA-88 (ATI-18800-1)", "ati18800v", &ati18800_vga88_device, GFX_VGA88, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] ATI VGA Charger (ATI-28800-5)", "ati28800", &ati28800_device, GFX_VGACHARGER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{ "[ISA] ATI VGA Edge-16 (ATI-18800-5)", "ati18800", &ati18800_device, GFX_VGAEDGE16, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
#if defined(DEV_BRANCH) && defined(USE_XL24)
|
||||
{"[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device, GFX_VGAWONDERXL24, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{ "[ISA] ATI VGA Wonder XL24 (ATI-28800-6)", "ati28800w", &ati28800_wonderxl24_device,GFX_VGAWONDERXL24, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
#endif
|
||||
{"[ISA] CGA", "cga", &cga_device, GFX_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Chips & Technologies SuperEGA", "superega", &sega_device, GFX_SUPER_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device, GFX_CL_GD5428_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}},
|
||||
{"[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device, GFX_CL_GD5429_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}},
|
||||
{"[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device, GFX_CL_GD5434_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}},
|
||||
{"[ISA] Compaq ATI VGA Wonder XL (ATI-28800-5)", "compaq_ati28800", &compaq_ati28800_device, GFX_VGAWONDERXL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{"[ISA] Compaq CGA", "compaq_cga", &compaq_cga_device, GFX_COMPAQ_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device, GFX_COMPAQ_CGA_2, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Compaq EGA", "compaq_ega", &cpqega_device, GFX_COMPAQ_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] EGA", "ega", &ega_device, GFX_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Hercules", "hercules", &hercules_device, GFX_HERCULES, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Hercules Plus", "hercules_plus", &herculesplus_device, GFX_HERCULESPLUS, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] MDA", "mda", &mda_device, GFX_MDA, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] MDSI Genius", "genius", &genius_device, GFX_GENIUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] OAK OTI-037C", "oti037c", &oti037c_device, GFX_OTI037C, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}},
|
||||
{"[ISA] OAK OTI-067", "oti067", &oti067_device, GFX_OTI067, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}},
|
||||
{"[ISA] OAK OTI-077", "oti077", &oti077_device, GFX_OTI077, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}},
|
||||
{"[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device, GFX_PVGA1A, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device, GFX_WD90C11, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device, GFX_WD90C30, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}},
|
||||
{"[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] CGA", "cga", &cga_device, GFX_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] Chips & Technologies SuperEGA", "superega", &sega_device, GFX_SUPER_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] Cirrus Logic CL-GD 5428", "cl_gd5428_isa", &gd5428_isa_device, GFX_CL_GD5428_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}},
|
||||
{ "[ISA] Cirrus Logic CL-GD 5429", "cl_gd5429_isa", &gd5429_isa_device, GFX_CL_GD5429_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}},
|
||||
{ "[ISA] Cirrus Logic CL-GD 5434", "cl_gd5434_isa", &gd5434_isa_device, GFX_CL_GD5434_ISA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}},
|
||||
{ "[ISA] Compaq ATI VGA Wonder XL (ATI-28800-5)","compaq_ati28800", &compaq_ati28800_device, GFX_VGAWONDERXL, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{ "[ISA] Compaq CGA", "compaq_cga", &compaq_cga_device, GFX_COMPAQ_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] Compaq CGA 2", "compaq_cga_2", &compaq_cga_2_device, GFX_COMPAQ_CGA_2, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] Compaq EGA", "compaq_ega", &cpqega_device, GFX_COMPAQ_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] EGA", "ega", &ega_device, GFX_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] Hercules", "hercules", &hercules_device, GFX_HERCULES, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] Hercules Plus", "hercules_plus", &herculesplus_device, GFX_HERCULESPLUS, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] MDA", "mda", &mda_device, GFX_MDA, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{ "[ISA] MDSI Genius", "genius", &genius_device, GFX_GENIUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] OAK OTI-037C", "oti037c", &oti037c_device, GFX_OTI037C, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}},
|
||||
{"[ISA] OAK OTI-067", "oti067", &oti067_device, GFX_OTI067, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}},
|
||||
{"[ISA] OAK OTI-077", "oti077", &oti077_device, GFX_OTI077, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}},
|
||||
{"[ISA] Paradise PVGA1A", "pvga1a", ¶dise_pvga1a_device, GFX_PVGA1A, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Paradise WD90C11-LR", "wd90c11", ¶dise_wd90c11_device, GFX_WD90C11, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Paradise WD90C30-LR", "wd90c30", ¶dise_wd90c30_device, GFX_WD90C30, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}},
|
||||
{"[ISA] Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
#if defined(DEV_BRANCH) && defined(USE_TI)
|
||||
{"[ISA] TI CF62011 SVGA", "ti_cf62011", &ti_cf62011_device, GFX_TICF62011, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] TI CF62011 SVGA", "ti_cf62011", &ti_cf62011_device, GFX_TICF62011, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
#endif
|
||||
{"[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}},
|
||||
{"[ISA] Tseng ET4000AX", "et4000ax", &et4000_device, GFX_ET4000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{"[ISA] VGA", "vga", &vga_device, GFX_VGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Wyse 700", "wy700", &wy700_device, GFX_WY700, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device, GFX_MACH64GX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}},
|
||||
{"[PCI] ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}},
|
||||
{"[PCI] Cardex Tseng ET4000/w32p", "et4000w32p_pci", &et4000w32p_cardex_pci_device, GFX_ET4000W32_CARDEX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}},
|
||||
{"[PCI] Cirrus Logic CL-GD 5430", "cl_gd5430_pci", &gd5430_pci_device, GFX_CL_GD5430_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[PCI] Cirrus Logic CL-GD 5434", "cl_gd5434_pci", &gd5434_pci_device, GFX_CL_GD5434_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[PCI] Cirrus Logic CL-GD 5436", "cl_gd5436_pci", &gd5436_pci_device, GFX_CL_GD5436_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[ISA] Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}},
|
||||
{"[ISA] Tseng ET4000AX", "et4000ax", &et4000_device, GFX_ET4000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}},
|
||||
{"[ISA] VGA", "vga", &vga_device, GFX_VGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[ISA] Wyse 700", "wy700", &wy700_device, GFX_WY700, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}},
|
||||
{"[PCI] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_pci", &mach64gx_pci_device, GFX_MACH64GX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}},
|
||||
{"[PCI] ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}},
|
||||
{"[PCI] Cardex Tseng ET4000/w32p", "et4000w32p_pci", &et4000w32p_cardex_pci_device,GFX_ET4000W32_CARDEX_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 4, 4, 4, 10, 10, 10}},
|
||||
{"[PCI] Cirrus Logic CL-GD 5430", "cl_gd5430_pci", &gd5430_pci_device, GFX_CL_GD5430_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[PCI] Cirrus Logic CL-GD 5434", "cl_gd5434_pci", &gd5434_pci_device, GFX_CL_GD5434_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[PCI] Cirrus Logic CL-GD 5436", "cl_gd5436_pci", &gd5436_pci_device, GFX_CL_GD5436_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
#if defined(DEV_BRANCH) && defined(USE_STEALTH32)
|
||||
{"[PCI] Diamond Stealth 32 (Tseng ET4000/w32p)","stealth32_pci", &et4000w32p_pci_device, GFX_ET4000W32_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}},
|
||||
{"[PCI] Diamond Stealth 32 (Tseng ET4000/w32p)","stealth32_pci", &et4000w32p_pci_device, GFX_ET4000W32_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}},
|
||||
#endif
|
||||
{"[PCI] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_pci",&s3_virge_pci_device, GFX_VIRGE_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[PCI] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_pci",&s3_virge_988_pci_device, GFX_VIRGEVX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}},
|
||||
{"[PCI] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_pci", &s3_diamond_stealth64_pci_device, GFX_STEALTH64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}},
|
||||
{"[PCI] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_pci",&s3_virge_pci_device, GFX_VIRGE_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[PCI] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_pci",&s3_virge_988_pci_device, GFX_VIRGEVX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}},
|
||||
{"[PCI] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_pci", &s3_diamond_stealth64_pci_device,GFX_STEALTH64_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 2, 2, 4, 26, 26, 42}},
|
||||
#if defined(DEV_BRANCH) && defined(USE_RIVA)
|
||||
{"[PCI] nVidia RIVA 128", "riva128", &riva128_device, GFX_RIVA128, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}},
|
||||
{"[PCI] nVidia RIVA TNT", "rivatnt", &rivatnt_device, GFX_RIVATNT, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}},
|
||||
{"[PCI] nVidia RIVA TNT2", "rivatnt2", &rivatnt2_device, GFX_RIVATNT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}},
|
||||
{"[PCI] nVidia RIVA 128", "riva128", &riva128_device, GFX_RIVA128, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}},
|
||||
{"[PCI] nVidia RIVA TNT", "rivatnt", &rivatnt_device, GFX_RIVATNT, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}},
|
||||
{"[PCI] nVidia RIVA TNT2", "rivatnt2", &rivatnt2_device, GFX_RIVATNT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 24, 24, 36}},
|
||||
#endif
|
||||
{"[PCI] Number Nine 9FX (S3 Trio64)", "n9_9fx_pci", &s3_9fx_pci_device, GFX_N9_9FX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[PCI] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_pci", &s3_bahamas64_pci_device, GFX_BAHAMAS64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}},
|
||||
{"[PCI] Phoenix S3 Vision864", "px_vision864_pci", &s3_phoenix_vision864_pci_device, GFX_PHOENIX_VISION864_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}},
|
||||
{"[PCI] Phoenix S3 Trio32", "px_trio32_pci", &s3_phoenix_trio32_pci_device, GFX_PHOENIX_TRIO32_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[PCI] Phoenix S3 Trio64", "px_trio64_pci", &s3_phoenix_trio64_pci_device, GFX_PHOENIX_TRIO64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[PCI] S3 ViRGE/DX", "virge375_pci", &s3_virge_375_pci_device, GFX_VIRGEDX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[PCI] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_pci",&s3_virge_375_4_pci_device, GFX_VIRGEDX4_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[PCI] Trident TGUI9440", "tgui9440_pci", &tgui9440_pci_device, GFX_TGUI9440_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}},
|
||||
{"[VLB] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_vlb", &mach64gx_vlb_device, GFX_MACH64GX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}},
|
||||
{"[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device, GFX_ET4000W32_CARDEX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}},
|
||||
{"[VLB] Cirrus Logic CL-GD 5429", "cl_gd5429_vlb", &gd5429_vlb_device, GFX_CL_GD5429_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[VLB] Cirrus Logic CL-GD 5434", "cl_gd5434_vlb", &gd5434_vlb_device, GFX_CL_GD5434_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[PCI] Number Nine 9FX (S3 Trio64)", "n9_9fx_pci", &s3_9fx_pci_device, GFX_N9_9FX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[PCI] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_pci", &s3_bahamas64_pci_device, GFX_BAHAMAS64_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}},
|
||||
{"[PCI] Phoenix S3 Vision864", "px_vision864_pci", &s3_phoenix_vision864_pci_device,GFX_PHOENIX_VISION864_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 4, 4, 5, 20, 20, 35}},
|
||||
{"[PCI] Phoenix S3 Trio32", "px_trio32_pci", &s3_phoenix_trio32_pci_device,GFX_PHOENIX_TRIO32_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[PCI] Phoenix S3 Trio64", "px_trio64_pci", &s3_phoenix_trio64_pci_device,GFX_PHOENIX_TRIO64_PCI,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[PCI] S3 ViRGE/DX", "virge375_pci", &s3_virge_375_pci_device, GFX_VIRGEDX_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[PCI] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_pci",&s3_virge_375_4_pci_device,GFX_VIRGEDX4_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[PCI] Trident TGUI9440", "tgui9440_pci", &tgui9440_pci_device, GFX_TGUI9440_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}},
|
||||
{"[VLB] ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx_vlb", &mach64gx_vlb_device, GFX_MACH64GX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}},
|
||||
{"[VLB] Cardex Tseng ET4000/w32p", "et4000w32p_vlb", &et4000w32p_cardex_vlb_device,GFX_ET4000W32_CARDEX_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 4, 4, 4, 10, 10, 10}},
|
||||
{"[VLB] Cirrus Logic CL-GD 5428", "cl_gd5428_vlb", &gd5428_vlb_device, GFX_CL_GD5428_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[VLB] Cirrus Logic CL-GD 5429", "cl_gd5429_vlb", &gd5429_vlb_device, GFX_CL_GD5429_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[VLB] Cirrus Logic CL-GD 5434", "cl_gd5434_vlb", &gd5434_vlb_device, GFX_CL_GD5434_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, GFX_ET4000W32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}},
|
||||
{"[VLB] Diamond Stealth 32 (Tseng ET4000/w32p)","stealth32_vlb", &et4000w32p_vlb_device, GFX_ET4000W32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}},
|
||||
#endif
|
||||
{"[VLB] Diamond SpeedStar PRO (CL-GD5428)", "cl_gd5428_vlb", &gd5428_vlb_device, GFX_CL_GD5428_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, GFX_CL_GD5430_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[VLB] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_vlb",&s3_virge_vlb_device, GFX_VIRGE_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[VLB] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_vlb",&s3_virge_988_vlb_device, GFX_VIRGEVX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}},
|
||||
{"[VLB] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_vlb", &s3_diamond_stealth64_vlb_device, GFX_STEALTH64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}},
|
||||
{"[VLB] Number Nine 9FX (S3 Trio64)", "n9_9fx_vlb", &s3_9fx_vlb_device, GFX_N9_9FX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[VLB] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_vlb", &s3_bahamas64_vlb_device, GFX_BAHAMAS64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}},
|
||||
{"[VLB] Phoenix S3 Vision864", "px_vision864_vlb", &s3_phoenix_vision864_vlb_device, GFX_PHOENIX_VISION864_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}},
|
||||
{"[VLB] Phoenix S3 Trio32", "px_trio32_vlb", &s3_phoenix_trio32_vlb_device, GFX_PHOENIX_TRIO32_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[VLB] Phoenix S3 Trio64", "px_trio64_vlb", &s3_phoenix_trio64_vlb_device, GFX_PHOENIX_TRIO64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[VLB] S3 ViRGE/DX", "virge375_vlb", &s3_virge_375_vlb_device, GFX_VIRGEDX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[VLB] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_vlb",&s3_virge_375_4_vlb_device, GFX_VIRGEDX4_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[VLB] Trident TGUI9400CXi", "tgui9400cxi_vlb", &tgui9400cxi_device, GFX_TGUI9400CXI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}},
|
||||
{"[VLB] Trident TGUI9440", "tgui9440_vlb", &tgui9440_vlb_device, GFX_TGUI9440_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}},
|
||||
{"", "", NULL, -1 }
|
||||
{"[VLB] Diamond SpeedStar PRO (CL-GD5426)", "cl_gd5426_vlb", &gd5426_vlb_device, GFX_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, GFX_CL_GD5430_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}},
|
||||
{"[VLB] Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000_vlb",&s3_virge_vlb_device, GFX_VIRGE_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[VLB] Diamond Stealth 3D 3000 (S3 ViRGE/VX)", "stealth3d_3000_vlb",&s3_virge_988_vlb_device, GFX_VIRGEVX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 4, 26, 26, 42}},
|
||||
{"[VLB] Diamond Stealth 64 DRAM (S3 Trio64)", "stealth64d_vlb", &s3_diamond_stealth64_vlb_device,GFX_STEALTH64_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 2, 2, 4, 26, 26, 42}},
|
||||
{"[VLB] Number Nine 9FX (S3 Trio64)", "n9_9fx_vlb", &s3_9fx_vlb_device, GFX_N9_9FX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[VLB] Paradise Bahamas 64 (S3 Vision864)", "bahamas64_vlb", &s3_bahamas64_vlb_device, GFX_BAHAMAS64_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}},
|
||||
{"[VLB] Phoenix S3 Vision864", "px_vision864_vlb", &s3_phoenix_vision864_vlb_device,GFX_PHOENIX_VISION864_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 4, 4, 5, 20, 20, 35}},
|
||||
{"[VLB] Phoenix S3 Trio32", "px_trio32_vlb", &s3_phoenix_trio32_vlb_device,GFX_PHOENIX_TRIO32_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[VLB] Phoenix S3 Trio64", "px_trio64_vlb", &s3_phoenix_trio64_vlb_device,GFX_PHOENIX_TRIO64_VLB,VIDEO_FLAG_TYPE_SPECIAL,{VIDEO_BUS, 3, 2, 4, 25, 25, 40}},
|
||||
{"[VLB] S3 ViRGE/DX", "virge375_vlb", &s3_virge_375_vlb_device, GFX_VIRGEDX_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[VLB] S3 ViRGE/DX (VBE 2.0)", "virge375_vbe20_vlb",&s3_virge_375_4_vlb_device,GFX_VIRGEDX4_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}},
|
||||
{"[VLB] Trident TGUI9400CXi", "tgui9400cxi_vlb", &tgui9400cxi_device, GFX_TGUI9400CXI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}},
|
||||
{"[VLB] Trident TGUI9440", "tgui9440_vlb", &tgui9440_vlb_device, GFX_TGUI9440_VLB, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}},
|
||||
{"", "", NULL, -1 }
|
||||
};
|
||||
|
||||
|
||||
@@ -189,6 +190,11 @@ video_reset(int card)
|
||||
if ((card == GFX_NONE) || \
|
||||
(card == GFX_INTERNAL) || machines[machine].fixed_gfxcard) return;
|
||||
|
||||
if (fontdatksc5601) {
|
||||
free(fontdatksc5601);
|
||||
fontdatksc5601 = NULL;
|
||||
}
|
||||
|
||||
pclog("VIDEO: initializing '%s'\n", video_cards[video_old_to_new(card)].name);
|
||||
/* Initialize the video card. */
|
||||
device_add(video_cards[video_old_to_new(card)].device);
|
||||
@@ -317,6 +323,8 @@ int video_is_mda(void)
|
||||
case ROM_IBMPS2_M30_286:
|
||||
case ROM_IBMPS2_M50:
|
||||
case ROM_IBMPS2_M55SX:
|
||||
case ROM_IBMPS2_M70_TYPE3:
|
||||
case ROM_IBMPS2_M70_TYPE4:
|
||||
case ROM_IBMPS2_M80:
|
||||
case ROM_IBMPS1_2121:
|
||||
case ROM_T3100E:
|
||||
@@ -348,6 +356,8 @@ int video_is_cga(void)
|
||||
case ROM_IBMPS2_M30_286:
|
||||
case ROM_IBMPS2_M50:
|
||||
case ROM_IBMPS2_M55SX:
|
||||
case ROM_IBMPS2_M70_TYPE3:
|
||||
case ROM_IBMPS2_M70_TYPE4:
|
||||
case ROM_IBMPS2_M80:
|
||||
case ROM_IBMPS1_2121:
|
||||
return 0;
|
||||
@@ -378,6 +388,8 @@ int video_is_ega_vga(void)
|
||||
case ROM_IBMPS2_M30_286:
|
||||
case ROM_IBMPS2_M50:
|
||||
case ROM_IBMPS2_M55SX:
|
||||
case ROM_IBMPS2_M70_TYPE3:
|
||||
case ROM_IBMPS2_M70_TYPE4:
|
||||
case ROM_IBMPS2_M80:
|
||||
case ROM_IBMPS1_2121:
|
||||
return 1;
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
* W = 3 bus clocks
|
||||
* L = 4 bus clocks
|
||||
*
|
||||
* Version: @(#)video.c 1.0.18 2018/03/02
|
||||
* Version: @(#)video.c 1.0.19 2018/03/15
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -79,7 +79,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;
|
||||
@@ -656,6 +656,11 @@ video_close(void)
|
||||
|
||||
destroy_bitmap(buffer);
|
||||
destroy_bitmap(buffer32);
|
||||
|
||||
if (fontdatksc5601) {
|
||||
free(fontdatksc5601);
|
||||
fontdatksc5601 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -765,11 +770,14 @@ loadfont(wchar_t *s, int format)
|
||||
break;
|
||||
|
||||
case 6: /* Korean KSC-5601 */
|
||||
if (!fontdatksc5601)
|
||||
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;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Definitions for the video controller module.
|
||||
*
|
||||
* Version: @(#)video.h 1.0.22 2018/03/02
|
||||
* Version: @(#)video.h 1.0.23 2018/03/15
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -76,11 +76,12 @@ enum {
|
||||
GFX_MACH64VT2, /* ATI Mach64 VT2 */
|
||||
GFX_CL_GD5424_ISA, /* Cirrus Logic CL-GD 5424 ISA */
|
||||
GFX_CL_GD5424_VLB, /* Cirrus Logic CL-GD 5424 VLB */
|
||||
GFX_CL_GD5426_VLB, /* Diamond SpeedStar PRO (Cirrus Logic CL-GD 5426) VLB */
|
||||
GFX_CL_GD5428_ISA, /* Cirrus Logic CL-GD 5428 ISA */
|
||||
GFX_CL_GD5428_VLB, /* Diamond SpeedStar PRO (Cirrus Logic CL-GD 5428) VLB */
|
||||
GFX_CL_GD5428_VLB, /* Cirrus Logic CL-GD 5428 VLB */
|
||||
GFX_CL_GD5429_ISA, /* Cirrus Logic CL-GD 5429 ISA */
|
||||
GFX_CL_GD5429_VLB, /* Cirrus Logic CL-GD 5429 VLB */
|
||||
GFX_CL_GD5430_VLB, /* Diamond SpeedStar PRO SE (Cirrus Logic CL-GD 5430) PCI */
|
||||
GFX_CL_GD5430_VLB, /* Diamond SpeedStar PRO SE (Cirrus Logic CL-GD 5430) VLB */
|
||||
GFX_CL_GD5430_PCI, /* Cirrus Logic CL-GD 5430 PCI */
|
||||
GFX_CL_GD5434_ISA, /* Cirrus Logic CL-GD 5434 ISA */
|
||||
GFX_CL_GD5434_VLB, /* Cirrus Logic CL-GD 5434 VLB */
|
||||
@@ -150,6 +151,10 @@ typedef struct {
|
||||
uint8_t r, g, b;
|
||||
} rgb_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t chr[32];
|
||||
} dbcs_font_t;
|
||||
|
||||
typedef rgb_t PALETTE[256];
|
||||
|
||||
|
||||
@@ -170,7 +175,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;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#
|
||||
# Makefile for Win32 (MinGW32) environment.
|
||||
#
|
||||
# Version: @(#)Makefile.mingw 1.0.110 2018/03/07
|
||||
# Version: @(#)Makefile.mingw 1.0.112 2018/03/16
|
||||
#
|
||||
# Authors: Miran Grca, <mgrca8@gmail.com>
|
||||
# Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
@@ -292,7 +292,8 @@ ifneq ($(WX), n)
|
||||
LIBS += $(WX_LIBS)
|
||||
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
|
||||
@@ -415,8 +416,7 @@ CFLAGS := $(CFLAGS)
|
||||
#########################################################################
|
||||
MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \
|
||||
pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \
|
||||
device.o nvr.o nvr_tc8521.o rtc_tc8521.o nvr_at.o \
|
||||
nvr_ps2.o $(VNCOBJ) $(RDPOBJ)
|
||||
device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ)
|
||||
|
||||
INTELOBJ := intel.o \
|
||||
intel_flash.o \
|
||||
@@ -429,7 +429,8 @@ CPUOBJ := cpu.o cpu_table.o \
|
||||
|
||||
MCHOBJ := machine.o machine_table.o \
|
||||
m_xt.o m_xt_compaq.o \
|
||||
m_xt_t1000.o m_xt_xi8088.o \
|
||||
m_xt_t1000.o m_xt_t1000_vid.o \
|
||||
m_xt_xi8088.o \
|
||||
m_pcjr.o \
|
||||
m_amstrad.o \
|
||||
m_europc.o m_europc_hdc.o \
|
||||
@@ -437,7 +438,7 @@ MCHOBJ := machine.o machine_table.o \
|
||||
m_at.o \
|
||||
m_at_ali1429.o m_at_commodore.o \
|
||||
m_at_neat.o m_at_headland.o \
|
||||
m_at_t3100e.o \
|
||||
m_at_t3100e.o m_at_t3100e_vid.o \
|
||||
m_ps1.o \
|
||||
m_ps2_isa.o m_ps2_mca.o \
|
||||
m_at_opti495.o m_at_scat.o \
|
||||
@@ -526,7 +527,6 @@ VIDOBJ := video.o \
|
||||
vid_hercules.o vid_herculesplus.o vid_incolor.o \
|
||||
vid_colorplus.o \
|
||||
vid_genius.o \
|
||||
vid_t1000.o vid_t3100e.o \
|
||||
vid_wy700.o \
|
||||
vid_ega.o vid_ega_render.o \
|
||||
vid_svga.o vid_svga_render.o \
|
||||
@@ -568,15 +568,15 @@ LIBS := -mwindows \
|
||||
-lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 \
|
||||
-lcomctl32 -lwinmm
|
||||
ifeq ($(VNC), y)
|
||||
LIBS += $(VNCLIB) -lws2_32 -lz
|
||||
LIBS += $(VNCLIB) -lws2_32
|
||||
endif
|
||||
ifeq ($(RDP), y)
|
||||
LIBS += $(RDPLIB)
|
||||
endif
|
||||
ifneq ($(WX), n)
|
||||
LIBS += $(WX_LIBS) -lz -lm
|
||||
LIBS += $(WX_LIBS) -lm
|
||||
endif
|
||||
LIBS += -lkernel32 -lwsock32 -liphlpapi -lpsapi
|
||||
LIBS += -lpng -lz -lkernel32 -lwsock32 -liphlpapi -lpsapi
|
||||
LIBS += -lpthread -static -lstdc++ -lgcc
|
||||
ifneq ($(X64), y)
|
||||
LIBS += -Wl,--large-address-aware
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* Platform main support module for Windows.
|
||||
*
|
||||
* Version: @(#)win.c 1.0.45 2018/01/23
|
||||
* Version: @(#)win.c 1.0.46 2018/03/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -770,32 +770,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
|
||||
|
||||
@@ -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.12 2018/02/25
|
||||
* Version: @(#)cdrom_ioctl.c 1.0.13 2018/03/15
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -98,9 +98,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;
|
||||
@@ -114,15 +114,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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.5 2018/01/15
|
||||
* Version: @(#)win_ddraw.cpp 1.0.6 2018/03/16
|
||||
*
|
||||
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
|
||||
* Miran Grca, <mgrca8@gmail.com>
|
||||
@@ -27,13 +27,16 @@
|
||||
#define BITMAP WINDOWS_BITMAP
|
||||
#include <windows.h>
|
||||
#undef BITMAP
|
||||
|
||||
#define PNG_DEBUG 0
|
||||
#include <png.h>
|
||||
|
||||
#include "../86box.h"
|
||||
#include "../device.h"
|
||||
#include "../video/video.h"
|
||||
#include "../plat.h"
|
||||
#include "../ui.h"
|
||||
#include "win_ddraw.h"
|
||||
#include "win_png.h"
|
||||
#include "win.h"
|
||||
|
||||
|
||||
@@ -49,6 +52,9 @@ static HBITMAP hbitmap;
|
||||
static int ddraw_w, ddraw_h,
|
||||
xs, ys, ys2;
|
||||
|
||||
static png_structp png_ptr;
|
||||
static png_infop info_ptr;
|
||||
|
||||
|
||||
static void
|
||||
CopySurface(IDirectDrawSurface4 *pDDSurface)
|
||||
@@ -71,6 +77,24 @@ CopySurface(IDirectDrawSurface4 *pDDSurface)
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
DoubleLines(uint8_t *dst, uint8_t *src)
|
||||
{
|
||||
@@ -84,69 +108,112 @@ DoubleLines(uint8_t *dst, uint8_t *src)
|
||||
|
||||
|
||||
static void
|
||||
SaveBitmap(wchar_t *szFilename, HBITMAP hBitmap)
|
||||
SavePNG(wchar_t *szFilename, HBITMAP hBitmap)
|
||||
{
|
||||
static WCHAR szMessage[512];
|
||||
BITMAPFILEHEADER bmpFileHeader;
|
||||
BITMAPINFO bmpInfo;
|
||||
HDC hdc;
|
||||
FILE *fp = NULL;
|
||||
LPVOID pBuf = NULL;
|
||||
LPVOID pBuf2 = NULL;
|
||||
png_bytep *b_rgb = NULL;
|
||||
int i;
|
||||
|
||||
do {
|
||||
hdc = GetDC(NULL);
|
||||
/* create file */
|
||||
FILE *fp = plat_fopen(szFilename, (wchar_t *) L"wb");
|
||||
if (!fp) {
|
||||
pclog("[SavePNG] File %ls could not be opened for writing", szFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
ZeroMemory(&bmpInfo, sizeof(BITMAPINFO));
|
||||
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
/* initialize stuff */
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
|
||||
GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS);
|
||||
if (!png_ptr) {
|
||||
pclog("[SavePNG] png_create_write_struct failed");
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bmpInfo.bmiHeader.biSizeImage <= 0)
|
||||
bmpInfo.bmiHeader.biSizeImage =
|
||||
bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8;
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (!info_ptr) {
|
||||
pclog("[SavePNG] png_create_info_struct failed");
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) {
|
||||
// pclog("ERROR: Unable to Allocate Bitmap Memory");
|
||||
break;
|
||||
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) {
|
||||
pclog("[SavePNG] Unable to Allocate Bitmap Memory");
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ys2 <= 250) {
|
||||
bmpInfo.bmiHeader.biSizeImage <<= 1;
|
||||
|
||||
if ((pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) {
|
||||
pclog("[SavePNG] Unable to Allocate Secondary Bitmap Memory");
|
||||
free(pBuf);
|
||||
fclose(fp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ys2 <= 250)
|
||||
pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage * 2);
|
||||
bmpInfo.bmiHeader.biHeight <<= 1;
|
||||
}
|
||||
|
||||
bmpInfo.bmiHeader.biCompression = BI_RGB;
|
||||
pclog("save png w=%i h=%i\n", bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight);
|
||||
|
||||
GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS);
|
||||
bmpInfo.bmiHeader.biCompression = BI_RGB;
|
||||
|
||||
if ((fp = _wfopen(szFilename, L"wb")) == NULL) {
|
||||
_swprintf(szMessage,
|
||||
plat_get_string(IDS_2088), szFilename);
|
||||
ui_msgbox(MBX_ERROR, szMessage);
|
||||
break;
|
||||
}
|
||||
GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS);
|
||||
|
||||
bmpFileHeader.bfReserved1 = 0;
|
||||
bmpFileHeader.bfReserved2 = 0;
|
||||
if (pBuf2) {
|
||||
bmpInfo.bmiHeader.biSizeImage <<= 1;
|
||||
bmpInfo.bmiHeader.biHeight <<= 1;
|
||||
}
|
||||
bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage;
|
||||
bmpFileHeader.bfType=0x4D42;
|
||||
bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER);
|
||||
png_set_IHDR(png_ptr, info_ptr, bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight,
|
||||
8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE,
|
||||
PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
|
||||
|
||||
(void)fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp);
|
||||
(void)fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp);
|
||||
if (pBuf2) {
|
||||
DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf);
|
||||
(void)fwrite(pBuf2,bmpInfo.bmiHeader.biSizeImage,1,fp);
|
||||
} else {
|
||||
(void)fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp);
|
||||
}
|
||||
} while(false);
|
||||
if ((b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * bmpInfo.bmiHeader.biHeight)) == NULL) {
|
||||
pclog("[SavePNG] Unable to Allocate RGB Bitmap Memory");
|
||||
free(pBuf2);
|
||||
free(pBuf);
|
||||
fclose(fp);
|
||||
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, info_ptr);
|
||||
|
||||
png_write_image(png_ptr, b_rgb);
|
||||
|
||||
png_write_end(png_ptr, NULL);
|
||||
|
||||
/* cleanup heap allocation */
|
||||
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 (pBuf2) free(pBuf2);
|
||||
|
||||
if (pBuf) free(pBuf);
|
||||
@@ -425,7 +492,7 @@ ddraw_take_screenshot(wchar_t *fn)
|
||||
|
||||
CopySurface(lpdds_back2);
|
||||
|
||||
SaveBitmap(fn, hbitmap);
|
||||
SavePNG(fn, hbitmap);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,508 +0,0 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Simple PNG image file format handler.
|
||||
*
|
||||
* Adapted for use with 86Box. 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 in 86Box.
|
||||
*
|
||||
* 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.1 2017/11/11
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "../86Box.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<buflen; i++)
|
||||
crc = crc_table[(crc ^ *bufp++) & 0xff] ^ (crc >> 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; i<buflen; i++) {
|
||||
s1 = ((uint32_t)s1 + bufp[i]) % 65521;
|
||||
s2 = ((uint32_t)s2 + s1) % 65521;
|
||||
}
|
||||
|
||||
return((uint32_t)s2 << 16 | s1);
|
||||
}
|
||||
|
||||
|
||||
/* Finish the PNG file by writing the IEND record. */
|
||||
static int
|
||||
png_wriend(png_t *png)
|
||||
{
|
||||
uint8_t buff[12];
|
||||
int i = 0;
|
||||
|
||||
/* Create the IEND chunk. */
|
||||
png_putlong(&buff[i], 0, &i);
|
||||
memcpy(&buff[i], "IEND", 4); i += 4;
|
||||
png_putlong(&buff[i], 0xae426082, &i);
|
||||
if (fwrite(buff, 1, sizeof(buff), png->fp) != 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 ((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], "86Box 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);
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* 86Box A hypervisor and IBM PC system emulator that specializes in
|
||||
* running old operating systems and software designed for IBM
|
||||
* PC systems and compatibles from 1981 through fairly recent
|
||||
* system designs based on the PCI bus.
|
||||
*
|
||||
* This file is part of the 86Box distribution.
|
||||
*
|
||||
* Definitions for the Simple PNG image file format handler.
|
||||
*
|
||||
* Version: @(#)win_png.h 1.0.1 2017/11/11
|
||||
*
|
||||
* Author: Fred N. van Kempen, <decwiz@yahoo.com>
|
||||
*
|
||||
* Copyright 2017 Fred N. van Kempen.
|
||||
*/
|
||||
#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*/
|
||||
Reference in New Issue
Block a user